Vue的样式穿透(在父组件中为子组件定义样式)

在使用Vue开发前端项目时,我们经常需要引入第三方组件,比如下面的例子(假设我们已经注册了element-ui):

<template>
  <div class="root">
    <el-button type="plain">点击我</el-button>
  </div>
</template>

这是一个来自element-ui的按钮组件,它会渲染成这样:
在这里插入图片描述
那我如果我们想修改这个第三方组件的样式该怎么办呢?

下面的样式并不会生效:

<style scoped>
  .root .el-button--plain {
    font-weight: bold;
  }
</style>

因为el-button--plain对应的标签并不在当前组件作用域内,它在子组件<el-button>的作用域内。

一种非常不优雅的方案是,去掉style的scoped属性,比如:

<style>
  .root .el-button--plain {
    font-weight: bold;
  }
</style>

至于el-button--plain这个类名,需要打开浏览器开发者工具,从element面板中查看。

说到这里,我们需要先了解一下为什么Vue的组件样式推荐添加scoped属性。

我们知道,普通的样式标签内定义的样式对整个页面都是有效的。因此,假如两个组件内存在具有相同类名的标签,那么当我们为其中一个定义样式时,另一个标签的样式也会受到影响(这种影响大多数时候是不利的,因为这种影响不可控)。为了解决这个问题,我们可以在样式标签上添加scoped属性,这样,这个标签内定义的样式只在当前组件内有效。scoped的实现机制为,webpack会在打包时给每个组件的所有标签添加一个特定的属性,如:
在这里插入图片描述
然后,添加了scoped属性的标签内的所有css选择器都会带上这个属性,因此,对于下面的样式:
在这里插入图片描述
编译之后可能是这样的:
在这里插入图片描述
由于只有当前组件内的标签才会携带data-v-752ada3f属性,所以这条样式只会对当前组件内的标签生效。这样就可以保证这条样式只对当前组件内的标签有效。

所以,一旦去掉scoped属性,我们就又回到了原本的问题中。那么如何优雅地解决这个问题呢?

其实可以这样(这里collapse-title是组件内定义的类名,而el-collapse-item__header是组件引用的第三方组件内定义的):
在这里插入图片描述
这里是没有使用css预编译器的写法,>>>表示要穿透组件,使该样式对其子组件生效。它编译后是这样的:
在这里插入图片描述
可以看到,现在只有根选择器带了属性限制,三大于号后面的选择器则没有,这样,el-collapse-item__header就不限制必须属于当前组件了,于是这条属性对子组件内的标签就可以生效了。并且由于scoped属性的存在,这条样式不会影响到其他外部组件(不过如果当前组件的子组件也引用了第三方组件时需要慎重,因为它会继续穿透子组件)。

如果使用了css预编译器,如scss,则需要使用下面的语法:
在这里插入图片描述
这里的/deep/表示这个选择器不属于当前组件,而是属于其子组件,同样可以达到穿透组件修改第三方组件样式的效果。

猜你喜欢

转载自blog.csdn.net/qq_41694291/article/details/107498335