Vue中樣式scoped和樣式穿透的實現原理


在vue組件中可以使用scoped的css來實現樣式的模塊化,避免對其他組件的影響;而想在父組件中修改子組件的樣式時往往由於scoped的原因,導致樣式不生效,需要使用深度選擇器進行樣式穿透。

那么本文就來看看具體是怎么實現的。

1.准備案例

父組件App.vue

<template>
    <div class="container">
        <h3 class="title">Hello Vue</h3>
        <card />
    </div>
</template>

<script>
import Card from './Card.vue';

export default {
    components: { Card }
}
</script>


<style scoped>
.container {
    width: 300px;
    height: 300px;
    padding-top: 10px;
    background-color: #efefef;
}
.container .title {
    color: #709b90;
    text-align: center;
}
.card {
    border: 2px solid#CDC9C9;
    margin-left: 50px;
}
</style>

子組件Card.vue

<template>
    <div class="card">
        <div class="title">Vue Cli</div>
        <div class="list">
            <div class="item">vue serve</div>
            <div class="item">vue build</div>
        </div>
    </div>
</template>

<style scoped>
    .card {
        width: 200px;
        height: 200px;
    }
    .title {
        height: 30px;
        line-height: 30px;
        color: #FFDEAD;
        padding-left: 10px;
        background-color: #87CEFA;
    }
    .item {
        height: 30px;
        line-height: 30px;
        padding-left: 10px;
        background-color: #FFE4E1;
    }
</style>

效果如下:

2.scoped的實現

把組件進行編譯,查看一下:

編譯后的html:

<div data-v-4fe14a3c="" class="container">
    <h3 data-v-4fe14a3c="" class="title">Hello Vue</h3>
    <div data-v-119ff0e6="" data-v-4fe14a3c="" class="card">
        <div data-v-119ff0e6="" class="title">Vue Cli</div>
        <div data-v-119ff0e6="" class="list">
            <div data-v-119ff0e6="" class="item">vue serve</div>
            <div data-v-119ff0e6="" class="item">vue build</div>
        </div>
    </div>
</div>

需要說明一下:每次編譯后vue組件中的dom會由js動態生成,所以需要用瀏覽器打開編譯后的html,再用開發者工具查看

編譯后的css:

.card[data-v-119ff0e6] {
    width: 200px;
    height: 200px
}

.title[data-v-119ff0e6] {
    height: 30px;
    line-height: 30px;
    color: #ffdead;
    padding-left: 10px;
    background-color: #87cefa
}

.item[data-v-119ff0e6] {
    height: 30px;
    line-height: 30px;
    padding-left: 10px;
    background-color: #ffe4e1
}

.container[data-v-4fe14a3c] {
    width: 300px;
    height: 300px;
    padding-top: 10px;
    background-color: #efefef
}

.container .title[data-v-4fe14a3c] {
    color: #709b90;
    text-align: center
}

.card[data-v-4fe14a3c] {
    border: 2px solid#CDC9C9;
    margin-left: 50px
}

編譯后dom元素都會添加上data-v-hashxxxx的屬性,而樣式中的選擇器也被添加上了data-v-hashxxxx的屬性,每個組件的data-v-hashxxxx是一樣的因此限制了樣式的作用范圍。另外子組件的最外層也會被添加上父組件的data-v-hashxxxx,同時含有父組件、子組件的data-v-hashxxxx屬性,所以父組件中的樣式會對子組件的最外層元素起作用,如上面的.card定義的樣式。

3.父組件中直接修改子組件的樣式

App.vue中添加:

.card .title {
    color: #eee;
}

 在父組件中直接修改子組件中(非最外層)元素的樣式,然而並不起作用,來看看怎么回事吧。

再次編譯,查看編譯后的html:

<div data-v-7a169200="" class="container">
    <h3 data-v-7a169200="" class="title">Hello Vue</h3>
    <div data-v-119ff0e6="" data-v-7a169200="" class="card">
        <div data-v-119ff0e6="" class="title">Vue Cli</div>
        <div data-v-119ff0e6="" class="list">
            <div data-v-119ff0e6="" class="item">vue serve</div>
            <div data-v-119ff0e6="" class="item">vue build</div>
        </div>
    </div>
</div>

編譯后的css:

.card[data-v-119ff0e6] {
    width: 200px;
    height: 200px
}

.title[data-v-119ff0e6] {
    height: 30px;
    line-height: 30px;
    color: #ffdead;
    padding-left: 10px;
    background-color: #87cefa
}

.item[data-v-119ff0e6] {
    height: 30px;
    line-height: 30px;
    padding-left: 10px;
    background-color: #ffe4e1
}

.container[data-v-7a169200] {
    width: 300px;
    height: 300px;
    padding-top: 10px;
    background-color: #efefef
}

.container .title[data-v-7a169200] {
    color: #709b90;
    text-align: center
}


.card[data-v-7a169200] {
    border: 2px solid#CDC9C9;
    margin-left: 50px
}

.card .title[data-v-7a169200] {
    color: #eee
}

在父組件內編寫的樣式經編譯后都會帶上和父組件元素一樣的data-v-hashxxxx,只對父組件范圍內的元素起作用,觸及不到引入的子組件的內部,也就是說無法覆蓋子組件的樣式。

4.使用 >>> 深度選擇器進行樣式穿透

在App.vue中添加樣式,修改子組件的title及列表項的字體顏色:

.card >>> .title {
    color: #eee;
}
.container .card >>> .list .item {
    color: #FF6347;
}

這次起作用了,效果如下:

再查看一下編譯后的結果,編譯后的html:

<div data-v-dba577b2="" class="container">
    <h3 data-v-dba577b2="" class="title">Hello Vue</h3>
    <div data-v-119ff0e6="" data-v-dba577b2="" class="card">
        <div data-v-119ff0e6="" class="title">Vue Cli</div>
        <div data-v-119ff0e6="" class="list">
            <div data-v-119ff0e6="" class="item">vue serve</div>
            <div data-v-119ff0e6="" class="item">vue build</div>
        </div>
    </div>
</div>

編譯后的css:

.card[data-v-119ff0e6] {
    width: 200px;
    height: 200px
}

.title[data-v-119ff0e6] {
    height: 30px;
    line-height: 30px;
    color: #ffdead;
    padding-left: 10px;
    background-color: #87cefa
}

.item[data-v-119ff0e6] {
    height: 30px;
    line-height: 30px;
    padding-left: 10px;
    background-color: #ffe4e1
}

.container[data-v-dba577b2] {
    width: 300px;
    height: 300px;
    padding-top: 10px;
    background-color: #efefef
}

.container .title[data-v-dba577b2] {
    color: #709b90;
    text-align: center
}

.card[data-v-dba577b2] {
    border: 2px solid#CDC9C9;
    margin-left: 50px
}

.card[data-v-dba577b2] .title {
    color: #eee
}

.container .card[data-v-dba577b2] .list .item {
    color: tomato
}

可以看到,使用樣式穿透后編譯后沒有在選擇器末尾添加data-v-hashxxxx屬性,而是把data-v-hashxxxx添加到了>>>的位置,這樣就能夠選中子組件中的元素了。

 

補充一下

不同css預處理器中樣式穿透的寫法:

css:  >>>

less/sass:  /deep/

scss:  ::v-deep

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM