今天,看到小伙伴在开发Vue项目,看到了他使用/deep/来修改第三方组件的样式,给我的第一感觉是不是和:global类似,能够避免选择器被hash(哈西),但其实不然。下面,我将详细介绍使用这两个关键字有什么作用。
首先,我创建了一个App.vue单文件组件,在其中使用了ant-design-vue的Slider组件。
<template>
<div id="app">
<span>123</span>
<div id="parent">
<span>234</span>
<a-slider id="test" :default-value="30" :disabled="disabled" />
</div>
</div>
</template>
<script>
import Vue from 'vue';
import 'ant-design-vue/dist/antd.css';
import { Slider } from 'ant-design-vue';
Vue.component(Slider.name, Slider);
export default {
name: 'App',
data() {
return {
disabled: true
}
}
}
</script>
<style lang="less" scoped>
#app {
& > span {
color: red;
}
#parent {
& > span {
color: green;
}
}
}
</style>
App.vue效果如下:
看下渲染出来的dom以及编译之后的css样式什么样的吧。首先,可以发现渲染出来的dom在template下的html标签都加上了data-v-xxxx属性,而第三方组件只有根节点才会加上data-v-xxx属性;其次,可以看到css被编译成了最后的选择器才会加上data-v-xxx属性。
如果我们想要修改Slider组件的样式,有两种情况,分别为修改根节点和非根节点。
- 根节点
根节点.ant-slider的高度为12px,此时,如果需要修改它的高度为20px,则直接在style下写这个选择器就可以修改了。
<style lang="less" scoped>
#app {
& > span {
color: red;
}
#parent {
.ant-slider {
height: 20px;
}
& > span {
color: green;
}
}
}
</style>
- 非根节点
非根节点.ant-slider-rail的background-color: #f5f5f5,如果需要修改它为red,可能会照葫芦画瓢,直接在style下写这个选择器修改,会不会起作用呢?
<style lang="less" scoped>
#app {
& > span {
color: red;
}
#parent {
& > span {
color: green;
}
.ant-slider-rail {
background-color: yellow;
}
}
}
</style>
实际上,这并不能起作用,.ant-slider-rail的背景颜色仍然没有发生变化。
我们可以看一下less编译成css的结果,可以看到在.ant-slider-rail选择器的后面加一个data-v-xxx的属性选择器,而.ant-slider-rail并没有该属性,所以样式不会起作用。
为了解决该问题,引入了/deep/,俗称样式穿透,用法如下。
<style lang="less" scoped>
#app {
& > span {
color: red;
}
#parent {
& /deep/ .ant-slider-rail {
background-color: red;
}
& > span {
color: green;
}
}
}
</style>
进度条变红了,看下编译后的css,可以加上/deep/并没有在.ant-slider-rail后面添加data-v-xxx属性,而是在#parent后添加了data-v-xxx属性,此时的选择器规则可以命中.ant-slider-rail元素,背景颜色被修改为红色。
最后,我也尝试:global的写法,看下样式能否起作用。
<style lang="less" scoped>
#app {
& > span {
color: red;
}
#parent {
:global .ant-slider-rail {
background-color: yellow;
}
& > span {
color: green;
}
}
}
</style>
进度条的背景颜色没有变成绿色,很遗憾,:global失效了。看看编译后的css结果,你就知道为什么了。:global并没有被正确解析,直接出现在编译后的结果。
有一种常犯的错误,我们可能会在自定义组件中给根节点定义相同的类名,例如:container。但这样,虽然子组件的样式正确,但却可以发现该子组件应用和父组件相同样式,只是被在子组件定义相同样式覆盖了而已,这同样是由上面介绍的scoped导致的,所以不推荐大家在组件中给根节点定义相同的类名。