Vue 中的 deep 和 v-deep 有什么区别?什么时候用哪个?

“你用 Element Plus 写了个按钮,想改下 hover 颜色,结果死活不生效!最后查了半天,发现得加个 :deep 才行”

实则,这是 Vue 中一个超级常见的坑: 样式作用域冲突 。那为什么用 UI 库时,加上 :deep ::v-deep >>> 后,样式就能生效呢?

它们是什么?有什么区别?什么时候该用哪个?

一、先说背景

我们在 Vue 单文件组件( .vue 文件)里写样式时,一般会加上 scoped 属性:

 




.el-button {
background: red;
}

加了 scoped 后,Vue 会自动给这个组件里的所有元素加上一个唯一的属性(列如 data-v-123456 ),然后把 CSS 选择器也加上这个属性,变成:

 .el-button[data-v-123456] {
background: red;
}

这样做的好处是: 样式只作用于当前组件,不会污染全局 。、

但问题来了: Element Plus 的 组件内部结构,是在它自己的组件里定义的 。也就是说,你写的 .el-button 元素,实则是 Element Plus 渲染出来的子组件,它身上 没有 你当前组件的 data-v-xxx 属性!

所以你的样式根本匹配不到它,自然就失效了。

二、那怎么办?

为了解决这个问题,Vue 提供了样式穿透(style penetration)的语法,让你能穿透当前组件的作用域,去影响子组件内部的元素。

Vue 社区出现过三种写法:

写法

适用版本

状态

>>>

Vue 2(某些预处理器支持)

已废弃/不推荐
::v-deep

Vue 2 + Vue 3(兼容写法)

过渡方案
:deep

Vue 3.0+(推荐)

官方推荐

下面我们一个个拆解。

1. >>> :曾经的快捷方式,但问题许多

早期 Vue2 时代,许多人用:

 
.parent >>> .child {
color: blue;
}

它的意思是:从 .parent 开始,穿透到所有后代中的 .child

但问题在于:

  • Sass/Less 等预处理器不认 >>> ,会报错。

  • • 不是标准 CSS 语法。

  • • Vue3 已经明确不再支持。

所以目前基本可以忘掉它了。

2. ::v-deep :Vue2 到 Vue3 的桥梁

为了兼容预处理器,Vue 引入了 ::v-deep

 
.parent ::v-deep(.child) {
color: blue;
}

或者更常见的写法:

 .parent {
::v-deep(.child) {
color: blue;
}
}

它在 Vue2 和 Vue3 中都能用,算是一个安全的过渡方案。

但注意: 在 Vue3 中,官方文档已经明确提议使用 :deep 替代它

3. :deep :Vue3 的标准答案

Vue3 引入了更简洁、更符合 CSS 规范的伪类函数写法:

 
:deep(.el-button) {
background: red !important;
}

或者配合父级选择器:

 
.my-wrapper :deep(.el-input__inner) {
border-radius: 10px;
}

优点

  • • 语法清晰,像原生 CSS。

  • • 支持所有预处理器(Sass/Less/Stylus)。

:deep 本质上是一个编译时转换,Vue 在构建时会把它展开成带 data-v-xxx 的复杂选择器,从而实现穿透。

三、怎么正确修改 Element Plus 的样式?

举个真实例子:你想把 Element Plus 的输入框圆角改成 8px。

错误写法(不生效):

 
.el-input__inner {
border-radius: 8px;
}

正确写法:

 template>
divclass="my-form">
el-inputv-model="value"/>
div>
template>

stylescoped>
.my-form :deep(.el-input__inner) {
border-radius: 8px;
}
style>

为什么要加 .my-form 这个父级?

避免全局污染 !如果直接写 :deep(.el-input__inner) ,那么这个页面里 所有 Element 输入框都会被改掉。加上父级限定,就能够精准的控制范围。

© 版权声明

相关文章

暂无评论

none
暂无评论...