[Vue.js] Scoped的使用以及樣式穿透

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.基本原理

可以概括為以下幾個步驟:

  1. 為當前組件模板的所有DOM節(jié)點添加相同的attribute,添加的屬性和其他的scope不重復,比如data-v-123來表示它的唯一性;
  2. 在每句css選擇器的末尾(編譯后生成的css語句)加一個當前組件的data屬性選擇器,比如div[data-v-123]來私有化樣式;
  3. 如果組件內(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>

我們可以在瀏覽器中進行驗證:

image.png

總的來說,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):

image.png

從上圖中可以看到除了在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時,瀏覽器需要額外處理樣式選擇器;
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容