Vue scoped 和 deep 原理
在没有 scoped 时,我们写的所有样式都是全局样式,一旦类名重复,样式就会被更改,造成污染。scope 的作用就是防止样式污染。
scoped 原理
vue 中 scoped 主要是通过 postcss 实现的,转译代码时做了如下处理:
- 给每个 DOM 节点添加一个唯一的属性(如:data-v-a0901)
- 在 css 选择器后面加上属性选择器(如:
.box[data-v-a0901]
)来私有化样式
如果组件内包含子组件,只会给子组件的最外层标签加上当前组件的 data-v 属性。
如果子组件是第三方组件,那么其最外层标签可能添加不上 data-v 属性。
转译前:
1 | <div class="box">xxx</div> |
转译后:
1 | <div data-v-a0901 class="box">xxx</div> |
scoped 产生的影响
一般情况下,有修改其他组件样式的需求时,大多是父组件修改子组件的样式,尤其是在项目中使用了第三方组件库,我们经常需要去修改他们的样式。
然而,由于组件的样式添加了属性选择器,这就会导致修改不成功。
父组件:
1 | <template> |
子组件:
1 | <template> |
编译后:
1 | <div data-v-8dea36e1 class="parent"> |
如果在父组件中修改 .child
,编译后的样式为:
1 | .child[data-v-8dea36e1] {} |
由于 .child
所在标签有 data-v-8dea36e1 属性,修改成功。
如果在父组件中修改 .child-1
,编译后的样式为:
1 | .child-1[data-v-8dea36e1] {} |
由于 .child-1
所在标签没有 data-v-8dea36e1 属性,修改失败。
此时想要修改成功,就需要用 :deep()
穿透。
deep 深度选择器
deep 的原理就是将 css 选择器的私有属性由子组件变为父组件。
在父组件中用 deep 修改子组件样式:
1 | :deep(.child-1) {} |
编译后:
1 | [data-v-8dea36e1] .child-1 {} |
将属性选择器提前,并将属性改为父组件私有属性。
现在他的匹配顺序是:先匹配带有 data-v-8dea36e1 属性的标签,然后再匹配该标签下拥有类名为 child-1
的标签。
因此可以修改成功。