scoped
在 Vue 的单文件组件(.vue
文件)中,scoped
是一个用于 样式作用域隔离 的关键特性。
以下是关于 scoped
样式的深度解析:
1. 核心作用
- 样式隔离 :添加
scoped
后,组件内的 CSS 样式 仅作用于当前组件,避免污染全局样式。 - 实现原理 :Vue 在编译时会给当前组件的 DOM 元素添加唯一的
data-v-xxxxxx
属性,并通过属性选择器约束 CSS 作用域。
2. 使用方式
在 <style>
标签中添加 scoped
属性:
vue
<template>
<div class="demo">Hello Scoped</div>
</template>
<style scoped>
.demo {
color: red;
}
</style>
编译后的结果:
html
<div class="demo" data-v-f3f3eg9>Hello Scoped</div>
<style>
.demo[data-v-f3f3eg9] {
color: red;
}
</style>
3. 关键特性
作用域限制
- 仅对 当前组件的根元素及其子元素 生效。
- 无法直接覆盖子组件样式(除非子组件根元素)。
深度选择器
若需强制影响子组件内部样式,使用深度选择器:
- Vue 2 :
>>>
或/deep/
或::v-deep
- Vue 3 :统一使用
:deep()
vue
<style scoped>
/* Vue 3 写法 */
.parent :deep(.child-inner) {
color: blue;
}
/* Vue 2 兼容写法 */
.parent ::v-deep .child-inner {
color: blue;
}
</style>
全局样式穿透
若需在 scoped
样式内部定义全局样式:
vue
<style scoped>
/* 使用 :global() 包裹 */
:global(.global-class) {
font-size: 16px;
}
</style>
4. 注意事项
-
避免滥用深度选择器
过度使用
:deep()
会破坏组件封装性,推荐优先通过 Props 控制子组件样式。 -
与 CSS 预处理器配合
scoped
可与 Sass/Less/Stylus 等预处理器共存:vue<style scoped lang="scss"> .demo { &:hover { color: green; } } </style>
-
动态生成的内容
通过
v-html
插入的 HML 内容 不受scoped
样式影响(因为编译时无法处理动态内容)。 -
性能影响
scoped
样式会增加 CSS 选择器的复杂度,但在现代浏览器中性能差异可忽略不计。
5. 适用场景
场景 | 是否推荐使用 scoped |
---|---|
组件库开发 | ✅ 必须使用 |
全局基础组件 | ✅ 推荐使用 |
需要覆盖第三方组件 | ⚠️ 需配合 :deep() |
页面级布局 | ❌ 避免使用(用全局样式) |
6. 替代方案
-
CSS Modules :通过
module
特性生成局部类名(更适合复杂项目)。vue<style module> .red { color: red; } </style> <!-- 使用 --> <div :class="$style.red"></div>
-
BEM 命名规范:手动通过命名约定隔离样式(依赖团队规范)。
最佳实践
-
默认启用
scoped
除非明确需要全局样式,否则始终为组件添加
scoped
。 -
原子化 CSS 库兼容
若使用 Tailwind CSS 等工具,
scoped
可能影响工具类,需谨慎配置。 -
组件库开发
必须使用
scoped
+:deep()
的组合,确保样式隔离性。
示例:父子组件样式控制
vue
<!-- Parent.vue -->
<template>
<div class="parent">
<Child />
</div>
</template>
<style scoped>
.parent {
padding: 20px;
}
/* 强制修改子组件内部样式 */
.parent :deep(.child-inner) {
background: #f0f0f0;
}
</style>
<!-- Child.vue -->
<template>
<div class="child">
<div class="child-inner">子组件内容</div>
</div>
</template>
<style scoped>
.child-inner {
color: blue;
}
</style>