持续进步的同学都关注了“1024译站”第77篇文章
持续进步的同学都关注了“1024译站”
这是1024译站的第 77篇文章
随着代码规模的增长,前端项目中的 CSS 管理成了问题,其中之一就是 CSS 规则冲突。多人协作开发的项目,通过命名约定的方式有时候可能也无法完全避免。对此,不同的前端框架有不同的解决方案。Vue.js 提供了一种样式作用域(Scoped)的机制来防止组件之间的样式规则冲突。
但是如果单纯用scoped属性,在覆盖子组件元素样式的时候会碰到麻烦。因此,Vue 还提供了deep选择器来解决这个问题。通过本文我们来认识下deep选择器,了解它的原理和用法。
原理
首先要搞明白scoped的原理。在 Vue 单文件组件(.vue文件)中给style标签加上scoped属性,然后里面定义的样式规则就会只作用于当前组件,不会影响到其他组件。这是怎么做到的呢?
每次面试我基本上都会问这个问题,不少初学者都表示不清楚。其实,了解某项功能的原理会帮助你更好地使用它,碰到问题时才知道根源在哪。原理也很简单,加上scoped属性后,在浏览器查看开发工具你会发现,组件模板里的每个 DOM 元素多了一个属性data-v-xxx,CSS 规则也有对应的属性选择器。这些属性名就是组件的唯一 ID,每个组件都不一样。配合 CSS 属性选择器,样式规则就只应用到对应的组件了,这样就能防止互相干扰了。
image.png
但是这样有个问题,组件只会给自己模板里的元素加上属性data-v-xxx,而不会给子组件里的元素加这个属性。同时,生成的 CSS 属性选择器也是只到自己的 DOM 元素,无法应用到子组件内部的元素。当我们需要覆盖子组件内部元素的样式时,在父组件的style里写的规则就无能为力了。在引入第三方组件库的时候经常碰到这种情况。
还好,我们有deep选择器。deep的原理就是将属性选择器里的属性移到上层,这样就能作用到所有子元素了。
举例
为了更好地演示deep选择器的用法,我们来写个简单的示例。示例应用有一些组件,组件自身不会设置样式,而是由它所在的父组件来设置。
只是简单包装了下 HTML。这里额外用了个
做容器,原因后面再讲。
<pre style="box-sizing: border-box;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" />
</pre>
这里的按钮没有设置样式,但是要注意的是js选择器,它依然会受到全局 CSS 规则的影响,比如在全局样式表里有个规则button { background-color: 'blue'; }。
下一步是创建包含该按钮组件的两个父组件。为了演示,我们在每个父组件里用v-for循环渲染三个按钮。
第一个是BlueParent:
<pre style="box-sizing: border-box;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> I is blue<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> {{ i }}<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /><br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> import BaseButton from "./BaseButton";<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> export default {<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> components: { BaseButton }<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> };<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" />
</pre>
第二个是RedParent:
<pre style="box-sizing: border-box;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> I is red<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> {{ i }}<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /><br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> import BaseButton from "./BaseButton";<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> export default {<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> components: { BaseButton }<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> };<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" />
</pre>
在BlueParent里加上如下的 CSS 代码:
<pre style="box-sizing: border-box;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> div >>> button {<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> background-color: lightblue;<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> }<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" />
</pre>
这里的三个大于号>>>就是所谓的deep选择器。这里选择器的作用是,对div底下的所有button应用样式规则,即使是子组件内部渲染的button。
最终效果就是所有的按钮背景色变成蓝色了。
我们再来做个试验,在BlueParent里面再加一个简单的:
<pre style="box-sizing: border-box;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> I is blue<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> {{ i }}<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> Blue<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" />
</pre>
你会看到,这个新的Blue元素也用上了这个样式。
最后一个测试,把样式代码改成这样:
<pre style="box-sizing: border-box;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> .blue > button {<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> background-color: lightblue;<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> }<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" />
</pre>
没有了deep选择器,只是一个简单的>选择器js选择器,样式就不会再应用到里面的元素了。
再来看:
<pre style="box-sizing: border-box;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> div /deep/ button {<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> background-color: red;<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> }<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" />
</pre>
这里用了deep选择器另外一种写法,>>>跟/deep/的作用是一样的。之所以还有这种写法,是因为有些预编译器,比如 SASS,无法识别>>>这种语法,会导致编译失败。这种情况下改用/deep/就好了。
同样,效果就是所有按钮的背景色变成红色了。
还记得前面给加的额外的套套
吗?当你在选择器里能选中组件的根元素时,就可以不用这种deep选择器了,因为这个根元素也是父组件里直接渲染的元素。眼见为实,我们给的那个
加一个class="buttonWrapper":
<pre style="box-sizing: border-box;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" />
</pre>
在父组件里写上下面的 CSS:
<pre style="box-sizing: border-box;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"> div > .buttonWrapper {<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> background-color: yellow;<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" /> }<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" />
</pre>
效果就是div的背景变成黄色。
总结
deep选择器不会经常用,但是能在特定的情况下解决特定问题。另外值得一提的是,deep选择器会应用到所有子组件里的元素,包括嵌套子元素。因此需要自己考虑影响范围,采取适当措施。
发表评论
热门文章
Spimes主题专为博客、自媒体、资讯类的网站设计....
仿制主题,Typecho博客主题,昼夜双版设计,可....
一款个人简历主题,可以简单搭建一下,具体也比较简单....
用于作品展示、资源下载,行业垂直性网站、个人博客,....
热评文章
最新评论
bluejay21st
1月30日
我是作者,很意外我的插件会被转载,非常感谢。因为平时比较忙,改了博客的域名但是并没有及时做重定向以及更新插件,十分抱歉。
大家如果需要可以去Github下载我的插件:
https://github.com/bluejay21st/Typecho-BaiduSeo
https://github.com/bluejay21st/Typecho-Sitemap
chenyu
2天前
[已回复]
怎么配置主题 没看到教程