解决覆盖样式无效之scoped和deep间的那些事儿

在开发过程中,我们都知道在组件中给style标签添加scoped属性可以避免组件内样式对外界造成污染,scoped可限制样式的作用域使得组件内的样式变成局域样式,只作用于当前组件,但我们在使用第三方组件库、公共组件的时候,有时需要对这些组件进行一些样式修改,由于scoped的限制,会使得我们直接修改组件样式不生效,我们通常以下面几种方式来解决:
1.在这个scope的style标签下新建一个不含scoped的style标签覆盖组件样式;
2.在index.html中引入一个外部样式覆盖样式;
3.使用深度选择器-----/deep/ 覆盖子组件样式 ,例如 /deep/ .class{ 要覆盖的样式 } ;

 小提示:深度选择器: /deep/  和 “<<<"  二者其实作用是一样的,只是一些css预处理器,例如sass不能解析>>>属性,这种情况下可以用deep,它是>>>的别名,工作原理相同。

第一种方法简单粗暴,但是不推荐使用,因为如果命名冲突可能会导致其他样式异常;
第二种方法也比较刚硬,不推荐使用;
第三种方法既修改了子组件的样式,又不会污染全局样式,值得推荐使用,可它是啥原理呢?那我们继续往下瞅瞅~~

首先,就是在编译组件的时候,如果当前组件内style标签上有scoped属性时,就会给当前组件所有标签上添加一个【data-v-hash】属性,且在标签的css选择器的结尾加上和属性同样的字段,起到唯一性的作用,实现类似于"作用域"的作用,那么就使得当前组件内的样式只会作用于当前组件内的元素。
如以下父、子组件代码结构:

/*父组件结构*/
/*父组件里使用child子组件*/
<template>
  <div class="father-div">
    <span class="father-text">我是父组件</span>
    <child />
  </div>
</template>

<style lang="scss" scoped>
.father-div{
    
    
    .father-text{
    
    
        color:red;
    }
}
</style>
/*子组件结构*/
<template>
  <div class="child-div">
    <span class="child-text">我是子组件</span>
  </div>
</template>

<style lang="scss" scoped>
.child-div{
    
    
    .child-text{
    
    
        color:pink;
    }
}
</style>

由于组件的style标签上有scoped属性,所以浏览器解析时会给所有标签添加一个【data-v-hash】,且在class选择器的结尾加上和属性同样的字段,所以在浏览器上看到父组件的dom结构就是这样的:

<div data-v-7fa1cbbc class="father-div" >
    <span data-v-7fa1cbbc class="father-text">我是父组件</span>
</div>

对应的css样式也会在其选择器后面加上属性相同的字段:

.father-div[data-v-7fa1cbbc] {
    
    
       width: 200px;
       height: 20px;
}
.father-div .father-text[data-v-7fa1cbbc] {
    
    
     color: red;
}

如果当父组件和子组件的样式都是用了scoped属性时,子组件最外层的标签既会被加上当前组件的hash值,又会加上父级组件的hash值。
所以子组件在浏览器上解析的结构是这样的:

<div  data-v-384b136e data-v-7fa1cbbc class="child-div" >
      <span  data-v-384b136e class="child-text">我是子组件</span>
</div>

现在要是想在父组件内直接改变子组件内类名为child-text的span标签的样式时,就会发现不好使:

/* 父组件的css样式 */
<style lang="scss" scoped>
.father-div{
    
    
    .father-text{
    
    
        color:red;
    }
    .child-div {
    
      //直接修改
        .child-text{
    
    
            color: blue;
        }
    }
}
</style>

因为子组件的style标签也加上有scoped属性,子组件元素本身有自己的样式,浏览器会解析组件本身的样式,渲染对应的dom:

.child .child-text[data-v-384b136e] {
    
       //类选择器的hash值只与子组件标签的hash值对应
     color:pink
}

显而易见,直接修改时不好使的原因,是因为写在父组件内的样式解析的是父组件的hash值,但浏览器上解析的子组件内的标签添加的是子组件的hash值,对应的则是子组件内的样式,与父组件内的hash值对应不上,所以父组件内的样式覆盖也没有生效。
所以页面上还是展示子组件自身的样式:
在这里插入图片描述
所以现在回到咱们开始所说的,这种时候可以使用再添加一个不加scoped属性的style标签来解决,但是这种方法简单粗暴,指不定有啥别的样式被影响了,所以我们就可以使用深度选择器/deep/来解决

现在想要修改子组件类名为child-text的样式时,可以这样:

/* 父组件的css样式 */
<style lang="scss" scoped>
.father-div{
    
    
    .father-text{
    
    
        color:red;
    }
    /deep/ .child-div {
    
      //使用深度选择器修改
        .child-text{
    
    
            color: blue;
        }
    }
}
</style>

因为浏览器解析时,遇到"/deep/“的时候会将”/deep/"的位置替换成组件的hash值,即:

 .father-div[data-v-7fa1cbbc] .child-div .child-text{
    
      
    color: blue;
}

这样只需要注意css的权重就可以覆盖子组件内的样式了,页面上就会展示我们想要的样式了。
这时你会看到子组件的字体颜色已经变成我们想要的蓝色了:
在这里插入图片描述

写在最后的小提示:如果只是想要修改子组件最外层结构都样式,不需要/deep/就可以在父组件内覆盖样式,因为子组件内最外层的标签带了父、子组件的两个hash值,所以在父组件和子组件内都可直接定义其样式。

猜你喜欢

转载自blog.csdn.net/weixin_46422035/article/details/104537784