Content Table

Vue 尽量不用 scoped

在 Vue 中,为了减少样式的冲突,可以使用 scoped 使得生成的 DOM element 和 class 都带上随机属性,但有利有弊,总的来说,不推荐使用 scoped,因为使用 scoped 后就不能跨级设置组件的样式了。

跨级: 组件 A 中直接使用组件 B,组件 B 中直接使用组件 C,因为 C 没有在 A 中直接使用,所以我们说 A 和 C 跨级了。

下面在页面 Demo 里使用组件 XButton 和 XForm 进行演示:

  • Demo 是 scoped 的,使用 XForm 和 XButton
  • XForm 中使用 XButton

XButton.vue

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>

XForm.vue

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。