大白话理解scoped
在style标签设置scoped属性,可以使组件之间的样式不互相污染,达到样式私有模块化的目的。
接下来,我们分别从原理、优缺点、解法来认识下
原理:
style标签设置scoped属性,经过PostCSS转译后,在DOM结构以及css样式上加唯一的标记:data-v-hash属性,意味着CSS样式就只能作用于当前组件,从而使得组件之间的样式不互相污染,达到样式私有模块化的目的。
1)当前组件的DOM根节点及其子节点加一个不重复data属性(如data-v-19fca230),
2)当前组件引入子组件,那么,给子组件的根节点加上当前组件的data属性
3)在每句css选择器的末尾加一个当前组件的data属性选择器(如data-v-19fca230)
举个例子
例一:
<style scoped>
.wrap{
backgorund: lightsalmon
.parent1{
color: red
}
}
.parent2{
color: green
}
</style>
转译后, 当前组件的Dom根节点及子节点都有了一个[data-v-5406a40e]属性,其选择器末尾加一个当前组件的[data-v-5406a40e]属性
例二:引入子组件
// 父组件
<template> <div class="wrap"> <h1 class="parent">当前组件1</h1> <childCompontent class="childCompontent"></childCompontent> </div> </template> <style scoped> .childCompontent{ backgorund: lightgreen } </style>
// 子组件 <template> <div>
<h1 class="child-wrap">子组件</h1>
</div>
</template>
<style scoped>
</style>
转译后,
当前组件引入子组件,在子组件的style标签加了scoped, 那么,仅子组件的Dom根节点会带有父组件相同的[data-v-5406a40e]属性。
带有childCompontent的标签,其选择器末尾加一个当前父组件的[data-v-5406a40e]属性,而引入的child-wrap的标签,其选择器末尾加一个当前组件,也就是子组件组件的[data-v-180cce0f]属性
要是想在当前父组件中修改子组件的样式,怎么办呢?
直接修改,如下
// 父组件
<template> <div class="wrap"> <childCompontent class="childCompontent"></childCompontent> </div> </template> <style scoped>
.wrap .child-wrap{
color: red
}
</style>
结果,没有生效。那是因为渲染后,css选择器样式如下:
// 父组件渲染后
.wrap .child-wrap[data-v-5406a40e] { color: red; }
// 子组件渲染后
.child-wrap[data-v-180cce0f] {
color: lightpink;
}
目标子组件css选择器是.child-wrap[data-v-180cce0f] ,而我们在父组件修改的是data-v-5406a40属性的child-wrap,根本作用不到我们想要的DOM
节点上,
这种情况我们在父组件内部写的任何样式都不会影响到子组件组件,所以这就尴尬了。。。。
解决方法:
1)在模板中使用两次style标签:一个用于私有样式(带scoped属性),一个用于共有样式
<style lang="scss"> /* 需要覆盖的样式--注意css权重 */
.wrap .childCompontent .child-wrap{
</style> <style lang="scss" scoped> /* 当前组件的私有样式 */ </style>
2)使用 >>> 或者 /deep/ 操作符 (Sass、Less等预处理器无法正确解析 >>>,可以使用/deep/ )
<style lang="scss" scoped> .wrap /deep/ .child-wrap { color: red } } </style>