在我使用vue3进行样式调整时,我发现有时会出现使用第三方库样式调整无效(下方以Element-plus为例)的情况,网上讲解了很多关于深度选择器的作用原理,但是一直不得要领,我想有时候你真的需要去看一眼源代码可能才能理解很多时候原本自己不理解的东西吧。

首先我想强调一点的是,这应该是使用scoped时会出现的问题,但是我们应当尽量用scoped去写样式,不能因小失大,毕竟scoped提供的隔离的作用才是我们想要的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<template>
<div>
<el-button plain @click="dialogVisible = true"> Click to open the Dialog </el-button>
<el-dialog v-model="dialogVisible" title="Tips" width="500" :before-close="handleClose">
<span>This is a message</span>
</el-dialog>
</div>
</template>

<script setup>
import { ref } from 'vue'
import { ElMessageBox } from 'element-plus'

const dialogVisible = ref(false)

const handleClose = () => {
ElMessageBox.confirm('Are you sure to close this dialog?')
}
</script>

<style scoped lang="scss">
.el-overlay .el-dialog__body {
color: red;
background-color: aquamarine;
}
</style>

以这段代码为例,可以发现其实我们写的样式并没有生效。

image-20240401201311443

我们搜索一下最后我们写的样式到哪里去了。

image-20240401201532841

会发现编译完后css结果带上了data-xxx的属性,但是原来的元素却并不具有这个属性,所以最后就失效了。

查阅网上资料可以得知,对于vue来说,一个组件包含了子组件balabala后,最后编译的结果只有根组件会带有data-xxx这样的属性,显然Element-plus对ElDialog这个组件做了很多封装,所以最后写的样式被转换了但是html元素没有加上data-xxx属性。

使用:deep()包裹一下再看看结果。

image-20240401202022533

可以看到使用:deep()的作用其实是将data-xxx属性提前到父元素了(这里我没有写父元素所以是[data-xxx]),假如说我们这么写:

1
2
3
4
.el-dialog :deep(.el-dialog__body) {
color: red;
background-color: aquamarine;
}

然后你会发现样式又失效了,这里就不展示了,原因是当你去寻找.el-dialog元素时会发现他也不是根元素,没有data-xxx属性。

从上面的几个现象来看,我认为:deep()的作用原理应该就是将data-xxx属性提前。

所以我认为一般当我们无法修改某个元素的样式时,直接单独提出来用:deep()包裹就能正常修改样式了。