vue中改变组件样式

问题描述

遇到一个需求,改变vue项目中某个element组件的样式,但是正常的在style中写css样式不起作用

例如:我要改变下面输入框的的背景色以及字体颜色

    <el-dialog :title="title" :visible.sync="open" width="700px">
      <el-form ref="form" :model="form" label-width="140px">
        <el-form-item label="员工姓名" prop="name">
          <el-input v-model="form.name" disabled></el-input>
        </el-form-item>
      </el-form>
    </el-dialog>

解决问题

第一步

那么按照常理来说css代码应该会是这样的:

.el-dialog .el-form .el-input{
  background-color: white;
  color: rgb(8, 234, 49);
}
第二步

首先明确,在vue项目中的element组件中直接看到的组件名是不能直接用来写css代码来改变其样式的。因为组件名并不是它的最低一层的层级,也就是说直接用组件名写css样式,就等同于是没有选中元素,因此css样式是不会起作用的。正确的做法是,通过浏览器中的控制台,选中指定元素后,去看其最低一层的层级是什么,然后通过最低一层的层级选中目标元素之后写css代码。

但是事实上该样式不起作用,原因就是没有获取到最低一层的层级,获取其最低的层级如下图所示:

image-20230628224854510

当层级确定之后,css的代码应该是这样的:

.el-dialog .el-form .el-input .el-input__inner{
  background-color: white;
  color: rgb(8, 234, 49);
}
第三步

但是,当层级已经正确且css代码正确之后,依旧没有起作用,这是因为父组件的style样式无法渗透到子组件中起作用,这时就需要考虑一下是不是通过 deep 穿透一下,让样式可以渗透到其内部组件,添加穿透之后的css代码应该如下:

::v-deep .el-dialog .el-form .el-input .el-input__inner {
  background-color: white;
  color: rgb(8, 234, 49);
}

到此为止,问题已经解决了。

第四步

但是,有时候样式仍然会不起作用,这时候就需要考虑是不是选择器权重的问题,是不是权重没有达到要求,为了确保设置的样式权重最高,可以给代码再添加 ! important 属性(但是一般不建议使用该属性,因为它会破坏整个页面的权重结构

::v-deep .el-dialog .el-form .el-input .el-input__inner {
  background-color: white !important;
  color: rgb(8, 234, 49) !important;
}

到此为止,算是已经是一个完美体了,正确的选中了元素、css代码书写正确、添加了渗透、添加了最高级别的权重;基本上可以解决绝大部分问题。

拓展

查看element组件最低层级

查看element组件的最低一层的层级,上面已经讲过方法,在控制台查看即可。

关于vue中deep的用法
vue中的scoped属性

我们都知道,Vue组件的style标签里,有scoped属性,这是为了使其内部所写的样式只会作用于当前组件,而不会污染到其他组件的样式,避免了样式的全局污染;不仅仅是可以避免不同的.vue文件之间是隔离的,而且在一个.vue的内部,父组件和子组件之间样式也是隔离的。极大的避免了样式污染的发生。

因此对于vue项目来说,组件中style的scoped一定要写,且必不可少。

scoped存在导致的问题

但是这样就会出现一个问题:使用了scoped属性之后,父组件的style样式将不会渗透到子组件中。

而对于上文中的问题而言,el-dialog是一个弹窗组件,el-form是一个表单组件,el-input又是一个输入框组件,也就是说,我们刚才所写的看似是一层一层的css层级,实际上却是一层层的组件,由外到内。

如果直接写成:.el-dialog .el-form .el-input .el-input__inner,那么css样式仅仅只停留在el-dialog这一个父组件中,而不会作用到el-form乃至其更内层的组件中去,就会导致css样式不起作用。

此时一定大脑中有一个疑问,既然作用不到子组件中,那我直接只写最低一层的子组件这一层不就行了,就比如这样:.el-input__inner;哈哈,如果在当前的.vue文件中有且仅有这一个输入框、又或者是该页面的所有输入框都要修改样式,那么这样写是没有问题的,因为这样只写最低一级的层级,会选中该.vue文件中的所有输入框。

但是如果该.vue文件中代码很多,而你想选中且改变样式的输入框,仅仅只是众多输入框中的一个或者是几个呢?那么阁下又该如何应对呢?

我们还是要回到最初的问题上来,通过父组件一层一层的去筛选出我们想要改变样式的输入框,然后改变样式最好不过了,那么如何解决样式无法渗透到子级组件的问题呢?

deep

如果想对设置了scoped的子组件里的元素进行控制可以使用 ’>>>’ 或者 ’deep’,但是一些预处理程序,例如sass不能解析>>>属性,因此最终权衡之后都用deep是最好的选择了。

deep的写法,目前已知的有:/deep/::deep,其中兼容性最好的就是::deep,所以建议使用第二种。

使用方法:在想要影响子组件的那个元素的选择器的前边加上::v-deep

经过测试,deep是可以穿透多层的,只要组件写在deep之后,那么就可以穿透到最低一层,就比如:::deep .el-dialog .el-form .el-input .el-input__inner,样式不是穿透到el-dialog就不能再穿透了,而是可以一直穿透到最低一级:el-input__inner

deep精准定位

如果子组件里有很多个li,或者li嵌套li,那只在外边说深入里边的li不准确。怎么精确的定位到子组件里的某个元素呢?

可以给子组件传一个prop,是classPrefix。在子组件里判断,如果外边给传了这个classPrefix,那某个元素就拥有了一个class,叫做"xxx-item",xxx是classPrefix变量的值。

然后在父组件的css里,就可以deep 这个加了前缀的选择器,就可以精准找到这个元素了。

给元素绑定class

给一个元素添加class可以使用&&,也可以使用对象形式。

<li :class="type==='-' && 'selected'" @click="selectType('-')">支出</li>

如果前边的表达式为True,这个元素就拥有了后边的class。如果我这时再给它添加一个class绑定,会出错,不能同时有两个:class,所以升级使用对象

<li :class="{selected:type==='-',[classPrefix+'-item']:classPrefix}" @click="selectType('-')">支出</li>

绑定的class是一个对象,里边是key-value。表示如果value表达式为真,我就拥有了key这个class。因为对象可以有很多个键值对,所以使用对象可以同时动态绑定多个class。

我要绑定的第二个class,是xxx-item,xxx是父组件要给我传的一个prop。如果给传了,即如果classPrefix这个外部属性给传了,我就拥有了以它为前缀的一个class。可是这个classPrefix是一个变量,在这里使用${}插值不合法。有ES6的新语法:如果一个key里边有变量,就用[]把这个key包起来,里边用字符串相加的方式表达。

总结

在子组件的特定元素上绑定了classPrefix的类之后,在父组件的css里就可以deep 这个新加的class找到这个元素了。

<template>
   <Layout>
       <Type :type.sync="yyy" class-prefix="xxx"/>
   </Layout>
</template>
<style lang="scss" scoped>
    ::v-deep .xxx-item{
        border:1px solid black;
    }
    ::v-deep ul{
        border:1px solid red;
    }
</style>

使用classPrefix在以下场景非常好用:一个父组件使用了多个一样的子组件,但是又需要不同的样式,就可以给不同的子组件传不同的classPrefix,那么里边的具体某个元素在不同的使用下就有独特的class。这样每个组件的样式都不互相影响。

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值