1.簡介
Vue中的屬性隔離在Vue中Scoped是用來做樣式隔離的,能夠確保樣式只在當前的組件內(nèi)起作用。這意味著,在一個Vue組件中寫的樣式只會影響這個組件內(nèi)的元素,并不會影響其他組件或者全局的樣式。
使用很簡單,只需要在style標簽上,添加scoped關(guān)鍵字即可:
<template>
<div>
Hello, world!
</div>
</template>
<style scoped>
div {
background-color: yellow;
}
</style>
在這個例子中,我們給style標簽添加了scoped,這樣里面的樣式只會影響當前組件內(nèi)的元素,比如div添加的背景色,只會作用于這個組件的內(nèi)部div了,不會影響到其他地方的樣式。
2.基本原理
可以概括為以下幾個步驟:
- 為當前組件模板的所有DOM節(jié)點添加相同的attribute,添加的屬性和其他的scope不重復,比如data-v-123來表示它的唯一性;
- 在每句css選擇器的末尾(編譯后生成的css語句)加一個當前組件的data屬性選擇器,比如div[data-v-123]來私有化樣式;
- 如果組件內(nèi)部包含有其他組件,只會給其他組件的最外層標簽加上這個data屬性;
所以,經(jīng)過Vue的處理,上面的代碼將被轉(zhuǎn)化為類似下面這樣的代碼:
<template>
<div data-v-7ba5bd90>
Hello, world!
</div>
</template>
<style scoped>
div[data-v-7ba5bd90] {
background-color: yellow;
}
</style>
我們可以在瀏覽器中進行驗證:

總的來說,scoped可以保證當前樣式只針對于當前組件,這樣可以讓我們的樣式代碼更加清晰、模塊化,也更容易維護。
再舉個例子,正好也可以驗證下上面提到的scoped基本原理的第3點:
如果組件內(nèi)部包含有其他組件,只會給其他組件的最外層標簽加上這個data屬性;
我們先創(chuàng)建一個NavBar.vue組件,里面只包含一個按鈕和一個標題:
<template>
<div class="container">
<button>left</button>
<div class="title">NavbarTitle</div>
</div>
</template>
<style>
.container {
display: flex;
flex-direction: row;
}
.title {
flex: 1;
text-align: center;
}
</style>
然后在App.vue中使用該組件:
<template>
<navbar></navbar>
<div>AppVue</div>
</template>
<script>
import navbar from './components/NavBar.vue';
export default {
components: {
navbar
}
};
</script>
<style scoped>
div {
background-color: blue;
}
</style>
運行之后,查看標簽結(jié)構(gòu):

從上圖中可以看到除了在App.vue中添加的div標簽,NavBar組件的根標簽div也加上了data-v-7ba5bd90,所以如果組件內(nèi)部包含有其他組件,只會給其他組件的最外層標簽加上這個data屬性。
3.樣式穿透
在使用Vue的Scoped樣式時,有時候會遇到父組件無法直接操作子組件樣式的情況,這就是所謂的scoped樣式的穿透問題。
3.1 舉例說明
我們可以將上面的那個例子進行修改,進行驗證。
NavBar.vue:
<template>
<div class="container">
<button>left</button>
<div class="title">NavbarTitle</div>
</div>
</template>
<style>
.container {
display: flex;
flex-direction: row;
}
.title {
flex: 1;
text-align: center;
}
</style>
App.vue:
<template>
<navbar></navbar>
<div>AppVue</div>
</template>
<script>
import navbar from './components/NavBar.vue';
export default {
components: {
navbar
}
};
</script>
<style scoped>
div {
background-color: blue;
}
/// 新加的樣式
div button {
background-color: red;
}
</style>
基于上面的例子,我們在App.vue中新加了一個樣式,想要修改NavBar組件中按鈕的顏色。但是發(fā)現(xiàn)并沒有起作用,究其原因是因為上面提到的,scoped只會給組件的最外層標簽添加屬性,并且在經(jīng)過編譯之后,CSS如下:
<style type="text/css">
div[data-v-7ba5bd90] {
background-color: blue;
}
div button[data-v-7ba5bd90] {
background-color: red;
}
</style>
但是我們的button還是之前的樣式,并沒有data-v-7ba5bd90這個屬性,所以這個樣式并不會起作用。
但是我們在項目開發(fā)中經(jīng)常會遇到需要修改組件內(nèi)標簽樣式的情況,這就需要使用深度作用選擇器了。
3.2 深度作用選擇器(Deep Selectors)
Vue提供了深度作用選擇器,能夠穿透scoped樣式,直接影響子組件內(nèi)部的樣式。可以在負組件中使用 >>> 或者 /deep/ 來表示深度作用選擇器,然后在后面跟上你要修改的子組件內(nèi)部的樣式,比如:
div >>> button {
background-color: red;
}
或者
div /deep/ button {
background-color: red;
}
然后我們在瀏覽器中看下其樣式,發(fā)現(xiàn)和之前的有所改變,[data-v-7ba5bd90]放到了div后面,而不是button后面了:
<style type="text/css">
div[data-v-7ba5bd90] {
background-color: blue;
}
div[data-v-7ba5bd90] button {
background-color: red;
}
</style>
通過這種方式,我們就能夠解決scoped樣式穿透的問題,直接修改子組件內(nèi)部的樣式,而不會受到scoped的限制。
注意事項:
- 使用深度作用選擇器雖然能夠解決scoped樣式的穿透問題,但是不要濫用,以免影響到其他組件的樣式;另外,深度作用選擇器的性能也會有一些影響;
4. 總結(jié)
在使用Vue中的Scoped樣式時,我們需要知曉其原理,了解其優(yōu)點和缺點,這樣可以更好的去排查問題和提升工作效率。
優(yōu)點:
- 樣式私有化:更容易管理和維護樣式,避免了樣式的沖突和污染;
- 組件化開發(fā):每個組件都有獨立的樣式,提高了代碼的可維護性和復用性;
缺點:
- 樣式權(quán)重增加:scoped樣式會給每個樣式增加特定的選擇器屬性,導致樣式權(quán)重增加。可能會導致樣式覆蓋和繼承方面的問題,需要更高的權(quán)重來覆蓋scoped樣式;
- 無法直接操作子組件內(nèi)部樣式:如果需要操作子組件內(nèi)部樣式,就需要用深度作用選擇器或其他方式解決;
- 性能問題:使用scoped時,瀏覽器需要額外處理樣式選擇器;