zoukankan      html  css  js  c++  java
  • 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库自身提供接口。但是可以根据具体参数灵活计算。

  • 相关阅读:
    如何只通过Sandboxed Solution启动一个定时执行的操作
    创建与SharePoint 2010风格一致的下拉菜单 (续) 整合Feature Custom Action框架
    创建与SharePoint 2010风格一致的下拉菜单
    《SharePoint 2010 应用程序开发指南》第二章预览
    SharePoint 2013 App 开发 (1) 什么是SharePoint App?
    使用Jscex增强SharePoint 2010 JavaScript Client Object Model (JSOM)
    搜索范围的管理
    SharePoint 2010 服务应用程序(Service Application)架构(1)
    SharePoint 2010 服务应用程序(Service Application)架构(2)
    SharePoint 2013 App 开发 (2) 建立开发环境
  • 原文地址:https://www.cnblogs.com/webARM/p/12443518.html
Copyright © 2011-2022 走看看