在 Vue 中,为了减少样式的冲突,可以使用 scoped 使得生成的 DOM element 和 class 都带上随机属性,但有利有弊,总的来说,不推荐使用 scoped,因为使用 scoped 后就不能跨级设置组件的样式了。
跨级: 组件 A 中直接使用组件 B,组件 B 中直接使用组件 C,因为 C 没有在 A 中直接使用,所以我们说 A 和 C 跨级了。
下面在页面 Demo 里使用组件 XButton 和 XForm 进行演示:
- Demo 是 scoped 的,使用 XForm 和 XButton
- XForm 中使用 XButton
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <template> <span class="x-button"><slot>X-Button</slot></span> </template>
<script> export default { data() { return {}; }, }; </script>
<style lang="scss"> .x-button { display: inline-block; width: 200px; height: 40px; line-height: 40px; text-align: center; border-radius: 4px; border: 1px solid gray; } </style>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <template> <div class="x-form"> <XButton>X-Button in Form</XButton> </div> </template>
<script> import XButton from '@/components/XButton.vue';
export default { components: { XButton }, data() { return {}; }, }; </script>
<style lang="scss">
</style>
|
Demo.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <template> <div class="demo"> <XForm/> <br> <XButton/> </div> </template>
<script> import XForm from '@/components/XForm.vue'; import XButton from '@/components/XButton.vue';
export default { components: { XForm, XButton }, data() { return {}; }, }; </script>
<style lang="scss" scoped> .demo { .x-button { border-radius: 14px; } } </style>
|
代码分析
观察生成的代码,Demo 的 <style>
由于使用了 scoped,它直接使用的组件 XButton 会生成一个随机属性 dava-v-5ad1f0c6
,而跨级的组件 XButton (Form 里使用的) 则不会生成这个随机属性,并且生成的 <style>
中 class x-button[dava-v-5ad1f0c6]
使用了这个随机属性进行元素选择,所以 Demo 源码的 <style>
中定义的 class x-button
的样式只对直接使用的 XButton 生效,而对跨级使用的 XButton 无效,导致不能在 Demo 中修改所有使用到的 XButton 的样式。
在实际项目里跨级使用组件是很常见的,并且很多时候都要修改他们的样式,这时就不能使用 scoped 了。为了减少样式冲突,推荐每个页面都定义自己唯一的 class,使用 SCSS 写样式,尽量把样式的路径写全,并且不要使用 scoped。