第三方组件库的样式优先级 scoped 的作用 样式穿透 内联样式
我们在使用第三方组件库的样式的时候,往往会需要根据自身需求来修改组件的默认样式。
我们在使用第三方组件库的时候,我们自己写的组件的样式出现在前面,而插件(第三方组件库)的样式会从后面进来,会覆盖掉我们写的样式,所以如果我们直接给这个组件添加类和样式,是不能成功修改组件原有的样式的。
1. scoped 的作用
scoped 只针对当前组件生效,不污染全局样式
举个例子,如果我在 home.vue 这个组件中编写如下
<template>
<div class="test">
<div class="box">我是 home 的盒子</div>
</div>
</template>
<script>
export default {
name: 'home'
}
</script>
<style lang="scss" scoped>
.test{
.box{
color:pink;
}
}
</style>
同时我新建两个组件 index.vue 和 login.vue,在里面编写和 home.vue 一样的 html 和css 部分的代码,但是给 box 的字体颜色设置为蓝色,如下
<template>
<div class="test">
<div class="box">我是 index 的盒子</div>
</div>
</template>
<script>
export default {
name: 'index'
}
</script>
<style lang="scss" scoped>
.test{
.box{
color: skyblue;
}
}
</style>
<template>
<div class="test">
<div class="box">我是 login 的盒子</div>
</div>
</template>
<script>
export default {
name: 'login'
}
</script>
<style lang="scss" scoped>
.test{
.box{
color: orange;
}
}
</style>
出现的结果是, home.vue 运行出来的样式
index.vue 运行出来的样式是
login.vue 出来的样式是
这就是 scoped 的作用,虽然我们在 三个组件 index.vue、 home.vue 和 login.vue 中写的样式类名都是一样的,但由于scoped 的作用,样式只能作用在当前的组件内,所以 三个页面中的box的颜色,分别对应其页面中的 css 样式。
在看,假如我同时去掉三个页面中的 scoped, 然后刷新一下页面,我们会发现,这个时候,在多次切换三个页面的过程中,三个页面的样式会相互污染,出现的样式很混乱,并不是我们想要的三个页面分别出现不同的颜色(以下截图只是其中一种情况,大家可以自行测试,这里只想说明运行出来的样式并不能实现三个页面分别三种不同颜色的字体)。
出现这种情况的原因,就是因为我们去掉了scoped,在当前组件写的 css 样式,会污染(影响)到其他组件的样式,从而达不到我们想要的样式效果,所以一般开发中,都会添加 scoped 属性,防止出现样式直接相互污染的情况。
2. 样式穿透
而我们在使用第三方库的时候,如果我们即想用第三方库的样式,又不希望修改第三方库这个属性的全局样式。
简单的说,举个例子,例如 某第三方库的组件的 button 按钮,其默认宽度为70px(默认样式可以理解为这个第三方组件库的button 的其中一个全局样式)。我希望我在 A 页面用这个button,但是我觉得它不够宽,我想改成150px, 同时我又想在 另外一个 B 页面 里面也使用 button,但在 B页面 里面,我就觉得70px 刚刚好。这个时候,我就只希望修改 B 页面 这个页面里面的 button 的 宽度为150px, 其他页面的button 宽度不变,还是其默认的全局样式 70px。
在这种情况下,我要修改第三方组件库的 button 样式,同时也 我们需要用 scoped 来防止我修改 的 B 页面中的样式 污染到其他页面的 button 样式,但是如果直接在css 中给这个组件添加样式,会发现我们添加的 css 并不会生效。
原因就是开头我们说的,我们自己写的组件的样式出现在前面,而插件(第三方组件库)的样式会从后面进来,会覆盖掉我们写的样式。
举个例子,使用 elementUI 的 input,代码和运行的默认样式是这样的
<el-input placeholder="请输入内容"></el-input>
现在我想把这个 input 输入框的高度改成 200px,尝试以下几种方式
(1) 给它添加一个类明,添加 样式
<template>
<div class="test">
<el-input class="input-box" placeholder="请输入内容"></el-input>
</div>
</template>
<style lang="scss" scoped>
.test {
.input-box {
height: 200px;
}
}
</style>
运行后我们发现,这样写是 不生效 的
(2) F12 调出控制台,找到 input 对应的 html ,找到第三方库默认给input 添加的类名
给 .el-input__inner 添加 样式 ,去掉 scoped 的话是生效的,但是我们不想去掉 scoped 的情况下,就应该使用样式穿透了。
.test {
.el-input__inner {
height: 200px;
}
}
(3) 穿透 scoped
这个时候,需要在局部组件中修改第三方组件库样式,而又不想去除scoped属性造成组件之间的样式覆盖。这时我们可以通过特殊的方式 穿透 scoped。
1、stylus的样式穿透
外层 >>> 第三方组件 {
样式
}
2、sass和less的样式穿透
// 语法
外层 /deep/ 第三方组件 {
样式
}
则代码应该修改为如下,外层容器为 test,即 该部分css 只在 test 容器内生效。
<template>
<div class="test">
<el-input class="input-box" placeholder="请输入内容"></el-input>
</div>
</template>
<style lang="scss" scoped>
.test /deep/ .el-input__inner {
height: 200px;
}
</style>
这个时候就可以看到 input 成功修改为 200px 高了
如果我们在 test 容器外,再添加一个input ,会发现这个后添加的input,高度仍然为默认的高度,而不是 200px,就是因为 外层容器是test,修改的样式只在 test 容器内生效,再 test 外的容器中不起作用。
<el-input class="input-box" placeholder="input框1"></el-input>
<div class="test">
<el-input class="input-box" placeholder="input框2"></el-input>
</div>
<style lang="scss" scoped>
.test /deep/ .el-input__inner {
height: 200px;
}
</style>
3. 样式穿透和内联样式
这个问题,是我在用 ElementUI 的 组件的时候,发现 用样式穿透竟然不生效,后来看到官方提供了可修改的属性,直接修改官方提供的属性的值就可以生效,产生的疑惑。
(但 **如果是我们自己在第三方库上直接添加内联样式 是不能达到我们想要的样式效果的** )
例如我们直接给 input 添加一个内联样式 style="height: 200px"
<el-input placeholder="input框1" ></el-input>
<div class="test">
<el-input style="height: 200px" placeholder="input框2"></el-input>
</div>
可以发现,如果不使用样式穿透,直接添加内联样式,并不能使我们添加的样式有效的让 input 框的 输入框变为200px。但我们 input 整体的盒子变成了 200px 。
所以这也是为什么要用 样式穿透,而不用 内联样式 直接修改的原因。
但是 如果官方提供了可修改的参数,则可以通过该参数直接修改样式。
- 引用elementUI 的一个左侧菜单栏,默认宽度 300px
<el-aside >
此处省略
</el-aside>
- 通过样式穿透,将宽度修改为 100px (不生效)
.admin /deep/ .el-aside{
width: 100px;
}
- 通过修改官方提供的内联样式,生效
<el-aside style="width: 100px">
省略
</el-aside>
回顾一下样式的优先级
内联样式 > ID 选择器 > 类选择器 = 属性选择器 = 伪类选择器 > 标签选择器 = 伪元素选择器
也就是说 内联样式的优先级是最高的,ElementUI 官方提供的 可修改的属性 就是直接修改 内联样式。
而 我们通过 样式穿透 修改的样式,只是修改了ElementUI 封装的 类选择器 的样式,优先级是比内联样式低的,所以才不能生效。
以上仅个人的理解,有误请大家及时指正。