组件作用域 CSS - scoped 样式与深度作用选择器原理及兼容性测试汇总
引言
在 Vue 的单文件组件(SFC)中,借助 <style scoped>
,开发者可以实现样式在组件内部生效、外部隔离,避免样式污染。
但在某些场景中,如需要对子组件或第三方组件库中的 DOM 元素进行样式控制,但又被 scoped 形成的作用域所隔离。这时就需要使用 Vue 提供的“深度作用选择器”(如 >>>、 /deep/、::v-deep、:deep 等)来穿透作用域限制。
本文将从原理、语法、兼容性、构建工具支持等多个维度,系统梳理深度作用选择器的演进过程与使用要点,结合 Vue 版本与构建工具(vue-cli、webpack、vite)进行全面测试对比,帮助开发者理解其实际行为边界与最佳实践。
本文描述的现象所基于的测试环境:
测试环境 | vue 版本 | 构建工具 | CSS 预处理器相关依赖 |
---|---|---|---|
Env01 | vue(2.6.10) | vue cli(3.12.1) | node-sass(4.14.1)、sass-loader(8.0.2) |
Env02 | vue(2.6.12) | vue cli(4.4.6) | sass(1.32.13)、sass-loader(10.1.1) |
Env03 | vue(3.5.13) | vite(6.1.0) | sass(1.85.0) |
scoped 作用域样式
⚠️ 注意
本小节中的描述,只适用于组件中普通的 DOM 元素,并不包含组件中 slot 元素的表现。
本质:样式局部化
❌ 通常误解:
scoped 实现了“样式隔离”。
这个说法被广泛使用,但不够严谨,因为它隐含了“样式隔离是双向的”——即内部不影响外部,外部也不影响内部,而实际上并非如此。
✅ 准确的说法:
scoped 的本质是通过给当前组件的样式规则集都添加一层唯一的属性选择器(如 data-v-xxxx),只有当前组件的元素才能匹配上这些规则,从而达到限制当前组件样式的作用范围,防止样式“向外溢出”,但并不能阻止当前组件中的元素匹配上外部样式。
- 外部样式:指的是项目中的全局样式或父组件中的透传样式,以及第三方组件库的样式。(编译打包后,本质都是些不同的样式文件组成,并没有“内外部之分”)
- 向外溢出:在我们本文范畴下讨论的场景中,指的是样式在组件外部被应用。
要实现真正的“样式隔离”,需要使用 Shadow DOM 等更底层的技术机制。
原理:添加唯一属性选择器
引言
在 Vue 的单文件组件(SFC)中,当你为 <style>
标签添加 scoped 属性时,Vue 会在编译阶段为当前组件生成一个唯一的标识符(如 data-v-xxxx
), 并将其作为属性添加到组件模板中的 DOM 元素上,同时将样式规则改写为带有该标识的属性选择器(如 .box[data-v-xxxx]
),从而将样式局部作用于当前组件,实现样式的封装,避免样式冲突和污染。
<template>
<div class="title">Hello</div>
</template>
<style scoped>
.title {
color: red;
}
</style>
<style>
.title[data-v-1a2b3c] {
color: red;
}
</style>
<div data-v-1a2b3c class="title">Hello</div>
这背后的机制大致分为以下几个步骤:
- 为每个组件生成唯一的作用域标识符: Vue 会在编译过程中,为每个组件生成一个唯一的作用域标识符,通常是一个哈希值。假设 Vue 为当前组件生成的标识符是 data-v-1a2b3c。
- 修改 DOM 元素,加入作用域标识符属性: Vue 会修改组件的 DOM 元素,在每个元素上自动添加这个唯一的作用域标识符属性(如:data-v-1a2b3c)。
- 修改样式规则,加入作用域标识符属性选择器: Vue 在编译带有
<style scoped>
的样式时,会为每条CSS规则添加上对应组件的作用域标识符 属性选择器(如:.box[data-v-1a2b3c])。
- 修改样式规则,加入作用域标识符属性选择器: Vue 在编译带有
这样就形成了样式作用域,将当前组件的样式与其他组件的样式隔离开来。只有当前组件的元素才能匹配这些规则,而不会影响其他组件中的元素。
总结
Vue 中的 scoped
样式机制是通过编译和运行时的技术手段来实现的,具体背后的实现原理主要涉及 编译过程中的样式转换 和 DOM元素属性的动态修改。 以下是详细的实现原理分析,涵盖了 编译过程、作用域标识符的生成、样式的自动作用域匹配 等技术细节。
Vue 使用了基于 模板编译 的工作流来处理 .vue 单文件组件中的
<style scoped>
标签。编译过程的关键步骤包括:
Vue 编译器解析模板: 当你在
.vue
文件中使用<style scoped>
时,Vue 的编译器会解析和编译模板、脚本、样式三个部分。在这个过程中,Vue 会识别到<style scoped>
标签,并为其添加特定的作用域标识符。生成作用域标识符:Vue 为每个组件生成一个唯一的标识符,这通常是一个短的哈希值。这个标识符是通过组件的路径或组件 ID 生成的,例如
data-v-123abc
。 该标识符会在编译过程中添加到组件内的所有 DOM 元素上(通过data-v-xxxxxx
属性),同时也会被加到组件的 CSS 选择器中,以确保样式只作用于当前组件的 DOM 元素。举个例子,假设你在模板中有一个
<div class="box">
,Vue 在渲染时,会将这个 div 元素转换成:html<div class="box" data-v-123abc>Box content</div>
转换样式选择器:Vue 会对样式进行转换。对于 scoped 样式中的选择器(例如
.box
),Vue 会将其转换为带有作用域标识符的选择器(如.box[data-v-123abc]
)。
例如:css.box { color: red; }
会被转换为:
css.box[data-v-123abc] { color: red; }
这样一来,样式规则就会只作用于当前组件中的
.box
元素,而不会影响到外部其他组件中的.box
元素。
限制与注意事项
⚠️ 注意
- 子组件的样式无法通过 scoped 直接影响:scoped 样式只会作用于当前组件的 DOM 元素和子组件的根节点,不会渗透到子组件中。如果需要对子组件的元素应用样式,可以使用深度选择器。
- 作用域样式并没有消除对 class 的需求:由于浏览器渲染各种各样 CSS 选择器的方式,p { color: red } 结合作用域样式使用时 (即当与 attribute 选择器组合的时候) 会慢很多倍。如果你使用 class 或者 id 来替代,例如 .example { color: red },那你几乎就可以避免性能的损失。
- 小心递归组件中的后代选择器:对于一个使用了
.a .b
选择器的样式规则来说,如果匹配到 .a 的元素包含了一个递归的子组件,那么所有的在那个子组件中的 .b 都会匹配到这条样式规则。 - 动态生成的内容:通过 v-html 创建的 DOM 内容不受作用域内的样式影响,但是仍然可以通过深度作用选择器来为他们设置样式。
- Vue3 中默认不会影响到当前组件的
<slot/>
中渲染的内容:在 Vue3 中,当前组件的作用域样式默认是不会作用于当前组件<slot>
渲染出来的内容(但插槽默认填充内容除外),因为插槽中的元素被认为是父组件所持有并传递进来的。
scoped 下的 slot
引言
前面一节中提到的,诸如:“子组件的样式无法通过 scoped 直接影响,需要使用深度选择器”、“只有当前组件的元素才能匹配这些规则,而不会影响其他组件中的元素”。
这些描述只适用于组件中普通的 DOM 元素,并不包括组件中 slot 元素的表现。
样式作用域下的 slot 表现,在 vue2 和 vue3 两个版本中各有差异:
父组件 scoped 样式可作用于传递给子组件插槽的元素
示例代码
<template>
<div class="parent">
<Child>
<h2 class="child-title">
<span>this is an child title</span>
</h2>
</Child>
</div>
</template>
<style lang="scss" scoped>
.child-title { color: pink; }
</style>
<template>
<div class="child-root-element">
<slot>default-slot</slot>
</div>
</template>
编译后的 dom 结构和 css 样式
<style>
.child-title[data-v-parent] { color: pink; }
</style>
<div data-v-parent class="parent">
<div data-v-child data-v-parent class="child-root-element">
<h2 data-v-parent data-v-child class="child-title">
<span data-v-parent data-v-child>this is a child title</span>
</h2>
</div>
</div>
<style>
.child-title[data-v-parent] { color: pink; }
</style>
<div data-v-parent class="parent">
<div data-v-child data-v-parent class="child-root-element">
<h2 data-v-parent data-v-child-s class="child-title">
<span data-v-parent data-v-child-s>this is a child title</span>
</h2>
</div>
</div>
总结
由此可见,无论 Vue2 还是 Vue3,父组件传递给子组件的插槽元素,其实际 DOM 都是由父组件生成并注入的, 因此这些插槽元素都会被附加上父组件的作用域标识符属性(如 data-v-parent
),所以父组件中的 scoped 样式可以直接作用到传递给子组件的插槽元素上。
子组件 scoped 样式不一定都能直接作用于父组件传入的插槽元素上
示例代码
<template>
<div class="parent">
<Child>
<h2 class="child-title">
<span>this is an child title</span>
</h2>
</Child>
</div>
</template>
<template>
<div class="child-root-element">
<slot>default-slot</slot>
</div>
</template>
<style lang="scss" scoped>
.child-title { color: pink; }
</style>
编译后的 dom 结构和 css 样式
<style>
.child-title[data-v-child] { color: pink; }
</style>
<div data-v-parent class="parent">
<div data-v-child data-v-parent class="child-root-element">
<h2 data-v-parent data-v-child class="child-title">
<span data-v-parent data-v-child>this is a child title</span>
</h2>
</div>
</div>
<style>
.child-title[data-v-child] { color: pink; }
</style>
<div data-v-parent class="parent">
<div data-v-child data-v-parent class="child-root-element">
<h2 data-v-parent data-v-child-s class="child-title">
<span data-v-parent data-v-child-s>this is a child title</span>
</h2>
</div>
</div>
总结
父组件传递给子组件插槽中的每个元素,都会绑定父组件的作用域标识符属性(如 data-v-parent
)。
除此之外,还有一些差异点:
在 Vue2 中,会给每个传递的插槽元素,额外绑定上子组件的作用域标识符属性(如
data-v-child
),因此子组件 scoped 中的样式能够作用到父组件传递过来的插槽元素上。
在 Vue3 中,会给每个传递的插槽元素,额外绑定上带有
-s
后缀的子组件作用域标识符属性(如data-v-child-s
),可以称之为插槽元素标识符属性,这个 -s 后缀代表该元素是由父组件传递过来的插槽元素(slot), 用于辅助作用域判断与样式编译。因此子组件 scoped 中的样式不能够作用到父组件传递过来的插槽元素上。
插槽选择器 :slotted 伪类(Vue3 新增)
引言
前面提过:在 Vue2 中,子组件 scoped 中的样式能作用于父组件传递过来的插槽元素上,而 Vue3 中不支持。
如果在 Vue3 中,也需要子组件 scoped 中的样式作用于父组件传递过来的插槽元素上,那么有没有办法呢?
Vue3 中提供一个插槽选择器::slotted()
,使用 :slotted 伪类以明确地将插槽内容作为选择器的目标。
示例代码
<template>
<Child>
<h2 class="child-title">this is an child title</h2>
</Child>
</template>
<template>
<div class="child">
<slot>default-slot</slot>
<slot name="slot2">
<span class="slot2-default">slot2 default content</span>
</slot>
</div>
</template>
<style scoped lang="scss">
// Vue3中,默认是无法作用
.child-title {
color: pink;
}
// 可以作用
:slotted(.child-title) {
color: pink;
}
// 可以作用
.slot2-default {
color: pink;
}
// 为什么 .slot2-default 不用 :slotted(.slot2-default) 也可以?
// 因为 slot2-default 是 slot 的默认内容,可以在子组件中匹配到,
// 并不属于外部父组件传入的动态内容,所以不需要使用 :slotted。
// 但是需要注意选择器 .slot2-default 只能加在默认内容中,加在 slot 标签上无效,
// slot 本身属于插槽占位元素,并不会创建实际的 dom 元素。
</style>
编译后的 dom 结构和 css 样式
<style>
/* 插槽选择器 :slotted 本质就是额外加上插槽元素标识符属性 */
.child-title[data-v-child-s] { color: pink; }
</style>
<div data-v-parent class="parent">
<div data-v-child data-v-parent class="child-root-element">
<h2 data-v-parent data-v-child-s class="child-title">
<span data-v-parent data-v-child-s>this is a child title</span>
</h2>
</div>
</div>
🔔 提示
插槽默认填充内容,不属于父组件传入的插槽内容,可以被组件中 scoped 样式作用,不需要使用 :slotted 伪类。
归纳总结
🔔 提示
在 Vue2 和 Vue3 中,父组件传递给子组件插槽的每个元素,编译后都会携带上父组件作用域标识属性符。
在 Vue2 中,子组件 scoped 样式能作用于父组件传递过来的插槽元素,而 Vue3 中则不能作用。 原因是 Vue2 中,父组件传递给子组件插槽的元素,编译后会携带子组件作用域标识符属性(如:data-v-child),而 Vue3 中携带的是一个插槽元素标识符属性(如 data-v-child-s)。
在 Vue3 中,新增插槽选择器
:slotted()
伪类,用于解决 Vue3 中的子组件 scoped 样式不能作用于父组件传递过来的插槽元素,原理就是额外绑定上插槽元素标识符属性(如 data-v-child-s)。在 Vue2 和 Vue3 中,子组件插槽的默认填充内容,都是不属于父组件传入的插槽内容,都是可以被子组件 scoped 样式作用,因此编译后,插槽默认填充内容不会携带父组件作用域标识符属性, 会携带子组件作用域标识符属性(如 data-v-child),Vue3 中还会额外带上
-s
后缀的插槽元素标识符属性(如 data-v-child-s)。
深度作用选择器的用法与演进
引言
如前所述,scoped 样式只会作用于当前组件的 DOM 元素和子组件的根节点,不会渗透到子组件中。
但有时我们想对子组件中的元素或第三方库组件的元素进行样式控制。为了穿透这种作用域限制,可以使用深度选择器,Vue 提供了几种“深度作用选择器”写法。
支持性测试对比
以下是对 Vue 2 / 3 搭配不同构建工具(vue-cli、vite)下各类深度选择器的兼容测试,vue-cli 本身基于 webpack 做的上层封装,所以没有专门测试 webpack 手动配置的情况。 本文描述的现象所基于的测试环境:
测试环境 | vue 版本 | 构建工具 | CSS 预处理器相关依赖 |
---|---|---|---|
Env01 | vue(2.6.10) | vue cli(3.12.1) | node-sass(4.14.1)、sass-loader(8.0.2) |
Env02 | vue(2.6.12) | vue cli(4.4.6) | sass(1.32.13)、sass-loader(10.1.1) |
Env03 | vue(3.5.13) | vite(6.1.0) | sass(1.85.0) |
⚠️ 注意
错误暴露时机不同:webpack 的编译触发时机是启动阶段统一完成构建,所以编译阶段一次性报全项目错误,而 vite 的构建方式是按需即时编译,只有访问对应资源时,才会构建相应模块并抛出编译错误。
深度作用选择器 | Env01 + sass(无/有) | Env02 + sass(无/有) | Env03 + sass(无/有) |
---|---|---|---|
>>> | ✅ / ❌ | ✅ / ❌ | ✅ / ❌ |
/deep/ | ✅ / ✅ | ✅ / ❌ | ✅ / ❌ |
::v-deep | ✅ / ✅ | ✅ / ✅ | ✅ / ✅ |
::v-deep() | ❌ / ❌ | ❌ / ❌ | ✅ / ✅ |
:deep() | ❌ / ❌ | ❌ / ❌ | ✅ / ✅ |
接下来的小节是实际测试的结果。
操作符 >>>(早期写法)
引言
>>>
操作符 是 Vue Loader 中早期支持的深度选择器写法,能穿透 scoped 限制。
但它对 Sass、Less 等预处理器支持不友好,这类预处理器无法正确解析 >>>
,会当成普通选择器,导致无法转换生效。
✅不搭配 sass 之类的预处理器
在不结合使用 sass 之类的 CSS 预处理器的前提下,使用
>>>
操作符,Vue2 和 Vue3 都是能正确解析转换的。
示例代码
<template>
<div class="parent">
<Child />
</div>
</template>
<style scoped>
.parent {
font-size: 16px;
}
>>> .child-title {
color: pink;
}
</style>
<template>
<div class="child">
<h2 class="child-title">child title</h2>
</div>
</template>
编译后的 dom 结构和 css 样式
<style>
.parent[data-v-parent] {
font-size: 16px;
}
[data-v-parent] .child-title {
color: pink;
}
</style>
<div data-v-parent class="parent">
<div data-v-parent class="child">
<h2 class="child-title">child title</h2>
</div>
</div>
❌搭配 sass 之类的预处理器
sass 之类的 CSS 预处理器无法正确解析
>>>
操作符。
官方资料:Vue Loader 14 - 深度作用选择器、Vue Loader 15 - 深度作用选择器
示例代码
<template>
<div class="parent">
<Child />
</div>
</template>
<style scoped lang="scss">
.parent {
font-size: 16px;
>>> .child-title {
color: pink;
}
}
</style>
<template>
<div class="child">
<h2 class="child-title">child title</h2>
</div>
</template>
编译后的 dom 结构和 css 样式
<style>
.parent[data-v-parent] {
font-size: 16px;
}
.parent > > > .child-title[data-v-parent] {
color: pink;
}
</style>
<div data-v-parent class="parent">
<div data-v-parent class="child">
<h2 class="child-title">child title</h2>
</div>
</div>
<style>
.parent[data-v-parent] {
font-size: 16px;
}
</style>
<div data-v-parent class="parent">
<div data-v-parent class="child">
<h2 class="child-title">child title</h2>
</div>
</div>
测试环境 | 测试结果 | 测试结果说明 |
---|---|---|
Env01、Env02 | ❌ | 编译不报错,但不会正确解析 >>> 操作符。 |
Env03 | ❌ | 编译输出错误提示:视为无效 CSS,从生成的 CSS 中移除掉。 |
操作符 /deep/
/deep/
和::v-deep
都是>>>
的别名,同样能穿透 scoped 限制。相较>>>
,对预处理器支持稍好,能被 Vue Loader 正确识别转换。Vue-loader15官方文档里也明确指出,当>>>
无法正常解析时,可以用 /deep/ 或 ::v-deep 替代。
✅不搭配 sass 之类的预处理器
在不结合使用 sass 之类的 CSS 预处理器的前提下,使用
/deep/
操作符,Vue2 和 Vue3 都是能正确解析转换的。
示例代码
<template>
<div class="parent">
<Child />
</div>
</template>
<style scoped>
.parent {
font-size: 16px;
}
/deep/ .child-title {
color: pink;
}
</style>
<template>
<div class="child">
<h2 class="child-title">child title</h2>
</div>
</template>
编译后的 dom 结构和 css 样式
<style>
.parent[data-v-parent] {
font-size: 16px;
}
[data-v-parent] .child-title {
color: pink;
}
</style>
<div data-v-parent class="parent">
<div data-v-parent class="child">
<h2 class="child-title">child title</h2>
</div>
</div>
⚠搭配 sass 之类的预处理器
示例代码
<template>
<div class="parent">
<Child />
</div>
</template>
<style scoped lang="scss">
.parent {
font-size: 16px;
/deep/ .child-title {
color: pink;
}
}
</style>
<template>
<div class="child">
<h2 class="child-title">child title</h2>
</div>
</template>
编译后的 dom 结构和 css 样式
<style>
.parent[data-v-parent] {
font-size: 16px;
}
.parent[data-v-parent] .child-title {
color: pink;
}
</style>
<div data-v-parent class="parent">
<div data-v-parent class="child">
<h2 class="child-title">child title</h2>
</div>
</div>
# 编译失败:
Syntax Error: SassError: expected selector.
╷
│ /deep/ .child-title{
│ ^
╵
测试环境 | 测试结果 | 测试结果说明 |
---|---|---|
Env01 | ✅ | 可以正确解析转换。 |
Env02、Env03 | ❌ | 编译失败:Syntax Error: SassError: expected selector. |
操作符 ::v-deep
::v-deep
和/deep/
都是>>>
的别名,同样能穿透 scoped 限制。相较>>>
,对预处理器支持稍好,能被 Vue Loader 正确识别转换。Vue-loader15官方文档里也明确指出,当>>>
无法正常解析时,可以用 /deep/ 或 ::v-deep 替代。
⚠️ 注意
Vue3 中 ::v-deep
仍然支持,但不带参数的用法已被弃用,例如:
/* 已弃用,会有编译警告 */
::v-deep .child-class {
/* 样式 */
}
推荐写法是带参数的形式:
/* 推荐写法 */
::v-deep(.child-class) {
/* 样式 */
}
✅不搭配 sass 之类的预处理器
示例代码
<template>
<div class="parent">
<Child />
</div>
</template>
<style scoped>
.parent {
font-size: 16px;
}
::v-deep .child-title {
color: pink;
}
</style>
<template>
<div class="child">
<h2 class="child-title">child title</h2>
</div>
</template>
编译后的 dom 结构和 css 样式
<style>
.parent[data-v-parent] {
font-size: 16px;
}
[data-v-parent] .child-title {
color: pink;
}
</style>
<div data-v-parent class="parent">
<div data-v-parent class="child">
<h2 class="child-title">child title</h2>
</div>
</div>
✅搭配 sass 之类的预处理器
示例代码
<template>
<div class="parent">
<Child />
</div>
</template>
<style scoped lang="scss">
.parent {
font-size: 16px;
::v-deep .child-title {
color: pink;
}
}
</style>
<template>
<div class="child">
<h2 class="child-title">child title</h2>
</div>
</template>
编译后的 dom 结构和 css 样式
<style>
.parent[data-v-parent] {
font-size: 16px;
}
.parent[data-v-parent] .child-title {
color: pink;
}
</style>
<div data-v-parent class="parent">
<div data-v-parent class="child">
<h2 class="child-title">child title</h2>
</div>
</div>
带参数形式 ::v-deep()
Vue3 中新增的 ::v-deep 带参数形式。
⚠不搭配 sass 之类的预处理器
示例代码
<template>
<div class="parent">
<Child />
</div>
</template>
<style scoped>
.parent {
font-size: 16px;
}
::v-deep(.child-title) {
color: pink;
}
</style>
<template>
<div class="child">
<h2 class="child-title">child title</h2>
</div>
</template>
编译后的 dom 结构和 css 样式
<style>
.parent[data-v-parent] {
font-size: 16px;
}
[data-v-parent](.child-title) {
color: pink;
}
</style>
<div data-v-parent class="parent">
<div data-v-parent class="child">
<h2 class="child-title">child title</h2>
</div>
</div>
<style>
.parent[data-v-parent] {
font-size: 16px;
}
[data-v-parent] .child-title {
color: pink;
}
</style>
<div data-v-parent class="parent">
<div data-v-parent class="child">
<h2 class="child-title">child title</h2>
</div>
</div>
测试环境 | 测试结果 | 测试结果说明 |
---|---|---|
Env01、Env02 | ❌ | 无法正确解析转换。 |
Env03 | ✅ | 可以正确解析转换。 |
⚠搭配 sass 之类的预处理器
示例代码
<template>
<div class="parent">
<Child />
</div>
</template>
<style scoped lang="scss">
.parent {
font-size: 16px;
::v-deep(.child-title) {
color: pink;
}
}
</style>
<template>
<div class="child">
<h2 class="child-title">child title</h2>
</div>
</template>
编译后的 dom 结构和 css 样式
<style>
.parent[data-v-parent] {
font-size: 16px;
}
.parent[data-v-parent] (.child-title) {
color: pink;
}
</style>
<div data-v-parent class="parent">
<div data-v-parent class="child">
<h2 class="child-title">child title</h2>
</div>
</div>
<style>
.parent[data-v-parent] {
font-size: 16px;
}
.parent[data-v-parent] .child-title {
color: pink;
}
</style>
<div data-v-parent class="parent">
<div data-v-parent class="child">
<h2 class="child-title">child title</h2>
</div>
</div>
测试环境 | 测试结果 | 测试结果说明 |
---|---|---|
Env01、Env02 | ❌ | 无法正确解析转换。 |
Env03 | ✅ | 可以正确解析转换。 |
:deep(Vue3)
Vue3 官方文档中推荐的唯一方式,只在 Vue3 中支持。
/* 不带参形式 */
:deep .child-class {}
/* 带参数形式 */
:deep(.child-class) {}
写法语义清晰,更容易被各种工具链解析,避免了老写法的兼容问题。
⚠不搭配 sass 之类的预处理器
示例代码
<template>
<div class="parent">
<Child />
</div>
</template>
<style scoped>
.parent {
font-size: 16px;
}
:deep .child-title {
color: pink;
}
</style>
<template>
<div class="child">
<h2 class="child-title">child title</h2>
</div>
</template>
编译后的 dom 结构和 css 样式
<style>
.parent[data-v-parent] {
font-size: 16px;
}
:deep .child-title[data-v-parent] {
color: pink;
}
</style>
<div data-v-parent class="parent">
<div data-v-parent class="child">
<h2 class="child-title">child title</h2>
</div>
</div>
<style>
.parent[data-v-parent] {
font-size: 16px;
}
[data-v-parent] .child-title {
color: pink;
}
</style>
<div data-v-parent class="parent">
<div data-v-parent class="child">
<h2 class="child-title">child title</h2>
</div>
</div>
测试环境 | 测试结果 | 测试结果说明 |
---|---|---|
Env01、Env02 | ❌ | 无法正确解析转换。 |
Env03 | ✅ | 可以正确解析转换。 |
⚠搭配 sass 之类的预处理器
示例代码
<template>
<div class="parent">
<Child />
</div>
</template>
<style scoped lang="scss">
.parent {
font-size: 16px;
:deep .child-title {
color: pink;
}
}
</style>
<template>
<div class="child">
<h2 class="child-title">child title</h2>
</div>
</template>
编译后的 dom 结构和 css 样式
<style>
.parent[data-v-parent] {
font-size: 16px;
:deep .child-title {
color: pink;
}
}
</style>
<div data-v-parent class="parent">
<div data-v-parent class="child">
<h2 class="child-title">child title</h2>
</div>
</div>
<style>
.parent[data-v-parent] {
font-size: 16px;
}
.parent[data-v-parent] .child-title {
color: pink;
}
</style>
<div data-v-parent class="parent">
<div data-v-parent class="child">
<h2 class="child-title">child title</h2>
</div>
</div>
测试环境 | 测试结果 | 测试结果说明 |
---|---|---|
Env01、Env02 | ❌ | 无法正确解析转换。 |
Env03 | ✅ | 可以正确解析转换。 |