🎯 Vue scoped 样式穿透机制
⚠️ 本文针对 Vue 3。
🧩 一、scoped 样式到底怎么工作的?
当你在 Vue 文件中写下:
<style scoped>
.box {
color: red;
}
</style>
Vue 会在编译时自动把这个 CSS 转换成带作用域的选择器,比如:
.box[data-v-aaa111] {
color: red;
}
同时它也会把你的 HTML 编译成:
<div class="box" data-v-aaa111></div>
这就实现了样式只在当前组件生效的隔离效果。
❓ 二、都 scoped 了,父组件为啥还能影响子组件?
场景还原:
<!-- 父组件 -->
<template>
<ChildBox />
</template>
<style scoped>
.box {
border: 1px solid red;
}
</style>
<!-- 子组件 ChildBox.vue -->
<template>
<div class="box">子组件 box</div>
</template>
<style scoped>
.box {
background: lightblue;
}
</style>
你以为 .box 样式互不影响,结果页面上 .box 同时有 红色边框和蓝色背景?
🤯 原因揭秘:
Vue 的 scoped 是通过给元素加一个特殊属性实现的,比如:
<div class="box" data-v-child data-v-parent></div>
当一个组件渲染在父组件中时,最终生成的 DOM 是带有两个作用域属性的,比如:
- 父组件作用域:
data-v-parent - 子组件作用域:
data-v-child
这样,父组件写的 .box[data-v-parent] 就会匹配到子组件里的 div.box,导致样式“穿透”。
✅ 三、避免样式冲突的最佳实践
- 避免组件内使用通用 class 名称(如
.box,.wrapper) - 给组件 class 加命名空间
<!-- ❌ 不推荐 -->
<div class="box"></div>
<!-- ✅ 推荐 -->
<div class="my-component-box"></div>