如果有任何問題或建議,歡迎隨時聯繫我:
各位 Vue 的造型師!過去幾天,我們一直在 <script>
的世界裡鑽研 TypeScript 的內功心法,讓我們的邏輯變得堅不可摧。今天,我們要換個場景,把目光移到 <style>
標籤,來解決另一個讓開發者頭痛不已的問題:CSS 樣式衝突。
想像一下,你的應用程式是個盛大的化妝舞會。你精心為 Card
組件設計了一套華麗的 .title
樣式。結果,另一個 Header
組件也定義了一個 .title
樣式。最後,在舞會上,你的 Card
標題莫名其妙地戴上了 Header
的帽子!這就是 CSS 全域污染 的噩夢。
今天,我們要學習兩大神器,來徹底解決這個問題:
SCSS (Sassy CSS) 是 CSS 的超集,它提供了許多 CSS 原生沒有的便利功能,讓寫樣式變得更有趣、更有效率。在 Vue 中整合它,只需要一步。
1. 安裝 sass
npm install -D sass
2. 開始使用
就這樣!現在你可以在你的 .vue
檔案中,將 <style>
標籤改為 <style lang="scss">
,然後就可以開始使用 SCSS 的魔法了。
<style lang="scss">
// 1. 變數:把常用的顏色、字體大小存起來
$primary-color: #42b983;
$font-size-large: 18px;
.card {
border: 1px solid $primary-color;
// 2. 巢狀:樣式結構和 HTML 結構一樣,清晰明瞭
.title {
font-size: $font-size-large;
color: $primary-color;
&:hover {
color: darken($primary-color, 10%); // 內建函式,加深顏色
}
}
.content {
padding: 10px;
}
}
</style>
SCSS 就像是 CSS 的「語法糖」,它讓你的樣式碼更易讀、更易維護,但它本身並不能解決「全域污染」的問題。
即使有了 SCSS,如果你在 ComponentA
和 ComponentB
中都寫了 .card
樣式,它們依然會在全域打架。為了解決這個問題,Vue 提供了一個大殺器:CSS Modules。
你只需要做一個小小的改動:在 <style>
標籤上加上 module
屬性。
<template>
<!-- 注意這裡的 class 綁定方式 -->
<div :class="$style.card">
<h3 :class="$style.title">這是一個卡片標題</h3>
<p :class="$style.content">這是一些內容。</p>
</div>
</template>
<script setup>
// CSS Modules 會在組件中注入一個名為 $style 的物件
// 你可以把它 log 出來看看它的結構
// import { useCssModule } from 'vue';
// const style = useCssModule();
// console.log(style);
</script>
<!-- 加上 "module" 屬性,啟動隱形盔甲! -->
<style module lang="scss">
.card {
border: 1px solid #ccc;
padding: 16px;
text-align: center;
}
.title {
color: #42b983;
}
.content {
font-size: 14px;
}
</style>
當你使用 <style module>
,Vue 和建置工具在背後會做一件神奇的事:它會把你寫的 class 名稱(如 .card
)自動轉換成一個全域唯一的 hash 名稱。
.card
可能會變成 .MyComponent_card_Abc123
。.title
可能會變成 .MyComponent_title_Xyz789
。同時,它會把這個「對照表」注入到你的組件裡,成為一個叫做 $style
的物件。所以你可以透過 $style.card
來存取到那個獨一無二的 class 名稱。
因為每個組件的 class 名稱都帶有自己的「指紋」,所以它們永遠不可能和來自其他組件的樣式發生衝突!這就是作用域化 CSS (Scoped CSS) 的完美實現。
scoped
vs module
你可能會問:Vue 不是還有一個 <style scoped>
嗎?它和 module
有什麼不同?
<style scoped>
:是 Vue 的另一種樣式隔離方案。它透過為 HTML 元素添加一個獨特的屬性(如 data-v-f3f3eg9
)並修改 CSS 選擇器(如 .card
-> .card[data-v-f3f3eg9]
)來實現作用域。它更「自動」,你不需要修改 class 的寫法。<style module>
:更加「明確」。你必須手動透過 $style
物件來綁定 class,這讓你的模板能清楚地表明這個 class 是來自於 CSS Module。它提供了更強的控制力,並且與 JS 的互動更自然。兩者都是解決方案,沒有絕對的好壞。但 CSS Modules 因為其明確性和與 JS 的良好整合,在大型專案和組件庫中越來越受歡迎。
今天我們為組件的樣式進行了兩次大升級。
sass
並使用 <style lang="scss">
,我們解鎖了變數、巢狀、Mixin 等強大功能,讓 CSS 寫起來更像一門程式語言。<style>
標籤上添加 module
屬性,我們為每個組件的樣式穿上了「隱形盔甲」,並透過 $style
物件來存取它們,從而 100% 避免了全域樣式衝突的問題。從此以後,你可以放心地為每個組件設計樣式,再也不用擔心它會影響到別人,或是被別人影響了!
<style>
改為 <style module lang="scss">
。嘗試使用 SCSS 的變數和巢狀語法來重構你的樣式。最後,記得在 <template>
中使用 :class="$style.yourClassName"
來綁定樣式。<style scoped>
的自動化,還是 <style module>
的明確性?思考一下在什麼樣的場景下,你可能會選擇其中一種而不是另一種。本日關鍵字回顧
<style module>
: 在 Vue 中啟用 CSS Modules 的方式。$style
: Vue 注入到組件中的物件,包含了原始 class 名稱到唯一名稱的對應。明天,我們將學習如何使用 SCSS 建立可維護的全域樣式系統,讓你的專案在擁有獨立盔甲的同時,也能共享一套統一的設計語言!