样式污染示例
一个很简单的例子,在两个组件中都有class名为test的div标签,在ScopedDemo组件中设置test样式,在ScopedChildCpm中没有设置样式。
<template>
<div class="scoped-test-wrap">
<div class="test">样式污染</div>
<ScopedChildCpm></ScopedChildCpm>
</div>
</template>
<script>
import ScopedChildCpm from "./ScopedChildCpm.vue";
export default {
name: "ScopedDemo",
components: { ScopedChildCpm },
};
</script>
<style>
.test {
width: 100px;
height: 50px;
background-color: gold;
margin: 10px;
}
</style>
<template>
<div class="test">child组件</div>
</template>
<script>
export default {
name: "ScopedChildCpm",
};
</script>
<style>
</style>
当运行程序,在浏览器中可以看到,两个组件的样式都改变了。

如果对ScopedChildCpm组件中的标签也进行样式设置结果会是怎样的,它们会按照自己的样式进行渲染吗?
<template>
<div class="test">child组件</div>
</template>
<script>
export default {
name: "ScopedChildCpm",
};
</script>
<style>
.test {
width: 100px;
height: 50px;
background-color: red;
}
</style>
浏览器渲染结果:

可以看到两个div标签都渲染了ScopedChildCpm中的设置的样式。这就是样式污染。一个组件的样式影响了项目中其他组件的样式。
解决方法
虽然我们可以给每一个样式选择器设置不同的名称,但是一个项目通常由多人完成,你无法干预其他同事的代码,所以需要一种方法能使样式之间相互不影响,即使选择器名称相同也不会相互干扰。而scoped就恰好做了这件事。
Scoped
Scoped是组件样式私有化,当一个style标签拥有scoped属性之后,它的css样式就只能作用域当前的组件。
我们先来看下使用scoped和不使用scoped的区别。
不实用scoped:

使用scoped:
可以看到style标签使用了scoped属性之后,编译之后每个组件的标签都添加了一个data-v-xxx的属性,其中data-v-xxx是scopedId,每个Vue文件都会对应一个唯一的id,该id是根据文件路径名和内容hash生成,通过组合形成scopedId,所以scopedId也是唯一的,这样不同的组件中的选择器就是唯一的,样式也就不会相互影响,从而得到我们希望的结果。

父组件和子组件中的几种情况
父组件使用scoped,子组件不使用scoped
先稍微对子组件ScopedChildCpm进行一些修改
<template>
<div class="child-wrap">
<div class="test">child组件</div>
<div class="child-div"></div>
</div>
</template>
<script>
export default {
name: "ScopedChildCpm",
};
</script>
<style>
.test {
width: 100px;
height: 50px;
background-color: red;
}
</style>

可以看到父组件使用scoped属性,子组件不使用scoped属性时,只会给子组件最外层的标签添加data-v-xxx动态属性。
父组件不使用scoped,子组件使用scoped

可以看到父组件没有动态属性,子组件有动态属性,所以子组件的scoped属性不会影响父组件。
父组件使用scoped,子组件使用scoped

可以看到子组件的最外层标签添加了两个data-v-xxx动态属性,一个是父组件生成的data-v-xxx,一个是子组件自身生成的data-v-xxx
本文探讨了Vue中样式污染的问题,并介绍了如何通过使用scoped来防止样式冲突。详细阐述了不同情况下,如父组件和子组件是否使用scoped时的样式作用范围,解释了scoped的工作原理,即通过为组件添加唯一ID实现样式私有化。
6776





