「这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战」
前言
scoped也叫范围样式,曾经是h5的新特性,只是后面又取消了, 具体可以参考这篇帖子github.com/whatwg/html… , 后面vue受到启示,借用了这个概念,又重新实现了一次。
在Vue中当一个style标签拥有scoped属性时候,它的css样式只能用于当前的Vue组件,可以使组件的样式不相互污染。如果一个项目的所有style标签都加上了scoped属性,相当于实现了样式的模块化。
scoped原理
Vue中的scoped属性的效果主要是通过PostCss实现的。以下是转译前的代码:
<template>
<div class="main">
<p class="title">title</p>
</div >
</template>
<style scoped>
.title{
margin: 0 0 10px 0;
}
</style>
转换结果:
<div data-v-f3d719be class="main">
<p data-v-f3d719be class="title">
test
</p>
</div>
<style>
.title[data-v-f3d719be] {
margin: 0 0 10px 0;
}
</style>
既:PostCSS给一个组件中的所有dom添加了一个独一无二的动态属性,给css选择器额外添加一个对应的属性选择器,来选择组件中的dom,这种做法使得样式只作用于含有该属性的dom元素(组件内部的dom)。
scoped带来的问题
test.vue文件
<template>
<div class="main">
<p class="title">title</p>
<HelloWorld></HelloWorld>
</div >
</template>
<style lang="less" scoped>
.title{
margin: 0 0 10px 0;
.content{
.hello{
color:green;
}
}
}
</style>
helloworld.vue文件
<template>
<div class="content">
<p class="hello">
helloworld
</p>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
}
}
</script>
<style lang="less" scoped>
.hello{
margin: 40px 0 0;
/*color:red;*/
}
</style>
渲染后的结果
可以看到红框里的div 有两个data-v-hash, 一个是父组件的scoped生成的,一个是子组件scoped生成的, 所以父组件生成的data-v-hash仅仅是在子组件的最外层的div才会有,而在子组件的内部元素是不存在父组件生成的data-v-hash。
假设现在有一个这样的需求,需要在父组件里面控制子组件的样式,从而达到不影响别的使用了该组件的页面,但是scoped关键字使得,父组件的样式仅仅作用于父组件的元素和子组件的最外层div,假设子组件的代码如下:
<template>
<div class="son">
son
<p class="grandson">
helloworld
</p>
</div>
</template>
父组件的代码为下:
<template>
<div class="main">
<p class="title">title</p>
<HelloWorld></HelloWorld>
</div >
</template>
<style lang="less" scoped>
.title{
margin: 0 0 10px 0;
}
.main .son{
color:red;
}
.main .son .grandson{
color:yellow !important;
}
</style>
效果如下:
可以看到.main .son .grandson{ color:yellow !important; }即使加了!important,也没有生效。
解决方案
加入/deep/即可生效:
.main /deep/ .son .grandson{
color:yellow ;
}
效果如下:
可以看到已经生效。
在css中/deep/应该改为>>>, 在vue3中应该改为::v-deep。
当然还有其他方案,就不再赘述。
总结
看到一篇文章写到scoped是h5的新特性, 心中非常疑惑,印象中scoped是vue的特性,怎么成了h5的特性了,于是多方求证, 原来h5确实曾经规划过范围样式scoped,只是大部分浏览器都没有实现,后面又取消了这个特性, 而vue借鉴了这个概念,并且自己实现了该特性。