• VUE 如何覆盖element组件样式


          最近在用element UI开发一个toB系统时,发现设计稿和UI库有不小的出入,由于不是内部系统,所以这块的还原度没办法“得过且过”。我整理了一些覆盖UI库样式的“手段”

    为什么UI库(这里用的是element UI)的组件不好直接覆盖?

             我们通常的vue工程都是用vue-cli自动生成出来的,不知道大家有没有发现一个细节——生成的*.vue文件上会默认带上“scoped”,如下图:

                                       

    UI库不好覆盖的问题也基本从这里开始了。首先看“scoped”是什么?首先“scoped”并不是vue的专利,(“scoped”属性是HTML5的新特性,如果使用该属性,则样式仅仅应用到style元素的父元素及其子元素。)说人话就是vue用了scoped属性,导致当前*.vue文件里的style仅仅作用于当前组件的元素,而对部分element UI的组件无效(一些简单的组件,例如el-button这种简单替换的还是可以覆盖的)。

    “scoped”在工程中是如何工作的?

            我们可以用自己的工程运行起来看一下。看看生成的页面是什么样的。

              

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

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

           问题来啦,我们在自己组件上用scoped初衷是好的。还拿上面的例子来说,我们data-v-a2a7b732是我们自己组件的模块的标识,这里element UI对“简单组件”并没有用data-v-hash管理,我们再举个“复杂组件”的例子,比如带浮层的例如el-select,我们想把【全部数据的按钮边框去掉】

         

                                                                             

    这样写出来发现在浏览器的选择器里并没有生效。对于“el-input__inner”生的只有库本身的css样式,我们看似“合理”的css继承关系为什么没有生效呢?我们来看一下我们自己的代码到底生成了什么:

    首先父级长这样:data-type有了一个属性选择器确保唯一

    工程生成的长这样: 发现问题了吗?

    • 给HTML的DOM节点加一个不重复data属性(形如:data-v-a2a7b732)来表示他的唯一性
    • 在每句css选择器的末尾(编译后的生成的css语句)加一个当前组件的data属性选择器(如[data-v-a2a7b732])来私有化样式

    也就是说scope的操作是这样的:我们的组件作为父级组件,调用其他组件(element UI)的场景下,scope仅仅作用于我们的当前组件,我们的组件每一级dom上多了一个data-v-hash,生成的css结尾加上了属性"[data-v-hash]"(注意是每个css规则的结尾),这样做的策略是保证css命中的叶子节点是在scope规则下的。那么我们在父级嵌套element ui时“el-input__inner”作为叶子节点即一条css规则的末尾被加上了后缀"[data-v-hash]",但是实际渲染DOM上element UI组件并不会加上属性"[data-v-hash]"。因此后缀"[data-v-hash]"的css无法匹配属性"[data-v-hash]"的DOM元素。也就不会生效。

    为什么有的时候能覆盖?

    刚才简单提到过,比较简单的elementUI组件能搞定,我们看看为什么。这里有一个按钮,我要附加一些样式:

       

    注意这里我就是正常写了,给button加上一个自己的class:add-account,但是生效了。

            原因在于,elememt-ui中有一些组件,其实是单层级组件,比如:<el-button>替换成了<button class="el-button">而且会拷贝所有的class,因此element替换后仍是当前组件里的scoped控制,而上面提到的情况是组件内部深层元素不受scoped影响的情况。所以scoped场景下,仍可以控制其他组件的最外层dom,深层次规则就会出现前面的情况。而element-ui的“简单组件”基本是单层结构,也就是当前层仍能添加"[data-v-hash]"。

    下面我们来看一下几种解决方案:

    1、去掉scoped

    刚才提到css不能覆盖的原因是属性"[data-v-hash]"导致的,那么最简单的方法就是去掉“scoped”,但是一旦这样做,当前组件中的css就可能污染组件外的空间,vue工程本来就比较庞大复杂,一个页面很可能会加载很多的组件,这些组件页有可能多人维护,难免名字相同,除非你的css有比较好的“命名空间管理”就像element-ui一样。我个人建议还是不要轻易去掉。

    2、多个<style></style>

    一个vue文件可以写多个<style>标签,我们可以把大部分代码写在<style scoped>里,少数需要覆盖子组件的写在普通<style>中。但是这样只是减小了污染,并没有解决

    3、/deep/ 或者 >>> 深度作用选择器

    还用最开始的el-select举例,我添加了/deep/如下图:

                生效了!没有border了

    某些预处理器(如Sass)可能无法>>>正确解析。在这些情况下,您可以使用/deep/组合器 - 它是别名>>>并且工作完全相同。这种方法,我比较推荐,页很好用,但是并不是万能的。

    4、css import 

    有一些element-ui组件会产生脱离当前从属结构的DOM元素,比如el-dialog会在body中插入一段html,这个dom就不符合当前组件的从属关系了,并不是当前组件的子元素。第一种方法是css import,这种元素仍可以产生一些特征来减少污染,element-ui对这类组件提供了一个css的命名权,即,你可以对子组件的某个结构单独命名。例如el-dialog和el-table都有这样的属性:

     或 

    这样在body中插入的html就有了一个和组件名相关的class。我们可以在组件路径下封一个单独的css处理(不推荐写到common里,不好维护)。

    5、style-function

    这也是我发现element独特支持的方法,还用刚才的el-table举例。

     我们可以传入一个函数,return你要的样式。

     

    这种方法相当于是向特定dom上加上style。完全不污染全局,但是依赖ui库自身提供接口。但是可以根据具体参数灵活计算。

  • 相关阅读:
    零基础入门学习Python(11)--列表:一个打了激素的数组(2)
    零基础入门学习Python(10)--列表:一个打了激素的数组
    零基础入门学习Python(9)--了不起的分支和循环3
    零基础入门学习Python(8)--了不起的分支和循环2
    零基础入门学习Python(7)--了不起的分支和循环1
    标量子查询中有ROWNUM=1怎么改?
    零基础入门学习Python(6)--Python之常用操作符
    一次ORA-01555问题分析,及SQL优化。
    零基础入门学习Python(5)--闲聊之Python的数据类型
    Python内置函数(60)——compile
  • 原文地址:https://www.cnblogs.com/webARM/p/12443518.html
Copyright © 2020-2023  润新知