【Vue bug】:deep()失效
vue 组件中使用了 element-plus 组件
<template><el-dialog:model-value="visible":title="title":width="width + 'px'":before-close="onClose"><div class="container" :style="{height:height + 'px'}"><slot name="content"></slot></div><template #footer><div class="dialog-footer"><el-button plain type="danger" @click="onClose">取消</el-button><el-button plain type="primary" @click="onConfirm">确定</el-button></div></template></el-dialog>
</template>
<style lang="scss" scoped>
// 组件内自定义的 elementplus 的样式,
:deep(.el-dialog){border-radius: 10px!important;background-color: #535bf2;
}
使用了:deep()失效
bug 剖析
1. 组件的样式与第三方子组件样式的加载顺序
- 若第三方子组件是完全引入的,比如 element-plus:子组件在应用启动的时候,样式就加载了
- 若第三方子组件是按需导入的,那么先加载组件,然后加载子组件。
2. 样式中scoped
当在一个Vue SFC的<style>
标签中添加scoped属性时,Vue编译器会为该组件内的所有元素添加一个唯一的属性(例如data-v-f3f3eg9),同时修改样式规则以匹配这个属性。这意味着这些样式只会应用于当前组件内的元素,而不会影响全局或其他组件中的相同类名或标签。
示例:
<template><div class="example">Hello, scoped CSS!</div>
</template><style scoped>
.example {color: red;
}
</style>
编译后可能会变成类似这样:
<template><div class="example" data-v-f3f3eg9>Hello, scoped CSS!</div>
</template><style>
.example[data-v-f3f3eg9] {color: red;
}
</style>
3. :deep()失效原因
<template><el-dialog:model-value="visible":title="title":width="width + 'px'":before-close="onClose"><div class="container" :style="{height:height + 'px'}"><slot name="content"></slot></div><template #footer><div class="dialog-footer"><el-button plain type="danger" @click="onClose">取消</el-button><el-button plain type="primary" @click="onConfirm">确定</el-button></div></template></el-dialog>
</template>
<style lang="scss" scoped>
// 组件内自定义的 elementplus 的样式,
:deep(.el-dialog){border-radius: 10px!important;background-color: #535bf2;
}
- 子组件是完全引入的,那么先加载子组件,后加载该组件。
- 组件的
<template></template>
中只含有子组件,那么组件的样式会覆盖子组件的样式 - 加载父组件的时候,由于子组件已加载完成,Vue 编译器无法为组件中的元素(即子组件)添加唯一属性,也就无法将组件的样式绑定到子组件。
故,使用:deep()
,样式依然失效。
解决办法
在组件的<template></template>
中,将子组件放入到<div></div>
标签中,那么在加载组件的时候,组件的样式会绑定到<div></div>
标签上。
<template><div><el-dialog:model-value="visible":title="title":width="width + 'px'":before-close="onClose"><div class="container" :style="{height:height + 'px'}"><slot name="content"></slot></div><template #footer><div class="dialog-footer"><el-button plain type="danger" @click="onClose">取消</el-button><el-button plain type="primary" @click="onConfirm">确定</el-button></div></template></el-dialog></div>
</template>