前言
最近鼠鼠面试的时候,被面试官问到style标签的scoped属性原理,还好我平时在浏览器面板有注意到DOM节点多了data开头的属性,现在总结分享给大家!
原理分析
当 <style>
标签带有 scoped
属性的时候,样式只会影响当前组件的元素。它的实现方式是通过 PostCSS 将以下内容:
<style scoped>
.example {
color: red;
}
</style>
<template>
<div class="example">hi</div>
</template>
转换为:
<style>
.example[data-v-f3f3eg9] {
color: red;
}
</style>
<template>
<div class="example" data-v-f3f3eg9>hi</div>
</template>
- 添加scoped属性之后,DOM节点添加了一个不重复的data开头的属性来表示其唯一性
- 添加scoped属性之后,DOM节点的css选择器末尾添加了data属性选择器来私有化该元素的样式
- 对于组件也是一样会添加data开头的属性来表示其唯一性
dom节点对应的样式规则添加的data开头的唯一标识是一致的!
style标签使用 scoped
后,父组件的样式将不会影响到子组件中。不过,子组件的根节点会同时被父组件的作用域样式和子组件的作用域样式影响。这样设计是为了让父组件可以从布局的角度出发,调整其子组件根元素的样式。
其它拓展
深度选择器
如果style标签添加了scoped
属性,如果此时想改变子组件样式,可以使用 :deep()
这个伪类:
<style scoped>
.a :deep(.b) {
/* ... */
}
</style>
上面的代码会被编译成:
.a[data-v-f3f3eg9] .b {
/* ... */
}
插槽选择器
默认情况下,作用域样式不会影响到 <slot/>
渲染出来的内容,因为它们被认为是父组件所持有并传递进来的。使用 :slotted
伪类以明确地将插槽内容作为选择器的目标:
<style scoped>
:slotted(div) {
color: red;
}
</style>
全局选择器
如果想让其中一个样式规则应用到全局,比起另外创建一个 <style>
,可以使用 :global
伪类来实现:
<style scoped>
:global(.red) {
color: red;
}
</style>
也可以在同一个组件中同时包含作用域样式和非作用域样式:
<style>
/* 全局样式 */
</style>
<style scoped>
/* 局部样式 */
</style>
总结
- 添加scoped属性之后,DOM节点添加了一个不重复的data开头的属性来表示其唯一性
- 添加scoped属性之后,DOM节点的css选择器末尾添加了data属性选择器来私有化该元素的样式
- 对于组件也是一样会添加data开头的属性来表示其唯一性