Vue样式scoped原理以及样式穿透原理
构建工具调用相应的处理器(loader),当 SFC 组件是 style 标签包含 scoped 属性时,处理器会给组件的 DOM 节点和子组件添加自定义属性data-v-xxx,子组件只会在最外层 DOM 节点添加自定义属性data-v-xxx,然后会给组件内 CSS 选择器之后添加对应的属性选择器[data-v-xxx]。
# 举例说明
父组件 template 内容:
<template>
<div>
<span>Hello World! I'm father!</span>
<span>I love coding.</span>
<SonComponent></SonComponent>
</div>
</template>
<style>
span {
color: red;
}
.hobby{
background-color: yellowgreen;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
子组件 template 内容:
<template>
<div>
<div>Hello, I'm son!</div>
<div class="hobby">I love painting.</div>
</div>
</template>
<style>
div {
color: blue;
}
.hobby{
background-color: pink;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
如果父组件和子组件都没有在 style 标签上添加 scoped 属性,渲染后的结果是:
<div>
<span>Hello World! I'm father!</span>
<span>I love coding.</span>
<div>
<div>Hello, I'm son!</div>
<div>I love painting.</div>
</div>
</div>
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
给父组件和子组件 style 标签添加 scoped 属性,渲染的结果是:
<div data-v-938b83b0>
<span data-v-938b83b0>Hello World! I'm father!</span>
<span data-v-938b83b0>I love coding.</span>
<div data-v-938b83b0 data-v-fb8c5270>
<div data-v-fb8c5270>Hello, I'm son!</div>
<div data-v-fb8c5270>I love painting.</div>
</div>
</div>
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
div[data-v-f2eb8ef8]{color:#00f}
.hobby[data-v-f2eb8ef8]{background-color:pink}
span[data-v-080e8582]{color:red}
.hobby[data-v-080e8582]{background-color:#9acd32}
1
2
3
4
2
3
4
此时,如果想修改子组件的样式,只能修改子组件最外层元素样式,无法修改子组件内部的元素的样式,因为父组件中,所有 CSS 选择器的后面都添加了父组件的自定义属性data-v-f2eb8ef8,只有拥有属性data-v-f2eb8ef8的元素才能应用父组件 CSS 选择器中的样式,子组件中除了子组件最外层元素,都没有data-v-f2eb8ef8属性。
要想改变子组件内部的样式,在 vue3 中需要在选择器使用:deep()包裹,生成的 CSS 会将data-v-f2eb8ef8提到选择器前方,而不是后方,此时,子组件最外层元素是有data-v-f2eb8ef8属性的,因此能够实现选择子组件的元素,实现样式穿透。
div[data-v-f2eb8ef8] {color:#00f}
.hobby[data-v-f2eb8ef8] {background-color:pink}
span[data-v-0a512275] {color:red}
[data-v-0a512275] .hobby{background-color:#9acd32}
1
2
3
4
2
3
4
样式穿透不仅可以穿透子组件,还可以穿透深层的后代组件
上次更新: 2023/12/16, 09:22:46