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

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

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

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

生效了,圖片小了很多!
我們再來審查一下頁面渲染出來的代碼,沒加 /deep/ 的:

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

還是重點看 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/ 選擇器后,會把當前元素 img 的 [data-v-6a6ef68c] 干掉,并通過他的父級(準確的說是 img 元素所屬空白頁組件的根元素 <div ></div> ),來查找到 img ,也就是通過 .no-data[data-v-f5321cf6] img 來定位到 img 元素。
因為我們的代碼是在列表頁寫的,列表頁 hash 出來的屬性是 [data-v-f5321cf6] ,在我們使用 /deep/ 之前, img 的 hash 是 [data-v-6a6ef68c] ,在列表頁中的 css 代碼當然是識別不到空白頁組件的 [data-v-6a6ef68c] ,所以修改寬高不生效。使用 /deep/ 之后,通過 .no-data[data-v-f5321cf6] img ,由于 [data-v-f5321cf6] 本身就是列表 hash 出來的,自然是可以識別的,修改寬高自然也就生效了。
為了加深理解,這里再提一點,仔細看 <div ></div> 這一塊的 html 代碼,你會發(fā)現(xiàn)它是同時具有 [data-v-f5321cf6] 和 [data-v-6a6ef68c] 兩種屬性,因為 <no-data> 組件的根元素是 <div ></div> ,在列表頁引入 <no-data> , <div ></div> 也相當于是列表中的一個元素,所以 scoped 也會給它 hash 上 [data-v-f5321cf6] 。 (這一塊在實際開發(fā)中,有些朋友會搞一些騷操作,比如在父組件和子組件同時改 .no-data )
以上就是一文徹底搞懂Vue中scoped和/deep/原理的詳細內(nèi)容,更多關于Vue scoped和/deep/原理的資料請關注腳本之家其它相關文章!
相關文章
Vue實現(xiàn)將數(shù)據(jù)庫中帶html標簽的內(nèi)容輸出(原始HTML(Raw HTML))
今天小編就為大家分享一篇Vue實現(xiàn)將數(shù)據(jù)庫中帶html標簽的內(nèi)容輸出(原始HTML(Raw HTML)),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-10-10
詳解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 的相關知識,需要的朋友可以參考下2018-10-10
vue 界面刷新數(shù)據(jù)被清除 localStorage的使用詳解
今天小編就為大家分享一篇vue 界面刷新數(shù)據(jù)被清除 localStorage的使用詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-09-09
vue2.0基于vue-cli+element-ui制作樹形treeTable
這篇文章主要介紹了vue2.0基于vue-cli+element-ui制作樹形treeTable,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-04-04
vue+axios 前端實現(xiàn)登錄攔截的兩種方式(路由攔截、http攔截)
本文通過實例代碼給大家介紹了vue+axios 前端實現(xiàn)登錄攔截的方法,主要通過路由攔截和http攔截,具體實例代碼大家跟隨小編一起通過本文學習吧2018-10-10

