Vue.js 组件 deep 选择器的用法和原理

1,260 阅读3分钟

随着代码规模的增长,前端项目中的 CSS 管理成了问题,其中之一就是 CSS 规则冲突。多人协作开发的项目,通过命名约定的方式有时候可能也无法完全避免。对此,不同的前端框架有不同的解决方案。Vue.js 提供了一种样式作用域(Scoped)的机制来防止组件之间的样式规则冲突。

一、scoped 作用域

scoped原理:加上scoped属性后,在浏览器查看开发工具你会发现,组件模板里的每个 DOM 元素多了一个属性data-v-xxx,CSS 规则也有对应的属性选择器。这些属性名就是组件的唯一 ID,每个组件都不一样。配合 CSS 属性选择器,样式规则就只应用到对应的组件了,这样就能防止互相干扰了。

*示例说明:

<style lang="scss" scoped>
.massif-table{
    .top-date{
        background:red;
    }
}
</style>

**「原理:」当我们打开控制台,抓取到对应的dom元素后,在右侧会发现我们的「样式选择器」**变成了

.massif-table .top-date[data-v-127071c6]{
    background:red;
}

**「选择器」**最后的层级加了一串唯一的hash码 **「data-v-127071c6」**以此来完成限制此样式只对改组件生效。

那么这也就是为什么在scoped的组件内无法修改同样有着scoped的子组件的样式,因为子组件和父组件的「hash码不一致」,选择器匹配不到,所以样式无法生效。

*思考问题:组件只会给自己模板里的元素加上属性 data-v-xxx,而不会给子组件里的元素加这个属性。同时,生成的 CSS 属性选择器也是只到自己的 DOM 元素,无法应用到子组件内部的元素。

二、deep 提升作用域

deep的原理就是将属性选择器里的属性移到上层,这样就能作用到所有子元素。

deep的主要作用是「css样式选择器作用域」的提升。deep肯定是和「scoped」属性结合使用的,那么首先我们就需要先了解一下scoped的作用

此时我们就需要使用 「deep」 来帮我们「提升作用域」

*示例说明

<style lang="sass" scoped>
.massif-table{
    .top-date{
       /deep/ .sub-componpent{
             background:red;
        }
    }
}
</style>

现在我们再来看看渲染后的的样式

.massif-table .top-date[data-v-127071c6] .sub-componpent{
    background:red;
}

不难发现 「data-v-127071c6」 这一串hash码被提到了 deep直接修饰的**「上一层级」**

三、错误的嵌套deep写法

其实与其说错误写法,倒不如说deep就不该有嵌套这种写法。

在我们对deep理解不深,并且有多层父子组件嵌套的时候,想在父组件修改子组件样式就可能会出现。

.fu{
    /deep/ .zi1{
         /deep/ .zi2{
                    /deep/ .zi3{
                          background:red;
                    }
         }
     }
}

这种奇葩的写法。首先我们看看这种写法会被解析成什么鬼样子。

.fu[data-v-127071c6]  .zi1  /deep/  .zi2  /deep/  .zi3{
     bakcground:red;
}

问题就来了,这种本身是不正确的,但是「浏览器却可以兼容」,完全无误的识别,所以样式会正常生效。但是手机浏览器就不会了。

四、三个大于号(>>>) VS deep

 <style scoped>
    div >>> button {
      background-color: lightblue;
    }
</style>

这里的三个大于号 >>>就是所谓的deep选择器。这里选择器的作用是,对div底下的所有button应用样式规则,即使是子组件内部渲染的button。

这里用了deep选择器另外一种写法,>>>跟/deep/的作用是一样的。之所以还有这种写法,是因为有些预编译器,比如 SASS,无法识别 >>>这种语法,会导致编译失败。这种情况下改用/deep/就好了。

*总结:

deep选择器不会经常用,但是能在特定的情况下解决特定问题。另外值得一提的是,deep选择器会应用到所有子组件里的元素,包括嵌套子元素。因此需要自己考虑影响范围,采取适当措施。