主要分成四個部份
@use
& @import
踩坑先說說新手可能會搞不懂的地方(還是只有我自己XD),Vue 提供開發者透過 lang
屬性宣告語言塊 (如:<style>
) 所使用的語言,但實際上,專案內所有樣式的預處理跟打包,是由建構工具來執行的,所以,「要怎麼在 Vue 專案引入 .sass
/.scss
檔案」這件事,要看建構工具的官方文件。
這也是 Vue 官方文件在 Pre-Processors 提到的:
Note that integration with various pre-processors may differ by toolchain. Check out the respective documentation for examples:
注意对不同预处理器的集成会根据你所使用的工具链而有所不同,具体细节请查看相应的工具链文档来确认:
- Vite
- Vue CLI
- webpack + vue-loader
我目前專案上使用的建構工具是 Vite,以下說明內容都是以 Vite 為主。
vite
內建支持 .scss
、.sass
、.less
、.styl
和 .stylus
等檔案,沒有 vite
特殊的插件,只要安裝一般的預處理器就可以了。
npm
為例)安裝預處理器 Sassnpm add -D sass
<style>
註明使用語言Vue SFC 檔的 language blocks 可以透過 lang
屬性宣告所使用的語言,所以想在 <style>
block 使用 SCSS
風格撰寫,必須這樣寫:
<style lang="scss">
$primary-color: #333;
body {
color: $primary-color;
}
</style>
好了,就這樣。
(???)
你可能有的疑惑:「我不用自己手動將 .scss
預處理成 .css
嗎?」
對的,不用,交給 vite 處理!
.scss
樣式或變數區域引入指的是:只要將樣式或變數引入到單一元件檔的 <style>
中使用。
我們可以透過 @use
或 @import
,將整份 .scss
檔引入到元件檔中,就可以在 <style>
內使用 Sass 變數、@mixin
和 @extend
等。
<style lang="scss" scoped>
@use "@/assets/scss/_font.scss";
@import "@/assets/scss/_colors.scss";
body {
color: $primary-color;
font-size: font.$super-big;
}
</style>
記得在語言塊加上 scoped
屬性,才能將樣式鎖定在區域元件內。(否則就變成全域共享 CSS 樣式啦,還不清楚 scoped
作用的人,建議先去看昨天的文章-Day 14: style scoped 原理)
.scss
樣式想要全域引入 scss 樣式,主要有兩個引入點:
App.vue
main.js
在這裡想要先說明,全域「引入 .scss
樣式」這個說法並不精準,就轉換的執行結果,準確來說是「全域共享這份 .scss
檔所轉換出來的 CSS 樣式」,這也是為什麼要特別區分「樣式」與「Sass 變數」。
App.vue
其實概念和引用到單一元件檔是一樣的,只要不加上 scoped
,就可以影響全域的樣式,但因為 App.vue
通常是最整個專案的「根元件」,這裡引入全域樣式是最合理,也更容易管理的。
注意:轉換前的 Sass 變數、@mixin
和 @extend
等等是不能共享的;轉換後的 CSS 樣式,因為沒有 scoped
限制,所以可以影響全域的元件。
<style lang="scss">
@use "@/assets/scss/_font.scss";
@import "@/assets/scss/_colors.scss";
body {
color: $primary-color;
font-size: font.$super-big;
}
</style>
scoped
css
樣式而不是 scss
,所以變數、@mixin
** 和** @extend
還是不能全域共享
也就是說,實際上共用的是下面這組樣式:
body {
color: cyan;
font-size: 48px;
}
main.js
這個方法一樣是利用轉換後的 CSS 樣式,套用到全域,所以轉換前的 Sass 變數等等還是不能共享。
也就是說,只有 Sass 變數的檔案在這裡引入是沒有意義的,元件檔內也無法使用這些變數。
import { createApp } from "vue";
import App from "./App.vue";
import "./assets/main.css
//只有 Sass 變數的檔案在這裡引用沒有意義
import "@/assets/scss/_colors.scss";
//適合 reset.scss 這類型要套用全局的樣式
import "@/assets/scss/_reset.scss";
const app = createApp(App);
app.mount("#app");
css
樣式而不是 scss
,所以變數、@mixin
** 和** @extend
還是不能全域共享
透過 vite
設定來處理,在 vite.config.js
加入下列這段設定:
css: {
preprocessorOptions: {
scss: {
additionalData: `@import "@/assets/global.scss";`
}
}
},
@import "@/assets/global.scss";
這行會被加到每一份 style 中,等同於在每個 SFC <style>
引入 "@/assets/global.scss"
,如此一來元件就都能取用 global.scss
裡面 scss
的變數!
但在這裡要注意選擇引用的方式(@use
v.s @import
)。
稍微說明一下 @use
跟 @import
的差異:
@use
fileName.variableName
,避免變數衝突的問題@import
@import
@use
最關鍵的是引入順序,@use
在前,@import
在後,否則會報錯。
css: {
preprocessorOptions: {
scss: {
additionalData: `@use "@/assets/globalColor.scss";`
}
}
},
試想,additionalData
的 @import "@/assets/globalColor.scss";
這一行字串會寫在檔案的哪裡?
這行字串會被加到每份 <style>
的最前面,所以要注意 @use
跟 @import
的引用順序衝突。
如果選擇在 additionalData
使用:
@import
引入:SFC 內就不能使用 @use
引入 .scss
檔案
只要在任何 SFC 內使用 @use
引入 .scss
檔案,就會直接報錯 (錯誤訊息:@use rules must be written before any other rules.),因為 Sass 的規則就是 @use
在前,@import
在後。
@use
引入注意 name spacing 或改用 *
alias
@use 'file'
:要注意的是,在個別的 SFC 中,雖然看不到引用的檔案名稱,但每次取用變數還是要幫他加上 name spacing!@use 'file' as *
效果如同 @import
,可以巧妙避開引用順序報錯,但缺點如 @import
,要注意變數衝突的問題。不建議用這個方式引入太多 scss 檔案,因為每份 .scss
檔案都會被所有元件樣式重覆引入。
.scss
。main.js
或 App.vue
的 <style>
引入。註:vite 官方文件其實沒有特別提到 additionalData
引入的內容會寫在哪裡,我主要是根據測試報錯內容、vitejs github 討論和 webpack sass loader 說明來推測的。