一文徹底搞懂Vue中scoped和/deep/原理
背景
我們做 Vue 項(xiàng)目在組件里寫 css 的時(shí)候,經(jīng)常會(huì)給 <style> 標(biāo)簽加上 scoped ,比如這樣: <style lang="less" scoped> ,這樣寫出來的 css 就是局部的,不會(huì)影響其他組件。
另外,假設(shè)我們?cè)谧约旱慕M件中引入了一個(gè)子組件,并且希望在我的組件中修改子組件中的樣式,由于我們用了 scoped ,直接修改是不生效的。去掉 scoped 是可以的,不過沒了局部 css 風(fēng)險(xiǎn)不可控。有一種更好的方式,用深度選擇器修改,比如 less 中的 /deep/ 。用過組件庫(如 element ui )的朋友,在覆蓋組件庫樣式的時(shí)候應(yīng)該會(huì)經(jīng)常用到深度選擇器 /deep/ 。
基于以上兩點(diǎn),我們來聊一聊:
- 為什么
scoped可以形成局部css?原理是什么? - 為什么
/deep/可以跨組件修改css?原理是什么?
scoped 形成局部 css 原理
先看一張圖:

我們審查 html 元素時(shí)發(fā)現(xiàn)多了很多類似 data-v-f321cf6 屬性,這些屬性其實(shí)就是 scoped hash 出來的。
再來看一張頁面生成的 css 截圖:

仔細(xì)看第一張圖標(biāo)記了兩種顏色,他們分別對(duì)應(yīng)兩種 hash 屬性值: data-v-f5321cf6 和 data-v-6a6ef68c ,其實(shí)這里就是兩個(gè)不同的組件生成的兩個(gè)不同的值,每個(gè)加過 scoped 的組件生成的值都是唯一的。
結(jié)合兩張圖,不難發(fā)現(xiàn) scoped 形成局部 css 的原理其實(shí)很簡單,就是先給元素加上 hash 出來的屬性,再通過屬性選擇器來選擇這些元素,由于每個(gè)組件 hash 出來的屬性值都是唯一的, css 屬性選擇器選出來的元素當(dāng)然也是組件級(jí)的了,因?yàn)樾纬闪私M件內(nèi)局部 css 。
/deep/ 跨組件修改 css 原理
一個(gè)例子
一個(gè)列表頁面 ,需要在數(shù)據(jù)為空的時(shí)候展示空白頁,這個(gè)空白頁我們引入的是第三方組件庫的空白頁組件 <no-data> 。

假設(shè)我們現(xiàn)在要修改空白頁組件中圖片的寬高, <no-data> 不支持傳入寬高,并且我們無法改動(dòng)這個(gè)第三方組件,只能在列表頁通過 css 覆蓋空白頁組件的樣式。
我們第一時(shí)間想到改樣式嘛,這還不簡單,于是寫下:
<style lang="less" scoped>
.no-data{
img {
width: 200px;
height: 200px;
}
}
</style>自信滿滿的點(diǎn)開瀏覽器查看效果,發(fā)現(xiàn)設(shè)置的寬高并沒起到作用,空白頁圖片還是默認(rèn)的偏大。
仔細(xì)一想,父組件用了 scoped 是不能直接改子組件內(nèi)樣式的,得用 /deep/ ,于是乎有了下面的代碼:
<style lang="less" scoped>
.no-data{
/deep/img {
width: 200px;
height: 200px;
}
}
</style>再查看效果:

生效了,圖片小了很多!
我們?cè)賮韺彶橐幌马撁驿秩境鰜淼拇a,沒加 /deep/ 的:

注意看 css 部分,這里的選擇器是 .acl-nodata img[data-v-6a6ef68c] ,這里的 data-v-6a6ef68c 屬性是 <no-data> 組件中的 scoped 生成的。
接著往下看,加上 /deep/ 后的:

還是重點(diǎn)看 css 部分,這里的選擇器是 .integral-detail .no-data[data-v-f5321cf6] img ,這里的 data-v-f5321cf6 是列表頁的 scoped 生成的。
核心區(qū)別在于: img[data-v-6a6ef68c] 和 .no-data[data-v-f5321cf6] img
/deep/ 原理
通過上面的例子,我們可以分析出,在使用了 /deep/ 選擇器后,會(huì)把當(dāng)前元素 img 的 [data-v-6a6ef68c] 干掉,并通過他的父級(jí)(準(zhǔn)確的說是 img 元素所屬空白頁組件的根元素 <div ></div> ),來查找到 img ,也就是通過 .no-data[data-v-f5321cf6] img 來定位到 img 元素。
因?yàn)槲覀兊拇a是在列表頁寫的,列表頁 hash 出來的屬性是 [data-v-f5321cf6] ,在我們使用 /deep/ 之前, img 的 hash 是 [data-v-6a6ef68c] ,在列表頁中的 css 代碼當(dāng)然是識(shí)別不到空白頁組件的 [data-v-6a6ef68c] ,所以修改寬高不生效。使用 /deep/ 之后,通過 .no-data[data-v-f5321cf6] img ,由于 [data-v-f5321cf6] 本身就是列表 hash 出來的,自然是可以識(shí)別的,修改寬高自然也就生效了。
為了加深理解,這里再提一點(diǎn),仔細(xì)看 <div ></div> 這一塊的 html 代碼,你會(huì)發(fā)現(xiàn)它是同時(shí)具有 [data-v-f5321cf6] 和 [data-v-6a6ef68c] 兩種屬性,因?yàn)?<no-data> 組件的根元素是 <div ></div> ,在列表頁引入 <no-data> , <div ></div> 也相當(dāng)于是列表中的一個(gè)元素,所以 scoped 也會(huì)給它 hash 上 [data-v-f5321cf6] 。 (這一塊在實(shí)際開發(fā)中,有些朋友會(huì)搞一些騷操作,比如在父組件和子組件同時(shí)改 .no-data )
以上就是一文徹底搞懂Vue中scoped和/deep/原理的詳細(xì)內(nèi)容,更多關(guān)于Vue scoped和/deep/原理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Vue實(shí)現(xiàn)將數(shù)據(jù)庫中帶html標(biāo)簽的內(nèi)容輸出(原始HTML(Raw HTML))
今天小編就為大家分享一篇Vue實(shí)現(xiàn)將數(shù)據(jù)庫中帶html標(biāo)簽的內(nèi)容輸出(原始HTML(Raw HTML)),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-10-10
vue配置啟動(dòng)項(xiàng)目自動(dòng)打開瀏覽器方式
這篇文章主要介紹了vue配置啟動(dòng)項(xiàng)目自動(dòng)打開瀏覽器方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04
詳解Vue的常用指令v-if, v-for, v-show,v-else, v-bind, v-on
Vue.js的指令是以v-開頭的,它們作用于HTML元素,指令提供了一些特殊的特性。這篇文章主要介紹了Vue的常用指令v-if, v-for, v-show,v-else, v-bind, v-on 的相關(guān)知識(shí),需要的朋友可以參考下2018-10-10
vue 界面刷新數(shù)據(jù)被清除 localStorage的使用詳解
今天小編就為大家分享一篇vue 界面刷新數(shù)據(jù)被清除 localStorage的使用詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-09-09
vue實(shí)現(xiàn)循環(huán)滾動(dòng)圖片
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)循環(huán)滾動(dòng)圖片,多圖片輪播,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07
vue2.0基于vue-cli+element-ui制作樹形treeTable
這篇文章主要介紹了vue2.0基于vue-cli+element-ui制作樹形treeTable,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04
vue+axios 前端實(shí)現(xiàn)登錄攔截的兩種方式(路由攔截、http攔截)
本文通過實(shí)例代碼給大家介紹了vue+axios 前端實(shí)現(xiàn)登錄攔截的方法,主要通過路由攔截和http攔截,具體實(shí)例代碼大家跟隨小編一起通過本文學(xué)習(xí)吧2018-10-10

