vue | scoped与深度选择器

本文介绍了Vue中的scoped style特性,用于限制样式只作用于当前组件及其子组件,防止样式污染。讨论了scoped style的工作原理,澄清了理解误区,并探讨了如何在需要时使用深度选择器。此外,还比较了scoped style与class的性能和优先级问题。


若文章有任何纰漏或未涉及你想了解的内容,欢迎在评论提出,我会尽最快速度回复。

什么是scoped style

html scoped

scoped style最初是一个html5的特性。使用该属性,即为样式添加了作用域,使样式仅应用到 style 元素的父元素及其子元素上。
但仅有firefox支持,它的定义与使用详见html scoped
这种scoped特性之所以没有被广泛使用,是因为其将样式写在html内部,很影响代码可读性和可维护性。在传统的面向页面开发时代,样式作用域的迫切性也并不是很高。

vue scoped

与html scoped类似的,vue引入了scoped style的概念。
它的作用是将声明样式的作用域限制于当前组件与子组件的根节点。它的实现方法是为html节点添加唯一序列标识,即使用特性选择器进行样式定义。
例:

<style scoped>
.target{
 color : royalblue
}
</style>

将被处理为

<style>
.target[data-v-7ba5bd90]{  
 color : royalblue
}
</style>

为什么使用scoped style

MVVM框架的主要场景是面向组件的单页面应用开发(SPA)
在SPA开发中,所有组件的CSS都会被打包挂载到单一页面原理),因此尽管开发是组件化的,但CSS最终是混在一起的,组件间样式会相互污染

  • 为避免样式污染,我们有两种解决方法,而scoped style是其中一种,它的本质是CSS模块化。另一种是使用传统的class/id分类。
  1. 像面向页面开发一样,使用唯一的class/id进行细粒度区分,除全局样式外,不使用元素选择器。
  2. 使用scoped style使样式组件化。
  • 两者的优劣:
    class与scoped style各有优劣,class分类简单原始,但在大项目开发中,容易出现标签冗余,就像bootstrap,可读性很差。而scoped style可以避免标签冗余,实现样式的组件化,但其性能稍逊,且遇到修改第三方UI库的场景时,需要使用深度选择器。

scoped style 详解

理解误区

很多初学者将scoped style理解为使组件不受全局样式的污染。
但这个理解方向反了,实际情况是:

  1. scoped style是将样式限定于本组件,不污染其它组件
  2. 全局样式依然可能影响scoped style
  3. 全局选择器的优先级低于同类型特性选择器,即scoped style。

示例:

  • son组件:
  <div>
    <span>{{msg}}</span>
  </div>
<style scoped>
span {
  color: royalblue;  /* 特性选择器优先级高,生效 */
}
</style>

<style>
span {
  color: red;   /* 优先级低,被覆盖 */
  border: solid;  /* 全局样式有效 */
}
</style>

在这里插入图片描述

  • app组件
<div id="app">
    <span>app here</span>
    <son></son>
  </div>

在这里插入图片描述
全局样式污染了app组件,而scoped style则不会影响。

作用域与深度选择器

scoped style为当前元素以及其子元素的根节点添加统一的序列标识。
如下所示:
在这里插入图片描述
style scoped的目的就是为了实现样式组件化,我们只会对本组件元素进行样式定义,没有理由对子组件内部元素跨级修改样式,这是与组件化初衷矛盾的。
但引入第三方UI库后,又要修改默认样式时,我们不得不深入子元素修改内部样式。

如果使用后代选择器是没法修改子元素内部样式的。
示例如下:

<style scoped>
.el-input .el-input__inner {
  border: royalblue solid;
}
</style>

等价于

<style>
.el-input .el-input__inner[data-v-469af010] {
  border: royalblue solid;
}
</style>

子元素的内部元素并没有序列标识,故无法被选中。
在这里插入图片描述
在这里插入图片描述
此时,我们需要使用深度选择器 >>> (在sass/scss中写作/deep/),这样就可以深入子元素内部修改样式了。

<style scoped>
.el-input >>> .el-input__inner {
  border: royalblue solid;
}
</style>

在这里插入图片描述

优先级

在相同级别的选择器下,特性选择器即scoped style的优先级高于全局样式。
而优先级更高的选择器仍会高于低优先级的特性选择器,比如id选择器优先于类特性选择器。
示例如下:

  1. 同级别选择器下, scoped style定义的border样式生效
<style scoped>
.el-input >>>.el-input__inner {
  border: royalblue solid;
}
</style>

<style>
.el-input__inner {
  border: brown solid;
}

</style>

在这里插入图片描述

  1. 优先级更高的id选择器定义的border样式生效
<style scoped>
.el-input >>>.el-input__inner {
  border: royalblue solid;
}
</style>

<style>
#ipt{
  border: orange solid;
}
</style>

在这里插入图片描述

scoped style与class的性能对比

scoped style的性能要稍劣于class。
性能差别测试如下:

  • class选择器渲染效率:
    在这里插入图片描述
  • scoped style(特性选择器)
    在这里插入图片描述

动态生成内容

动态生成内容,即v-html因为渲染机制,会不受scoped样式影响,但你仍可以通过深度选择器设置它们的样式

### 如何通过 VueScoped CSS深度选择器修改子组件样式Vue 中,`<style scoped>` 提供了一种机制来限制样式作用范围,使其只应用于当前组件中的 DOM 节点。然而,默认情况下,这些作用域样式的规则不会穿透到子组件中。为了能够修改子组件的样式,可以使用 **深度选择器** `/deep/` 或 `>>>`。 以下是具体方法和示例: #### 方法说明 当 `<style scoped>` 应用于一个组件时,Vue 会自动为该组件内的 HTML 元素添加唯一的属性(通常是类似于 `data-v-f3f3eg9` 的形式)。同时,所有的样式也会被改写成带有相同属性的选择器[^2]。这确保了样式的隔离性。如果希望某些样式能影响子组件,则可以通过深度选择器覆盖默认的行为。 #### 示例代码 下面是一个完整的例子展示如何利用深度选择器修改子组件的样式: ```vue <!-- ParentComponent.vue --> <template> <div class="parent"> <ChildComponent /> </div> </template> <style scoped> /* 正常的本地样式 */ .parent { background-color: lightblue; } /* 使用深度选择器修改子组件样式 */ /deep/ .child-class { color: green !important; /* 强制设置颜色 */ } </style> ``` ```vue <!-- ChildComponent.vue --> <template> <div class="child-class">我是子组件的内容。</div> </template> <style scoped> .child-class { color: blue; /* 默认蓝色会被父组件的绿色覆盖 */ } </style> ``` 在这个例子中,尽管 `.child-class` 在子组件中有定义的颜色是蓝色,但由于父组件使用了深度选择器 `/deep/` 并设置了更高的优先级 (`!important`),最终显示的文字颜色将是绿色[^1]。 #### 注意事项 - 如果项目中使用的是 PostCSS 插件或者较新的 Vue 版本 (如 Vue CLI),可能需要替换 `/deep/` 为 `::v-deep` 来兼容最新的语法标准。 - 对于 Vue 3 用户来说,推荐直接采用 Composition API 配合动态类名的方式处理复杂的跨层样式需求,而不是依赖传统的深度选择器[^3]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值