• home > webfront > ECMAS > vue >

    Vue中scoped原理以及带来的样式问题

    Author:zhoulujun Date:

    vue 组件里的 style、script、template 分别会编译为相应的 style 标签、html 标签以及 script 标签引入。在一个大型项目中,不同的人的开发会导致两个不同的组件中使用了相同的类名,从而互相之间产生影响。

    css作用域

    之前一直很困扰css的作用域问题,即使是模块化编程下,在对应的模块的js中import css进来,这个css仍然是全局的。导致在css中需要加上对应模块的html的id/class 使用css选择器 保证css的作用域不会变成全局 而被其它模块的css污染。

    在vue文件中的style标签上,有一个特殊的属性:scoped。当一个style标签拥有scoped属性时,它的CSS样式就只能作用于当前的组件,也就是说,该样式只能适用于当前组件元素。通过该属性,可以使得组件之间的样式不互相污染。如果一个项目中的所有style标签全部加上了scoped,相当于实现了样式的模块化。

    vue-loader 的作用

    在一个 vue 的项目中,整个项目是通过 .vue 单文件组件组织的,一个组件即是从 UI 拆分下来的每个包含模版(HTML)+ 样式(CSS)+ 逻辑(JS)功能完备的结构单元。正是因为 vue-loader 的存在我们才得以组件化的形式进行编码。

    .vue 组件里的 style、script、template 分别会编译为相应的 style 标签、html 标签以及 script 标签引入。

    在一个大型项目中,不同的人的开发会导致两个不同的组件中使用了相同的类名,从而互相之间产生影响。好在 vue-loader 给我们提供了 scoped 属性,从编码上解决了这个问题

    Vue中scoped原理

    在vue中引入了scoped这个概念,scoped的设计思想就是让当前组件的样式不会修改到其它地方的样式,使用了data-v-hash的方式来使css有了它对应模块的标识,这样写css的时候不需要加太多额外的选择器,方便很多。

    scoped的实现原理:

    vue通过在DOM结构以及css样式上加了唯一标记,达到样式私有化,不污染全局的作用

    scoped的实现原理

    可以看出,加上scoped后的组件里的会多 data-v-5db9451a 属性, css样式中可以看出;

    1. 给HTML的DOM节点加一个不重复data属性( 如data-v-5db9451a) 用来 标志唯一性.

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

    3. 如果组件内部还有组件,只会给最外层的组件里的标签加上唯一属性字段,不影响组件内部引用的组件.

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

    vue中scoped的作用:

    1. 实现组件的私有化, 当前style属性只属于当前模块.

    2. 但是当我们使用公共组件的时候会造成很多困难.

    vue中scoped存在的问题:

    是要注意scoped的作用域,因为权重的问题,如果是在子组件使用了scoped,那么在父组件中是不能直接修改子组件的样式的,需要在父组件中使用vue的深度作用选择器。

    1. 父组件无scoped属性,子组件带有scoped,父组件是无法操作子组件的.

    2. 父组件有scoped属性,子组件无scoped.父组件也无法设置子组件样式.因为父组件的所有标签都会带有data-v-5db9451a唯一标志,但子组件不会带有这个唯一标志属性.

    3. 父子组件都有,同理也无法设置样式,更改起来增加代码量.

    scoped看起来很美,但是,在很多项目中,会出现这么一种情况,即:引用了第三方组件,需要在组件中局部修改第三方组件的样式,而又不想去除scoped属性造成组件之间的样式污染。此时只能通过特殊的方式,穿透scoped。

    白话就是说,比如你使用element-ui的样式,在demo.vue中使用table组件,并且style上加scoped,在修改table组件里边的样式是不生效的,因为data-v-009只加在子组件的第一层,子组件中其他dom是没有data-v-009这个属性的,而你写在scoped中的样式都会被postcss 添加[data-v-009],样式只作用于有data-v-009这个属性的dom

    无论你权值多高,甚至添加!important,都无法修改子组件中样式的

    /deep/深度选择解析

    <style lang="scss" scoped>.ParentA {
      color: red;
      /deep/ .Child {
        color: pink;
        &-content {
          background: green;
        }
      }
    }
    </style>

    编译结果

    .ParentA .Child-content[data-v-183fa219] {
        background: green;
    }

    使用deep

    <style lang="scss" scoped>.ParentA {
      color: red;
      /deep/ .Child {
        color: pink;
        &-content {
          background: green;
        }
      }
    }
    </style>

    编译结果为

    .ParentA[data-v-183fa219] {
      color: red;
    }
    .ParentA[data-v-183fa219] .Child {
        color: pink;
    }
    .ParentA[data-v-183fa219] .Child-content {
          background: green;
    }

    标示值提起到父容器了

    其他解决办法

    其实我讨厌是用scope的,毕竟牺牲了css查询性能

    BEM,三个字母分别代表 Block、Element、Modifier。

    块(block)(Nicole 称之为“物体(object)”)由子元素(element)构成,并且可以修改(modified)(或“主题化”)。

    命名约定

    BEM 所做的另一件事是定义了非常严格的命名约定:

    .block-name__element--modifier

    BEM不香么?



    参考文章:

    Vue中scoped原理 https://www.cnblogs.com/wtsx-2019/p/12469682.html

    解决 vue 开发中 scoped 样式问题 https://juejin.im/post/6844904137914580999




    转载本站文章《Vue中scoped原理以及带来的样式问题》,
    请注明出处:https://www.zhoulujun.cn/html/webfront/ECMAScript/vue/8551.html