一、問題敘述
項目里需要新添加一個表單頁面,里面就只是幾個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/位置的放置對其優先級的影響還是比較大的。大致這樣理解。