前言
在使用 Vue 开发项目的过程中,通常我们都会在样式标签 style
中加上 scoped
属性,来让样式只对当前 vue 文件生效,但是在开发项目的过程中,我们免不了会引用到第三方插件,并且有时后会接到一些需求需要去修改这些插件的样式,这时后如果我们直接在存在 scoped
属性的标签中写样式,就会发现无法生效,有的同学可能还发现,如果把scopde
去掉,那么样式就可以对插件生效了
本文就以该现象出发,带大家一起看看 scoped
究竟对我们的代码做了什么
scoped 简介
作用
通过给 <style>
标签添加 scoped 属性让样式在当前组件中生效,不影响其他的组件
实现原理
标签添加 scoped 后,会给节点新增自定义属性,然后
css
根据属性选择器添加样式
实现原理读起来可能有些抽象,我们一步一步来,要想了解 scoped 的实现原理,我们还需要先了解一下 CSS
的选择器都有哪些和优先级如何计算
CSS 选择器
我们使用到的选择器有
- id 选择器(
#
) - 类选择器(
.
) - 属性选择器(
a[href]
) - 伪类选择器(
a:hover
) - 标签选择器(
div,p,h1...
) - 相邻选择器(
h1+p
) - 子元素选择器(
ul > li
) - 后代选择器(
li a
) - 通配符选择器(
*
)
优先级
重点来,其实不难想到,优先决定了我们写的样式是否生效,所以,我们可以利用优先级的特性,来让我们的样式只在一定范围内生效
先简单点我们来对他们做一个优先级比较(!important
标记的样式优先级最高)
!important > 内联样式 > id > class > 标签 > 大于通配 复制代码
有的时候,光靠以上优先级还不能确认权重,这时就涉及到了css
的权重计算了
- 内联样式(1000)
- ID选择器(0100)
- 类选择器/属性选择器/伪类选择器(0010)
- 元素选择器/伪元素选择器(0001)
- 关系选择器/通配符选择器(0000)
如果遇到不确定,可以按照以上的权重进行计算来得出样式的优先级
scoped 做了什么
其实想要得到答案很简单,动手试一试就知道,不过感觉很多人都没有关注到这一点,可能这个问题比较小,面试时问这个问题时还是蛮多候选人没答上来的
我们来做一个带 scoped
属性和一个不带 scoped
属性的 style
标签,看看页面有何不同
代码
<template> <div class="root"></div> </template> <!-- <style> .root { height: 100vh; width: 100%; } </style> --> <style scoped> .root { height: 100vh; width: 100%; } </style> 复制代码
调试
- 不带
scoped
- 带
scoped
怎么样,看到这里是不是已经不需要我说什么可能你已经明白了
实际上添加了 scoped
后就是给当前组件的样式添加了一个属性选择器 [data-v-XXXX]
,从而实现了局部样式的效果
为什么修改插件样式时使用scoped会失效
再回到我们一开始的问题,是不是你心里已经知道为什么了
原因
插件样式一般是全局引入,加上 scoped 后样式变成局部样式,局部样式 (由属性选择器实现) 不能影响全局样式 (权重更高)
怎么做
当然,遇到这种需要修改第三方组件样式的需求,我们是不建议直接使用全局样式 (即去掉scoped标签) 去覆盖的,最好是采用样式穿透的形式去修改样式
即:
// css 父元素 >>> 第三方组件 // scss 父元素 deep 第三方组件 复制代码
好了,本篇内容就讲到这里,相信看到这大家都能明白 scoped
属性的工作原理了,特别提醒一下,样式穿透在 vue 开发中使用的会比较频繁,但是要注意作用范围,最好避免全局下样式穿透修改组件样式