一个简单的组件
<template>
<div class="test">
<div class="title" >
我是标题t
</div>
</div>
</template>
此时正常生效颜色和字体大小
此时会编译为
.test .title[data-v-xxx]
.test{
.title{
font-size: 20px;
color: red;
}
}
但是如果加上:deep(),则不会生效,我们知道,此时按理说.title的[data-v-xxx]会被去掉,应该会被编译为
.test[data-v-xxxx] .title
.test{
:deep(.title){
font-size: 20px;
color: red;
}
}
但此时在浏览器style调试栏里没有任何对应的.title选择器
element.style {
}
用户代理样式表
div {
display: block;
unicode-bidi: isolate;
}
如果去掉外围的.test选择器,则又会重新生效
:deep(.title){
font-size: 20px;
color: red;
}
此时在浏览器style调试页则会显示
[data-v-xxx] .title {
font-size: 20px;
color: red;
}
表明当前其实选择器被编译为了[data-v-xxxx] .title
查询了AI得知疑似是因为vue内部对带有父元素选择器的 deep()进行了过滤,不参与编译结果,所以最终没有输出到浏览器style调试页上 但是在AI给出的来源文档里并没有看到对应的内容?疑似AI编造资料,特此记录
又重新问了一遍ai,ai又换说法了,把这种现象解释为vue处理css的时候将带有父元素的deep()处理为了.test [data-v-123] .title与原dom结构不同,所以不生效,在让ai给出参考的源文档中...
最后确认了,问题代码在经过vite编译后的结果显示
<template>
<div class="test">
<div class="title">测试标题</div>
</div>
</template>
<style scoped>
.test {
:deep(.title) {
font-size: 20px;
color: red;
}
}
</style>
在最后输出的结果是.test [data-v-c64d93fd] .title,符合与DOM结构不同,所以没生效的原因
.test [data-v-c64d93fd] .title {
font-size: 20px;
color: red;
}
而之前的其他情况对应的是
:deep(.title) {
font-size: 20px;
color: red;
}
[data-v-16bfa729] .title {}符合原行为
添加一个祖先元素
<div class="tabbar">
<div class="test">
<div class="title">测试标题</div>
</div>
</div>
.tabbar {
.title {
}
}
最后的结果是.tabbar [data-v-9ecd31d2] .title 由于祖先元素和title元素之间隔了一个带[data-v-xxx]的父元素,所以依旧能选中title
最后是最正确的写法
.test {
.title {
font-size: 20px;
color: red;
}
}
.test .title[data-v-bcdf58ac] {}
符合默认行为
如果是形如这种结构
<template>
<div class="tabbar">
<div class="test">
<div class="title">测试标题</div>
</div>
</div>
</template>
<style scoped>
.tabbar {
.test {
:deep(.title) {
font-size: 20px;
color: red;
}
}
}
</style>
编译后结果为
.tabbar .test [data-v-81722b88] .title
由此终于能得到结论,如果闲的没事干,在自己的组件里使用了:deep()来样式穿透,vue会将原本的.title[data-v-bcdf58ac]转换成.[data-v-bcdf58ac] .title,如果.title前面有任何其他类,则会转换成.xxxx [data-v-bcdf58ac] .title,所以就会出现有时候能选中,有时候选不中
至于正常的使用,形如(子组件带scoped)
// 父组件
<div class="tabbar">
<div class="test">
我是父组件
<Cpn class="son" />
</div>
</div>
//子组件
<div class="cpn">
我是组件外层根元素
<div class="cpn-inner">
组件内部第二层
</div>
</div>
如果在父组件内直接对子组件的cpn-inner进行选中但不使用:deep()
.tabbar {
.test {
color: greenyellow;
font-size: 20px;
.cpn-inner {
color: red;
background-color: #666;
}
}
}
则最终的编译结果里,此时cpn的[data-v-xxx]是父组件的xxx,无法选中子组件
.tabbar .test .cpn-inner[data-v-110961b9] {
color: red;
background-color: #666;
}
在父组件内添加了:deep()之后
:deep(.cpn-inner) {
color: red;
background-color: #666;
}
最终的编译结果里,依旧是子组件的[data-v-xxx]被插入到之前的元素中,此时的[data-v-2eaeac9f]为外部父组件的[data-v],由于这个[data-v]其实也会被添加到子组件的根节点中,所以通过css子代选择器,就能被选中子组件内的模块
.tabbar .test [data-v-2eaeac9f] .cpn-inner {
color: red;
background-color: #666;
}
接下来再看看如果子组件不带scoped的情况
DOM结构则会变成引入第三方组件库的形式:仅有外层根节点会设置父组件的[data-v],内部模块不会添加[data-v]
<div data-v-5725aaa2 class="tabbar">
<div data-v-5725aaa2 class="test">
我是父组件
<div data-v-5725aaa2 class="cpn son">
我是组件外层根元素
<div class="cpn-inner">组件内部第二层</div>
</div>
</div>
</div>
最后css的编译结果则是与之前相同的结构,[data-v-5725aaa2]为父组件[data-v]
.tabbar .test [data-v-5725aaa2] .cpn-inner {
color: red;
background-color: #666;
}
就能正确更改子组件模块内的样式了