Vue 组件间的样式污染

作者: 小虫巨蟹 | 来源:发表于2017-08-30 18:07 被阅读305次

    一、污染是如何产生的?

    得益于 Vue-loader,在 Vue 中可以使用类似于 Web Component 的组件化写法,<template></template><style></style><script></script>,在大多数情况下,我们希望组件间定义的样式是相互隔离的,在 Weex 当中的确如此,组件天生隔离,可是在 Vue 当中,运行的载体还是浏览器,所有的样式类还是会通过 <style> 标签插入头部,影响全局,交叉污染

    二、增加 Scoped 标识

    依然是 Vue-loader,通过为组件中的 style 标签增加一个 scoped 标识,Vue-loader 在编译的过程中会为组件每一个元素节点增加 scopeId 作为属性,同时为所有的样式类加上属性选择器 scopeId,从而达到隔离的效果,大概是下面的样子:

    // 编译前
    <template>
        <div class='bg'></div>
    </template>
    <style scoped>
      .bg {
          background: #000;
          width: 100px;
          height: 100px;
      }
    </style>
    
    // 编译后
    <template>
        <div class='bg' data-v-8e399fae></div>
    </template>
    <style>
      .bg[data-v-8e399fae] {
          background: #000;
          width: 100px;
          height: 100px;
      }
    </style>
    

    每个组件有唯一的 scopeId,按理说,这样应该能够做到样式隔离了,实际上,这种方式其实表现已经足够好了,除了以下这种情况~~

    三、ScopeId 的继承

    我们把上面的例子再完善下:

    // 父组件
    <template>
        <div>
            <div class="bg"></div>
            <Sub></Sub>
        </div>
    </template>
    <script>
        import Sub from './sub';
        export default {
            components: { Sub }
        };
    </script>
    <style scoped>
    .bg {
        background-color: #000;
        width: 100px;
        height: 100px;
    }
    </style>
    
    // 子组件
    <template>
        <div class="bg">
        </div>
    </template>
    <script>
        export default {
        };
    </script>
    <style scoped>
    .bg {
        width: 300px;
        height: 300px;
        margin-top: 5px;
    }
    </style>
    

    由于我们使用了 scoped 标识进行样式隔离,子组件的 div 不应该有任何背景颜色,可是现实总在狠狠的打脸~~

    实力打脸

    不知道你的媚眼看到问题的所在了没:
    子元素的根元素会继承父元素的 ScopeId!
    子元素的根元素会继承父元素的 ScopeId!
    子元素的根元素会继承父元素的 ScopeId!(说了三遍的话,肯定很重要)
    由于子元素的根元素除了拥有自己的 ScopeId 属性,还继承了父元素的 ScopeId 属性,所以父元素的样式类 bg 对其依然有效

    四、怎么破?

    破解的方式也很简单,为每一个组件的根元素提供一个另类一点的样式名(如果有的话),例如就不要每个组件都命名为:wrap,根据业务名为:b1-wrap、b2-wrap 等

    组件中的非根元素,类名不管怎么命名,怎么重名,都是不会发生污染的,这个自己领悟~~

    五、【更新】这不是bug

    惭愧,文档查得不够详实,实际上官网已经有:Be careful with descendant selectors in recursive components! For a CSS rule with the selector .a .b, if the element that matches .a contains a recursive child component, then all .b in that child component will be matched by the rule.
    此文还在公众号菲麦前端中发布:

    相关文章

      网友评论

        本文标题:Vue 组件间的样式污染

        本文链接:https://www.haomeiwen.com/subject/wsrxjxtx.html