在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