为什么vue:deep、/deep/、>>>样式能穿透到子组件

举报
yd_244540595 发表于 2024/08/20 14:07:59 2024/08/20
【摘要】 作者:前端下饭菜 如果你排斥加班,但不排斥偶尔加班并给加班工资的;如果你排斥外包,但不排斥薪酬待遇还不错的大厂外包的话,可以着重考虑以下。技术大厂内推,前后端测试捞人,感兴趣来。 为什么vue:deep、/deep/、>>>样式能穿透到子组件在scoped标记的style中,只要涉及三方组件,那deep符号会经常被使用,用来修改外部组件的样式。小试牛刀不使用deep要想修改三方组件样式,只能...

作者:前端下饭菜

 

如果你排斥加班,但不排斥偶尔加班并给加班工资的;如果你排斥外包,但不排斥薪酬待遇还不错的大厂外包的话,可以着重考虑以下。

技术大厂内推,前后端测试捞人,感兴趣来。

 

为什么vue:deep、/deep/、>>>样式能穿透到子组件

在scoped标记的style中,只要涉及三方组件,那deep符号会经常被使用,用来修改外部组件的样式。

小试牛刀

不使用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是不支持嵌套的。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。