文章目录
- 参考
- 描述
- 样式冲突
- 现象
- scoped
- 原理
- 样式穿透
- 深度选择器
- 使用
- 原理
- 顶层元素
- 局限性
参考
项目 | 描述 |
---|---|
搜索引擎 | Bing |
哔哩哔哩 | 黑马程序员 |
描述
项目 | 描述 |
---|---|
Edge | 109.0.1518.70 (正式版本) (64 位) |
操作系统 | Windows 10 专业版 |
@vue/cli | 5.0.8 |
npm | 8.19.3 |
VueJS | 2.6.14 |
样式冲突
在使用 Vue 进行前端工程化开发后,对 Vue 进行打包的过程中将会把所有组件中的所有样式代码都转移到 Vue 项目中的 index.html 文件中。也就是说,在默认情况下,在组件的 style 元素内部编写的样式代码能够影响的并不只是当前的组件。这种情况容易导致样式之间发生冲突(样式的覆盖),不利于 Vue 项目的组件化开发。
现象
App.vue
<template>
<div class="container">
<h3>TwoMoons</h3>
<Child></Child>
</div>
</template>
<script>
// 导入组件
import Child from '@/components/Child.vue';
export default {
// 注册组件
components: {
Child
}
}
</script>
<style>
/* 为 h3 标签设置样式 */
h3{
color: #f40;
font-size: 18px;
}
</style>
Child.vue
<template>
<div class="child">
<h3>RedHeart</h3>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
效果:
我仅在组件 App.vue 中为 h3 元素设置了样式,可是这个样式影响到了另外的组件中的 h3 元素。
scoped
VueJS 提供了 scoped 属性,将该属性应用到组件中的 style 元素中,就能够避免发生样式冲突。
修改 App.vue
<template>
<div class="container">
<h3>TwoMoons</h3>
<Child></Child>
</div>
</template>
<script>
// 导入组件
import Child from '@/components/Child.vue';
export default {
// 注册组件
components: {
Child
}
}
</script>
// 添加 scoped 属性,防止发生样式冲突
<style scoped>
/* 为 h3 标签设置样式 */
h3{
color: #f40;
font-size: 18px;
}
</style>
效果:
原理
在组件中使用 scoped 后,将在当前组件中的 template 元素内的元素中添加一个形如 data-v-* (每一个组件的 data-v-* 都不相同)的自定义属性。除此之外,VueJS 还将自动在原有的 CSS 选择器中添加属性选择器以选择带有自定义属性 data-v-* 的元素。
通过以上两点处理,我们就可以仅选择本组件中的元素进行样式设置了。
在浏览器中打开开发者工具观察上一个示例,你将有如下发现:
自定义属性
属性选择器
样式穿透
深度选择器
在为元素添加 scoped 后,当前组件的样式并不会应用到子组件中。在开发过程中,我们可能需要使用到第三方组件,在第三方组件中修改样式并不推荐,这样做容易造成混乱。我们需要在父组件中对其进行修改,为此我们可以使用深度选择器。
深度选择器可以在保证不发生全局样式冲突的前提下,将父组件中的样式应用到子组件(准确来说应该是当前组件的所有后代组件)中。深度选择器存在三种类型,它们分别对应不同的使用场景。
项目 | 描述 |
---|---|
CSS | >>> |
Less | /deep/ |
Scss | ::v-deep |
虽然三种深度选择器的应用场景不同,但三者的使用方式类型。在演示过程中仅使用 CSS 场景下的深度选择器。
使用
App.vue
<template>
<div class="container">
<h3>TwoMoons</h3>
<Child></Child>
</div>
</template>
<script>
// 导入组件
import Child from '@/components/Child.vue';
export default {
// 注册组件
components: {
Child
}
}
</script>
// 添加 scoped 属性,防止发生样式冲突
<style scoped>
/* 使用 CSS 场景下的深度选择器实现样式穿透 */
>>> h3{
color: #f40;
font-size: 18px;
}
</style>
Child.vue
<template>
<div class="child">
<h3>RedHeart</h3>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
效果:
父组件中的样式在添加了 scoped 属性的情况下应用到了子组件中。
注:
在使用深度选择器时,你的编辑器也许会在深度选择器下显示红色波浪线以提示开发者代码编写错误,请不要理会,深度选择器在 VueJS 中是合理的。
原理
请使用开发者工具观察上个示例,你将会有如下发现:
属性
可以看到使用了深度选择器后,style 元素的子元素的属性并没有发太大变化(相比没有使用深度选择器而 style 添加了 scoped 属性的情况)。
选择器
为了选择当前组件的子组件中的元素进行样式设置,先使用属性选择器选择自定义属性以指定当前组件(不同的组件 ,VueJS 为其分配的自定义属性 data-v-* 不同),再通过后代选择器选择当前组件的后代组件中的相应元素。
顶层元素
相信各位也都发现了一个问题,即子组件的顶层元素也被添加了当前组件所独有的自定义属性。
这意味着我们可以不使用深度选择器,达到样式穿透的目的,只是这种方法的局限性更大。
App.vue
<template>
<div class="container">
<h3>TwoMoons</h3>
<Child></Child>
</div>
</template>
<script>
// 导入组件
import Child from '@/components/Child.vue';
export default {
// 注册组件
components: {
Child
}
}
</script>
// 添加 scoped 属性,防止发生样式冲突
<style scoped>
h3{
color: #f40;
font-size: 18px;
}
</style>
Child.vue
<template>
<!-- 将需要被样式穿透的元素放置为当前组件的顶层元素 -->
<h3>RedHeart</h3>
</template>
<script>
export default {
}
</script>
<style>
</style>
效果:
局限性
- 由于组件中的 template 元素内仅允许使用一个根元素,即仅能存在一个顶层元素,所以使用该方式仅能选中子组件中的单个元素。
- 该方式并不像深度选择器可以选中当前组件的后代组件中的相应元素,仅能选中子组件中的相应元素。