Vue scoped 样式不生效的一个坑:CSS 选择器与 class 合并机制

📅 发布时间:2026/7/5 16:16:33 👁️ 浏览次数:
Vue scoped 样式不生效的一个坑:CSS 选择器与 class 合并机制
文章目录Vue scoped 样式不生效的一个坑CSS 选择器与 class 合并机制1.相关知识1.1 后代选择器 vs 同元素多 class 选择器1.2 Vue class 合并机制1.3 scoped :deep 穿透原理1.4 小结空格 vs 无空格2. demo实战Vue scoped 样式不生效的一个坑CSS 选择器与 class 合并机制1.相关知识1.1 后代选择器 vs 同元素多 class 选择器后代选择器.a.b意思选中 a 里面的 b结构如下divclassadivclassb/div/div同元素多 class 选择器.a.b选中同时具有 a 和 b 的元素结构如下divclassa b/div一个空格修改样式的含义就改变了1.2 Vue class 合并机制Vue 会把父组件传入的 class 合并到子组件根元素代码例子如下父组件ChunkUploadTriggerclassupload-area/子组件divclasschunk-upload-trigger最终DOMdivclasschunk-upload-trigger upload-area1.3 scoped :deep 穿透原理Vue scoped CSS 穿透当写style scoped.box{color:red;}/styleVue 编译后会变成类似divclassboxdata-v-123abcCSS也会变成.box[data-v-123abc]{color:red;}CSS 只会影响当前组件。举例来说子组件 Child.vuetemplatedivclasschild-box子组件内容/div/templatestyle scoped.child-box{border:2px solid gray;padding:20px;}/style父组件 Parent.vuetemplateChild//templatescript setupimportChildfrom./Child.vue/scriptstyle scoped.child-box{border-color:red;}/style样式不会生效原因如下编译后 DOM 变成divclasschild-boxdata-v-child/div父组件 CSS.child-box[data-v-parent]但是 DOM 是data-v-child 不是 data-v-parent 所以匹配不到正确写法style scoped:deep(.child-box){border-color:red;}/style// 忽略 scoped 限制// 直接选中 child-box1.4 小结空格 vs 无空格来一个例子.upload-area:deep(.chunk-upload-trigger)//这在 CSS 里的意思是upload-area 里面的 chunk-upload-trigger也就是要求 Domdivclassupload-areadivclasschunk-upload-trigger/div/div但是如果 Dom 结构是下面这样的divclasschunk-upload-trigger upload-area/div意思是同时拥有两个 class 的元素:deep(.chunk-upload-trigger.upload-area)没有空格空格 父子关系没空格 同一个元素2. demo实战子组件templatedivclasschild-box子组件divclasscontent内容区域/div/div/templatescriptsetuplangts/scriptstylescoped.child-box{border:2px solid #ccc;padding:20px;}.content{margin-top:10px;padding:10px;background:#f5f5f5;}/style子组件DOM实际是divclasschild-box子组件divclasscontent/div/div父组件 Parent.vuetemplatedivclasswrapperh3案例1class 透传/h3Childclassa b//div/templatescriptsetupimportChildfrom./Child.vue/scriptstylescoped/styleVue 会把 class 合并到子组件根节点。此时真实的DOMdivclasschild-box a b子组件divclasscontent/div/div练习1.a.b同一个元素在 Parent.vue 写:deep(.a.b){border:3px solid red;}练习2.a .b后代选择器修改 Parent.vuetemplatedivclasswrapperdivclassaChildclassb//div/div/template真实 DOMdivclassadivclasschild-box b/div/div推荐写法.a:deep(.b){border:3px solid blue;}含义当前组件中的.a ↓ 穿透到子组件中的.b Vue 编译后的效果类似.a[data-v-xxxx].b.a 仍然受 scoped 限制.b 允许 穿透到子组件这种写法同样可以生效但作用范围更大。:deep(.a.b){border:3px solid red;}.a 和.b 都脱离了 scoped 约束。因此只要在当前组件 DOM 树内部出现 .a .b 结构就可能匹配到。这会让样式的 影响范围变大也更难控制。