vue3处理css样式 :deep() 没有作用

<style lang="scss" scoped>
.el-dialog :deep(.el-dialog__body) {
    height: 500px;
    overflow: auto;
}
</style>

请问为什么样式穿透没有效果?
https://vuejs.org/api/sfc-css...
我不知道是我写的有问题还是vue3这块有问题,有点折磨

阅读 28.3k
2 个回答
<style lang="scss" scoped>
.el-dialog :deep(.el-dialog__body) {
    height: 500px;
    overflow: auto;
}
</style>

上面代码不生效的原因是 .el-dialog 并不是当前组件中的 class。它是 element plus 组件中的 class。编译当前 .vue 文件时它没有被当前 .vue 中 template 元素匹配到。

可以这么写 style:

:deep(.el-dialog__body) {
  background-color: red;
}

先看这个例子:

<script setup>
import { ref } from "vue";

const dialogVisible = ref(false);
</script>

<template>
  <div>
    <el-button @click="dialogVisible = true"
      >click to open the Dialog</el-button
    >

    <el-dialog
      v-model="dialogVisible"
      title="Tips"
      width="30%"
      :before-close="handleClose"
      custom-class="my-dialog"
    >
          Lorem ipsum dolor sit amet.
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="dialogVisible = false">Cancel</el-button>
          <el-button type="primary" @click="dialogVisible = false"
            >Confirm</el-button
          >
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<style scoped>
:deep(.el-dialog__body) {
  background-color: red;
}
</style>

image.png

正如你所见,它生效了。此时组件样式被编译器处理成:

image.png

组件 template 被处理成这样:

image.png

需要注意的是,当前 template 中给出了单个组件根节点。上面示例中组件根节点是 div。

如果我们去掉根节点,其他条件保持不变,当前组件的 template 会是这样:

<template>
  <el-button @click="dialogVisible = true">click to open the Dialog</el-button>
  <el-dialog
    v-model="dialogVisible"
    title="Tips"
    width="30%"
    :before-close="handleClose"
    custom-class="my-dialog"
  >
    Lorem ipsum dolor sit amet.

    <template #footer>
      <span class="dialog-footer">
        <el-button @click="dialogVisible = false">Cancel</el-button>
        <el-button type="primary" @click="dialogVisible = false"
          >Confirm</el-button
        >
      </span>
    </template>
  </el-dialog>
</template>

此时 style 依然被处理成这样:

image.png

正如你所见,深度选择器是不会生效的:

image.png

由于我们给 style 添加了 scoped,当前组件编译后的样式自动添加了用于表示样式作用域的选择器,而这个“表示样式作用域的选择器”默认对应组件的唯一根节点,但是我们没有唯一根节点。

上面已经给出了一种解决方法了:

  1. 组件要包含一个根节点
  2. 还要再 style 中使用 :deep()

我们来思考更好的做法。显然上面的解决办法中虽然直接更改了 element 组件的的 class,但是仅在作用域内生效,并无不妥。

但是常规的做法是尽量不直接修改组件库组件的的 class。例如提问中的例子我们可以修改插入元素的根节点高度。

<template>
  <div>
    <el-button @click="dialogVisible = true"
      >click to open the Dialog</el-button
    >
    <el-dialog
      v-model="dialogVisible"
      title="Tips"
      width="30%"
      :before-close="handleClose"
      custom-class="my-dialog"
    >
      <div class="my-dialog-content">
        <p>Lorem ipsum dolor sit amet.</p>
      </div>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="dialogVisible = false">Cancel</el-button>
          <el-button type="primary" @click="dialogVisible = false"
            >Confirm</el-button
          >
        </span>
      </template>
    </el-dialog>
  </div>
</template>


<style scoped>
.my-dialog-content {
  height: 200px;
}
</style>

.my-dialog-content 即是作为插槽内容的根节点 class,修改此 class 以达到等同更改 .el-dialog__body 的效果。

如果不是仅仅修改单组组件中组件库的样式,对于 element plus,可以通过修改 theme 文件中样式变量以达到全局修改的效果。

或者直接在任意组件中通过 vue3 提供的 :global() 修改全局样式。以题中的例子为例:

<style scoped>
:global(.el-dialog__body) {
  background: red;
}
</style>

既然是全局样式,当然与组件是否有单个根节点无关了。

vue2中element-ui中的dialog是挂载在body上的,也就是说你需要设置全局样式去改,而不能设置scoped样式,不知道element-plus中是不是这样,你可以看看,而且deep不应该放在body前面,应该放在dialog类前面

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题