1. 程式人生 > >vue中修改子元件樣式

vue中修改子元件樣式

一、問題敘述

  專案裡需要新新增一個表單頁面,裡面就只是幾個select,這個幾個select是原本封裝好的元件,有自己原本的樣式,而這次的原型圖卻沒有和之前的樣式統一起來,需要微調一下,這裡就涉及到父元件修改子元件的樣式。不想混用本地和全域性樣式,所以選擇了>>>,但是並不起作用,就換成/deep/,其實到這裡我也沒有繼續深入這個知識點,因為在瀏覽器裡預覽後已經實現了原型圖的樣式,直到打包在手機上測試,發現問題,在手機上瀏覽並沒有將樣式修改過來。如下圖:

 

問題:①為什麼使用>>>不起作用?②為什麼我使用了/deep/卻沒有成功的在手機上將樣式修改過來?

二、相關知識點

  ㈠關於vue中使用scoped屬性

在vue元件中,在style標籤中新增scoped屬性,這樣在這裡定義的css只作用於當前元件中的元素,可使元件之間的樣式不會相互汙染,使樣式私有化。比如在父元件內使用子元件,父元件的樣式不會滲透到子元件中。

  Ⅰ、在加上scoped後,會為DOM節點自動新增一個唯一的屬性(data-v-f3f3eg9後面這串數字像是獨一無二的hash值),以保證其唯一性。同時在相應的css選擇器末尾,也加上了當前元件的data-v-f3f3eg9屬性,來使其私有化。

如Vue Loader中所給出的程式碼示例:

<template>
  <div class="example">hi</div>
</template>

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

轉化後:

<template>
  <div class="example" data-v-f3f3eg9>hi</div>
</template>

<style>
.example[data-v-f3f3eg9] {
  color: red;
}
</style>

  ㈡關於深度作用選擇器:/deep/(>>>)

  使用了scoped後,儘管實現元件樣式的私有化,但在我們實際的專案中,在很多地方使用重複的子元件或其他的樣式庫時,在個別地方需要微調樣式,這個時候不能直接改子元件樣式,而且在父元件裡的樣式又不能滲透到子元件去。這個時候文件中有一句話:

不過一個子元件的根節點會同時受其父元件的 scoped CSS 和子元件的 scoped CSS 的影響。這樣設計是為了讓父元件可以從佈局的角度出發,調整其子元件根元素的樣式。

  所以還是有辦法解決剛才那個問題的,當我們希望 scoped 樣式中的一個選擇器能夠作用得“更深”,例如影響子元件,你可以使用 >>> 操作符,編譯後會在相應的選擇器後面增加獨有的屬性;如下:

<style scoped>
.a >>> .b { /* ... */ }
</style>

上述程式碼將會編譯成:

.a[data-v-f3f3eg9] .b { /* ... */ }

  在這裡需要注意的是,有些像 Sass 、scss之類的前處理器無法正確解析 >>>。這種情況下我們可以使用 /deep/ 或 ::v-deep 操作符來取代>>>,這是兩個都是 >>> 的別名,同樣可以正常工作。如下:

<style lang='scss' scoped>
.a {
    /deep/ .b{
                /* ... */
    }
}
</style>

三、問題解決

  ①為什麼使用>>>不起作用?

  因為這個專案使用的scss,所以無法正常解析>>>,所以在父元件沒有滲透下去。

.pop-content {
   .input-wrapper >>>  .form-item {
    .form-label {
     /*...*/
  }

  在瀏覽器檢視轉換的結果發現,還是原本元件的樣式,我新定義的並沒有出現。如下圖:

  ②為什麼我使用了/deep/卻沒有成功的在手機上將樣式修改過來?

  因為引用的這個子元件裡還包裹了一層子元件,我使用了兩個/deep/,不理解/deep/的實現原理,自以為每一個元件都要滲透一次。

/*錯誤程式碼:寫了兩次/deep */
.pop-content {
  /deep/ .input-wrapper /deep/  .form-item {
      ...
  } 
 }

轉換後在瀏覽器看到的程式碼,發現第二個是無法轉換的。

.pop-content[data-v-b93cf8e0] .input-wrapper /deep/ .form-item {}

 

/*修改後的程式碼*/
.pop-content {  
     .input-wrapper /deep/  .form-item {  
    }
  }​

/*編譯轉換後的程式碼*/
 .pop-content .input-wrapper[data-v-b93cf8e0] .form-item 

  ③隨之而來第三個問題,我只寫一個/deep/的話,我寫在哪個位置呢,是不是寫在哪都行,它們之間有什麼區別。

  ⅰ嘗試一:將/deep/寫在input-wrapper後面

.pop-content { 
   .input-wrapper /deep/  .form-item {
    padding: 0.4rem 2rem 0.3rem 1.5rem;
    .form-label {
      -webkit-box-flex: 0;
      -ms-flex: 0 0 8rem;
      flex: 0 0 50%;
      font-size: 15px;
      color: black;
      position: relative;
    }
  }

轉換後的樣式程式碼:原本的樣式已經失效了,並在input-wrapper後面添加了相應唯一的data-v屬性值。

  ⅱ嘗試二:將/deep/寫在pop-content後面

.pop-content {
  /deep/  .input-wrapper .form-item {
    padding: 0.4rem 2rem 0.3rem 1.5rem;
    .form-label {
      -webkit-box-flex: 0;
      -ms-flex: 0 0 8rem;
      flex: 0 0 50%;
      font-size: 15px;
      color: black;
      position: relative;
    }
  }

轉換後的樣式程式碼:原本的樣式已經失效了,並在pop-content後面添加了相應唯一的data-v屬性值。

  ⅲ嘗試三:將/deep/寫在form-item或者form-label後面,均不起作用。看了一下DOM結構,我覺得可能是因為這樣做的css的優先順序並沒有比原來的高,所以沒法改變。還有就是這個子元件內部的元件巢狀也比較複雜,所以從最外面的父元件看不出,所以對/deep/位置的放置對其優先順序的影響還是比較大的。大致這樣理解。

&n