为什么要使用scoped
vue中为了让样式私有化,不至于当前组件的css样式对全局造成污染,添加了scoped属性,但同时也要慎重的使用,因为一旦出现问题,排查起来可能会很麻烦。
scoped工作原理
我们平时开发vue的时候可能会比较好奇,经常会看到data-v-asf23235kd33k
在dom元素中出现,其实这就是scoped做的事情,比如我们一个button
组件,我们定义了如下scoped样式,给按钮添加一个边框弧度。
<template>
<button class="button">text</button>
</template>
<style scoped>
.button {
border-raduis: 1px;
}
</style>
这样最终渲染出来的页面代码应该是这样的
<button class="button" data-v-123lsdfasi32>
text
</button>
.button[data-v-123lsdfasi32]{
border-raduis: 1px;
}
可以看到这样一来,本页面定义为scoped下的样式属性,仅可能作用于当前组件,即使该组件被引用,也不会和其他的button属性产生冲突。
总结:
- 给DOM节点添加一个标志属性
- 给渗透DOM节点的样式属性添加一个属性选择器。(间接提升了样式的权重)
对上述情况做一下补充说明,css属性会叠加,类属性和属性选择权重为 0 0 1 0,叠加后权重变为0 0 2 0,所以通过一个简单的类属性可能无法覆盖了,需要一个id选择器或者内联样式。
实际使用
在引用组件到页面中的时候,总是会有需求说本页面修改一下组件的样式吧,但是由于scoped属性产生的data-v-12jfsjjj
只会作用于组件DOM元素的最外层标签,所以父组件的样式不会渗透到子组件中去【这里要自行理解一下为什么无法渗透,不做举例】。如果不使用scoped又怕样式渗透到全局?可以使用渗透scoped穿透
,个人理解这样的工作原理为沿用子组件生成的序列号,不重新生成。
.outer /deep/ .button { // outer为组件外层属性样式名称,没有的话也可以不加
border-raduis: 1px;
}
注意,如果使用stylus,渗透符号为 >>>
。
动态生成的DOM类名可能在scoped中也不会有作用,这个时候也可以添加/deep/来让样式生效。
问题回顾
在之前的项目中,有一次样式污染导致了一个比较严重的后果,我的自定义的一个折叠框,当项目一开始运行的时候不会出问题,但是项目运行一段时间之后,折叠框的内容就都看不到了,DOM节点都是有的,样式却变成了
opacity: 0;
这个问题当时我通过行内样式设置为!important
解决掉了,由于开发的是移动端,结果发现这个问题耗费了很长的时间,当时没有细究,今天学习后发现有一个组件使用过程中定义了一个和我一样的class属性,但是他却没有把这个属性放到<scoped>
中(当然了,作为一个公共组件组件这样使用肯定是不合理的),直接导致了他的样式合并到了同名的我的样式中,导致了这个问题,希望大家引以为戒。