二次元绘画创作
56.21M · 2026-02-04
在 Vue 开发中,我们既希望组件的样式能够“自成一体”,不干扰外部环境,又常常需要修改第三方组件库的内部样式。这两者之间的矛盾,正是通过 scoped 属性与“样式穿透”技术来解决的。本文将带你深入理解其背后的原理与最佳实践。
在 <style> 标签上添加 scoped 属性,可以使该组件内的 CSS 样式只作用于当前组件,不会污染全局或其他组件。
当你开启 scoped 后,Vue 编译器会做两件事:
data-v-7ba5bd90。示例代码:
<template>
<div class="container">
<h2 class="title">欢迎来到掘金</h2>
</div>
</template>
<style scoped>
/* 实际编译结果类似:.title[data-v-7ba5bd90] */
.title {
color: #42b983;
}
</style>
当我们在组件中使用第三方 UI 库(如 Element Plus)时,由于 scoped 的存在,我们无法直接在组件中通过普通的类名修改 UI 库内部深层的 DOM 样式。这时,就需要使用“样式穿透”。
:deep()在 Vue 3 中,推荐使用组合式 API 风格的深度选择器。它兼容普通的 CSS 以及所有的预处理器(Sass, Less, Scss)。
示例:
<script setup lang="ts">
// 引入第三方组件
import { ElButton } from 'element-plus'
</script>
<template>
<div class="my-wrapper">
<el-button class="custom-btn">自定义按钮</el-button>
</div>
</template>
<style scoped lang="scss">
.my-wrapper {
// 使用 :deep() 穿透 scoped 限制,修改 Element Plus 内部样式
:deep(.el-button) {
border-radius: 20px;
span {
color: red;
}
}
}
</style>
为了完整性,也回顾一下 Vue 2 中的实现:
>>> 操作符。/deep/ 或 ::v-deep。| 环境 | 推荐语法 | 适用场景 |
|---|---|---|
| Vue 3 | :deep(.className) | 兼容所有 CSS 预处理器,Vue 3 官方标准 |
| Vue 2 | /deep/ .className | 主要用于 Less/Sass 环境 |
| Vue 2 (原生) | >>> .className | 仅限于原生 CSS 环境 |
选择器的效率:样式穿透虽然强大,但尽量在特定的父级类名下使用(如示例中的 .my-wrapper),避免在全局范围内进行穿透,防止意料之外的样式污染。
动态类名:如果类名是通过 :class 动态绑定的,确保穿透的目标类名是稳定的,否则可能导致样式失效。
全局样式:如果你需要修改的是类似 el-message 这种挂载在 body 上的全局组件样式,scoped 里的 :deep() 是无效的。此时应该在 App.vue 或全局样式文件中编写非 scoped 的 CSS。