不使用 deep
要想修改三方组件样式,只能添加到 scoped 之外,弊端是污染了全局样式,后续可能出现样式冲突。
<style lang="less">
.container {
.el-button {
background: #777;
}
}
使用 /deep/ deprecated
.container1 {
/deep/ .el-button {
background: #000;
}
}
使用 >>> deprecated
.container2 >>> .el-button {
background: #222;
}
当在vue3使用/deep/
或者>>>
、::v-deep
,console面板会打印警告信息:
the >>> and /deep/ combinators have been deprecated. Use :deep() instead.
由于/deep/
或者>>>
在less或者scss中存在兼容问题,所以不推荐使用了。
使用 :deep
.container3 {
:deep(.el-button) {
background: #444;
}
}
那么问题来了,如果我按以下的方式嵌套 deep,能生效吗?
.container4 {
:deep(.el-button) {
:deep(.el-icon) {
color: #f00;
}
}
}
源码解析
/deep/ 或 >>> 会被编译为什么。编译后的代码为:
.no-deep .container1[data-v-f5dea59b] .el-button { background: #000; }
源代码片段:
if (
n.type === 'combinator' &&
(n.value === '>>>' || n.value === '/deep/')
) {
n.value = ' '
n.spaces.before = n.spaces.after = ''
warn(
`the >>> and /deep/ combinators have been deprecated. ` +
`Use :deep() instead.`,
)
return false
}
当 vue 编译样式时,先将样式解析为 AST 对象,例如 deep/ .el-button
会被解析为 Selector 对象,/deep/ .el-button
解析后生成的 Selector 包含的字段:
{ type: 'combinator', value: '/deep/' }
然后将 n.value 由 /deep/
替换为空。所以转换出来的结果,.el-button 直接变为 .container
下的子样式。
:deep 会被编译为什么?编译后的代码:
.no-deep .container3[data-v-f5dea59b] .el-button { background: #444; }
源代码片段:
// .foo :v-deep(.bar) -> .foo[xxxxxxx] .bar
let last: selectorParser.Selector['nodes'][0] = n
n.nodes[0].each(ss => {
selector.insertAfter(last, ss)
last = ss
})
// insert a space combinator before if it doesn't already have one
const prev = selector.at(selector.index(n) - 1)
if (!prev || !isSpaceCombinator(prev)) {
selector.insertAfter(
n,
selectorParser.combinator({
value: ' ',
}),
)
}
selector.removeChild(n)
还是以 .container4 :deep(.el-button)
为例,当解析到 :deep 符号式,selector 快照为
parent 为.container4 :deep(.el-button)
,当前 selector 的 type 正好为伪类标识 pseudo
,nodes 节点包含一个 .el-button
。经过递归遍历,生成的 selector 结构为 .container4 :deep(.el-button).el-button
,最后一行代码 selector.removeChild(n)
会将 :deep(.el-button)
移出,所以输出的最终样式为 .container4 .el-button
。如果样式为:deep(.el-button) { :deep(.el-icon) { color: #f00 } }
,当遍历 .el-icon 时找不到 ancestor,所以直接将 :deep(.el-icon)
作为其 icon 时找不到 ancestor, 其结果为:
.no-deep .container4[data-v-f5dea59b] .el-button :deep(.el-icon) { color: #f00; }
因此,deep 是不支持嵌套的。