对于scoped,之前只知道它可以避免父组件中的样式渗透到子组件中。原理是给每个组件添加唯一属性,而位于最后的选择器也对应地赋予属性限制。
简单地认为只要加了scoped就完全地独立开来了是错误的。下面举几个容易碰到的问题。
父组件和子组件设置样式
父组件
xml
<template>
<div class="container">
<Child />
</div>
</template>
<script>
import Child from "./components/Child.vue";
export default {
components: {
Child,
},
};
</script>
<style scoped>
.container {
width: 100px;
height: 100px;
background-color: red;
}
.child-container {
color: blue;
}
</style>
子组件
xml
<template>
<div class="child-container">child</div>
</template>
<style scoped>
.child-container {
color: pink;
}
</style>
子组件的div的字体是蓝还是粉?
答案是蓝。因为子组件的根元素也被加了父组件的唯一属性。那么第一个文件和第二个文件都对同一个元素设置样式,最终以父组件的为准。
再看一个例子,父组件同上,子组件
xml
<template>
<div>
<div class="child-container">child</div>
</div>
</template>
<style scoped>
.child-container {
color: pink;
}
</style>
子组件的div的字体是蓝还是粉?
答案是粉。因为只对子组件的根元素添加了父组件的唯一属性,再深入的元素都没有添加了。所以父组件的样式是无效的,没有一个class为child-container且有父组件属性的元素,只有子组件自己的样式才是有效的。
样式失效
参考文章如下,写的很好。
原先是4个div,拓展一下变为5个div,这种情况如何使用深度选择器去解决呢?
父组件
xml
<script setup>
import Component from "./components/Child.vue";
</script>
<template>
<div class="div1">
div1
<div class="div2">
div2
<Component />
</div>
</div>
</template>
<style scoped>
.div1 {
color: red;
}
.div1 .div2 {
color: blue;
}
.div1 .div2 .div3 {
color: green;
}
.div1 .div2 .div3 :deep(.div4) {
color: yellow;
}
.div1 .div2 .div3 :deep(.div4) .div5 {
color: purple;
}
</style>
</style>
子组件
xml
<script setup>
</script>
<template>
<div class="div3">
div3
<div class="div4">
div4
<div class="div5">div5</div>
</div>
</div>
</template>
<style scoped>
.div3 {
}
.div4 {
}
.div5 {
}
</style>
都是直接给子组件的根元素的第一个子元素加上:deep()即可,使得选择器的属性限制都退到子组件的根元素上。
附上深度选择器的写法
注意
vue2没什么问题,vue3的组件可以不只有一个根元素,当只有一个根元素还是符合上述规律。但是如果不止一个根元素,则子组件下的所有元素都不会添加父组件的唯一属性。
最佳实践
综上所述,最佳实践是全部用scoped,在需要深度选择器的地方再添加深度选择器。