vue 3 中必须用 :deep() 替代 /deep/ 和 ::v-deep,因后者非标准语法、已被弃用且易被预处理器误解析;:deep() 需配合外层选择器使用,括号内仅支持简单选择器,错误写法会导致穿透失效或全局污染。

Vue 3 项目中继续用 /deep/ 或 ::v-deep 会触发编译警告,且未来构建可能直接报错;必须改用 :deep(),否则样式穿透逻辑不可靠。
为什么 /deep/ 和 ::v-deep 被弃用了
它们不是标准 CSS 语法,而是 Vue 2 时代的临时方案:前者源自已被废弃的 CSS 提案,后者是为兼容预处理器做的别名封装。Vue 3 团队明确将其标记为 deprecated,并在 @vue/compiler-sfc 中强制校验——只要检测到 ::v-deep .xxx 这类写法,就会抛出 ::v-deep usage as a combinator has been deprecated. Use :deep() instead.。
更关键的是,这些旧写法在 Sass/Less 中容易被预处理器误解析(比如把 /deep/ 当作除法运算),而 :deep() 是标准伪类函数形式,和 CSS 原生语法对齐,构建工具链也更稳定。
:deep() 的正确写法和常见错误
它必须配合外层选择器使用,不能单独出现;括号内只接受简单选择器(类名、标签名、属性选择器),不支持空格分隔的后代或子代关系。
- ✅ 正确:
:deep(.el-input__inner)、&:deep([type="text"]) - ❌ 错误:
::v-deep .el-input__inner(已弃用)、:deep(.el-input .el-input__inner)(复合选择器不生效) - ⚠️ 危险:
:deep(div)没有外层锚点 → 会全局匹配所有div,破坏 scoped 初衷
迁移时最容易忽略的三个细节
实际改写时,光替换语法远远不够:
- 检查第三方组件最终渲染的 class 名——有些 UI 库用
v-bind:class动态拼接,inspect 元素才能确认真实类名,比如el-button--primary可能带 hash 后缀 - 如果目标元素有内联样式(
style="color: #999"),:deep()无法覆盖,得加!important(但应先排查是否 JS 动态设置了 style) - 在
<style lang="scss" scoped></style>中,:deep()必须写在嵌套规则内部,比如.my-form { &:deep(.el-input) { width: 100%; } },不能平级写
遇到老项目混用 Vue 2/Vue 3 组件怎么办
没有银弹,只能分场景处理:
- 纯 Vue 3 项目:统一删掉所有
/deep/、::v-deep、>>>,全部替换成:deep() - Vue 2 + Vue 3 混合(如微前端):Vue 2 子应用仍可用
::v-deep,但父应用(Vue 3)调用其组件时,需用:deep()穿透到该子应用根节点下——因为作用域哈希只在当前编译上下文生成,跨框架不传递 - 构建报错但暂时无法升级:可在
vue.config.js中临时关闭警告(不推荐),例如配置css: { loaderOptions: { sass: { additionalData: '' } } }并手动 suppress,但只是掩耳盗铃
真正麻烦的从来不是语法替换,而是那些没 inspect 就瞎猜类名、没确认作用域锚点就全局穿透、或者以为加了 :deep() 就能 override 内联样式的操作——这些才是线上样式失效的真正源头。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











