2024-12-08 style scoped

2024-12-08 style scoped

scoped 的作用與影響

在 Vue 中,<style scoped> 是用來將樣式限制於該組件本身的功能。加上 scoped 後,樣式只會影響該組件的模板,不會影響其他組件的樣式,避免了全局樣式的污染。


主要區別

1. scoped 的情況

1
2
3
4
5
6
7
8
9
<template>
<div class="box">Hello Scoped</div>
</template>

<style scoped>
.box {
color: red;
}
</style>
  • 樣式只會影響當前組件的 .box,例如:

    1
    2
    3
    <div class="box" data-v-12345abc> <!-- Scoped 自動加上 data-v-* -->
    Hello Scoped
    </div>
  • 自動生成的 CSS:

    1
    2
    3
    .box[data-v-12345abc] {
    color: red;
    }
    • data-v-12345abc 是 Vue 自動生成的屬性,用於識別該組件的元素。
    • 這樣就確保該樣式不會影響其他組件的 .box

2. 沒有 scoped 的情況

1
2
3
4
5
6
7
8
9
<template>
<div class="box">Hello Global</div>
</template>

<style>
.box {
color: red;
}
</style>
  • 樣式會是全局的,影響所有 .box 元素:

    1
    2
    3
    .box {
    color: red;
    }
  • 如果其他組件也有 .box,它們都會被影響。例如:

    1
    <div class="box">This will also be red</div>

優缺點比較

scoped

優點:

  1. 樣式封裝性強,避免樣式污染其他組件。
  2. 易於維護,樣式只會影響當前組件。

缺點:

  1. 生成的 CSS 比較冗長(因為會加上 data-v-* 的屬性選擇器)。
  2. 跨組件的樣式覆蓋需要額外處理(例如使用 >>>/deep/ 進行穿透)。

沒有 scoped

優點:

  1. 樣式是全局的,方便覆蓋全局樣式。
  2. 適合應用於全局的樣式規範(如重置樣式或主題樣式)。

缺點:

  1. 容易導致樣式衝突,特別是在大型項目中。
  2. 修改樣式可能會意外影響其他組件,導致調試困難。

何時使用 scoped

  • 適合使用 scoped 的情況:

    1. 當前組件的樣式應該與其他組件隔離。
    2. 樣式是組件私有的,不需要影響全局。
  • 適合不使用 scoped 的情況:

    1. 需要定義全局樣式,如重置樣式或通用樣式規範。
    2. 樣式需要影響多個組件。

常見問題

1. 如何讓 scoped 的樣式影響子組件?

使用 >>>/deep/,例如:

1
2
3
4
5
<style scoped>
/deep/ .child {
color: blue;
}
</style>

2. 可以同時使用 scoped 和全局樣式嗎?

可以!只需分開寫:

1
2
3
4
5
6
7
8
9
10
11
12
13
<style>
/* 全局樣式 */
body {
font-family: Arial, sans-serif;
}
</style>

<style scoped>
/* 組件樣式 */
.box {
color: red;
}
</style>

結論

  • 使用 <style scoped> 可以讓樣式更加模組化,避免樣式衝突。
  • 在大型應用中,推薦全局樣式與 scoped 樣式結合使用:
    • 全局樣式: 定義通用樣式和基礎設計系統。
    • scoped 樣式: 保護組件的獨立性。

是的!當將 .vue 文件拆分成多個模組時,**建議使用 <style scoped>**,以確保每個組件的樣式是獨立的,不會互相干擾。


為什麼要用 scoped

1. 避免樣式污染

如果不加 scoped,所有的 CSS 規則都是全局的,可能會影響其他 .vue 文件的元素。例如,以下樣式會影響全局:

1
2
3
button {
background-color: blue;
}

其他組件的 button 也會變藍,即使你並不希望如此。

加上 scoped 後,樣式就只影響當前組件,其他組件的 button 不會受到影響。


2. 方便模組化維護

拆分成多個 .vue 文件後,每個組件都有自己專屬的樣式,<style scoped> 可以讓樣式更具封裝性。即使同一專案中有多個類似的 class 名稱(例如 .box),也不會產生衝突。


實際場景舉例

不使用 scoped

假設你有兩個組件,樣式可能相互干擾:

Parent.vue

1
2
3
4
5
6
7
8
9
<template>
<div class="box">Parent Box</div>
</template>

<style>
.box {
color: red;
}
</style>

Child.vue

1
2
3
4
5
6
7
8
9
<template>
<div class="box">Child Box</div>
</template>

<style>
.box {
color: blue;
}
</style>

結果:

  • Parent BoxChild Box.box 可能會相互覆蓋,最終樣式可能是紅色,也可能是藍色,取決於 CSS 的加載順序。

使用 scoped

改成 scoped,則每個 .box 僅影響自身:

Parent.vue

1
2
3
4
5
6
7
8
9
<template>
<div class="box">Parent Box</div>
</template>

<style scoped>
.box {
color: red;
}
</style>

Child.vue

1
2
3
4
5
6
7
8
9
<template>
<div class="box">Child Box</div>
</template>

<style scoped>
.box {
color: blue;
}
</style>

結果:

  • Parent Box 顯示紅色。
  • Child Box 顯示藍色。
  • 兩者互不影響。

組件拆分後的建議

  1. 樣式優先使用 scoped

    • 每個組件的樣式是私有的。
    • 避免同名類別互相覆蓋。
    • 例如:
      1
      2
      3
      4
      5
      <style scoped>
      .button {
      background-color: green;
      }
      </style>
  2. 全局樣式集中管理:

    • 如果是全局通用樣式(如重置樣式、主題設計),可以放在單獨的全局 CSS 文件中,避免使用組件內的非 scoped 樣式。
    • main.js 或入口文件中引入:
      1
      import './assets/global.css';
  3. 跨組件的樣式使用穿透技巧:

    • 當某個樣式需要影響子組件時,可以用 /deep/::v-deep
      1
      2
      3
      4
      5
      <style scoped>
      /deep/ .child-box {
      color: yellow;
      }
      </style>

結論

  • 在拆分成多個 .vue 文件後,最好為每個組件的樣式加上 scoped,確保模組化和封裝性。
  • 全局樣式放在單獨的 CSS 文件,避免污染局部樣式。
  • 如果需要影響子組件,可以使用穿透選擇器進行特例處理。