前言
在我们前端的开发中经常会使用到各种 ui 框架 下面这两个是比较火的,也是我常用的两个ui框架。
问题描述
但是在使用框架的时候难免会遇到需要改变组件中的一些样式,当然如果我们所有页面的组件样式都是统一的话,我们可以进行全局设置样式,但是如果我们仅仅在一个页面中需要个性化的样式设置,我们平常会下面这样操作:
<style lang="less" scoped>
#main {width: 100%;height: 90%;
}
.ivu-form .ivu-form-item-label {color: #fff;
}
.ivu-table th {height: 60px !important;
}
.ivu-table td {height: 45px !important;
}
.conLeft {width: 78%;height: 100%;padding: 10px;position: relative;img {width: 100%;height: 100%;}.smaBox {cursor: pointer;position: absolute;width: 40px;height: 40px;}
}
</style>
不难看出我们上面的很多类名就是我们组件中自带的,我们只有通过这些类名去更改我们当前页面组件呈现的样式,但是因为我们在当前页面中去编写的样式只想让其应用在当前的页面中,所以我们在style中去添加了scoped属性,关于scoped属性的讲解我们放到下面去讲解;
先回到我们上面的代码中,看似没有任何问题我们去通过类名改变组件的样式,但是他不会生效,就是因为scoped属性导致的问题,在我们的Vue项目中scoped属性真的很好用,为我们避免了组件之间的样式覆盖,使我们定的样式不会造成全局的污染!
解决办法 - 样式穿透即可
首先我们要搞明白添加上scoped属性后发生了什么,如果您着急解决问题可以直接看我们这个小节的问题解决,如果您想知其然知其所以然,那么您现在可以先去看文章的下一小节——scoped属性的原理。
使用样式穿透去解决 scoped 带来的问题,样式穿透有四种形式:
不太推荐第一种写法,不同浏览器的展示形式不一样,容易出问题,2、3、4这几种都是有预处理器(less, scss, sass)的写法,推荐大家使用第二、三种,
- stylus的样式穿透 使用 >>>
- /deep/
- ::v-deep
- 去掉scoped
将scoped属性去掉。虽然很方便 但是失去了样式的保护,我们就需要用原始的方法保护该组件的样式作用域,可通过后台选择器等等方式实现样式的保护,使其不受污染。好像更麻烦了。
上面我通过使用第二种方式 轻松实现了
scoped属性的原理
为了使样式私有化(模块化),不对全局造成污染,可以在style标签上添加scoped属性以表示它的只属于当下的模块,这是一个非常好的举措
我们可能只了解他的作用就是为了让当前组中的style中的样式,仅仅对当前组件生效,对原理可能不太懂,那下面小编就带大家梳理一下scoped的原理。
scoped的用法
<template><div class="box">欢迎您的光临</div>
</template><style lang="less" scoped>.box{background-color:green;}
</style>
- 从上面的代码中我们可以看出我们的scoped属性就是直接写到我们的style标签当中,使用就是这么简单
设置scoped属性后发生了什么
设置上了scoped 实际上我们是将代码通过 PostCss 进行了转换,下面我们进行一下对比
PostCss是一个样式处理工具,它通过自定义的插件和工具生态体系来重新定义css,有兴趣的同学可以去了解一下关于PostCss中的一些常用插件,让你的css更哇塞
转换前:
<template><div class="box">欢迎您的光临</div>
</template><style lang="less" scoped>.box{background-color:green;}
</style>
转换后:
<template><div class="box" data-v-21aa888a>欢迎您的光临</div>
</template><style>.example[data-v-21aa888a] {color: red;}
</style>
- 上面对比后大家应该就懂了是怎么回事了吧,其实说白了加上scoped后vue编译过程中会生成一个唯一的data-xxx标志,样式后面会跟上该标志,以避免污染全局样式
- 在父组件中设置了scoped中的样式 如果该组件中有子组件 那子组件的根元素中也会继承父组件中生成的style的唯一标识
慎用scoped
上面我们看到了scoped这个属性很香,其实他隐藏了很多坑
- 大家都知道css样式有一个优先级的说法,scoped的这一操作,虽然达到了组件样式模块化的目的,但是会造成一种后果:每个样式的权重加重了:理论上我们要去修改这个样式,需要更高的权重去覆盖这个样式。这是增加复杂度的其中一个维度,所以如果要达到修改样式的目的,就必须加重我们要修改样式的权重(增加选择器层级,ID选择器,并列选择器,impotant等)
- 还有一种情况就是我们的两个组件中均含有scoped 而且一个组件中包含了另一个组件,所以在Dom渲染的时候会在dom节点上加上很多唯一style的标识,有的是继承的,有的是自己组件的,所以我们在修改样式的时候还是会涉及到上面所说的权重问题,如果做不好可能会出现尴尬的问题就是自己的组件修改不了自己组件的样式哈哈
- 最后的问题就是我们上面抛出的问题,当我们设置此属性后我们想要改变组件中的样式是改变不了的,当然我们可以通过强大样式穿透进行解决!