vue项目中的样式穿透

51 阅读2分钟

Vue样式隔离scope

Vue组件之间没有做到样式隔离,Vue中的样式隔离,是通过scoped属性来实现的。当在<style>标签上使用scoped属性时.基本原理概括为以下几个步骤:

  • 为当前组件模板的所有DOM节点添加相同的attribute,添加的属性与其他的scope不重复,data属性(形如:data-v-123)来表示他的唯一性。

  • 每句css选择器的末尾(编译后的生成的css语句)加一个当前组件的data属性选择器(如.ipt input[data-v-123])来私有化样式

  • 如果组件内部包含有其他组件,只会给其他组件的最外层标签加上当前组件的data属性

  • 样式隔离的效果:只能选中本组件元素,无法选中子组件的元素

为什么需要样式穿透

在Vue项目中,当我们引入第三方组件库时(如使用element-ui),需要在局部组件中修改第三方组件库样式,而又不想去除scoped属性造成组件之间的样式覆盖。这时候我们就需要样式穿透来实现我们想要的效果。

原理

让父组件在有scoped的标签里,可以访问到子元素选择器,从而使用子元素的选择器修改子元素的样式。

具体原因

因为vue在做样式隔离时,有子组件时只会在最外层的元素添加data属性,而css添加时,只会在最后添加属性选择器。而:deep样式穿透就是要解决,css选择器添加问题。 例如:比如修改a-input的背景颜色:

<template>
    <div>
        <el-input class="ipt"></el-input>
    </div>
</template>
<style scoped lang="scss">
.ipt{
    input{
        background-color: red;
    }
}
</style>

dom: 给最外层元素添加data属性,即: image.png css: 在最后添加样式选择器: image.png

不生效的原因是因为dom中选择器为ipt[data-v-b8cedf19] input 而style中默认为.ipt input[data-v-b8cedf19],所以导致样式不生效。

解决方法

添加deep: less中添加deep的方式:

<style lang="less" scoped> 
外层 /deep/ 第三方组件 { 
    \样式\ 
} 
</style>

例:

<template>
  <div class="parent">
    <child-component></child-component>
  </div>
</template>

<style lang="less" scoped>
.parent /deep/ .child {
  // Your styles here that affect .child component
  color: red;
}
</style>

在这个示例中,.parent 是有作用域的,而 /deep/ 则表示穿透作用域,影响到 .child 组件的样式。这确保了你可以在父组件的样式中修改子组件的样式。 记住,/deep/::v-deep 是 Vue 2.x 提供的穿透作用域的方式。在 Vue 3.x 中,可以使用 ::deep::slotted 来实现类似的效果。