1.scoped实现作用域隔离的原理
scoped通过给元素和css样式添加不重复的data属性(data-v-xxx)来使模块私有化(整个过程通过PostCSS转译实现)。
PostCSS会给一个组件中的所有元素添加一个唯一的data属性(data-v-xxx),给css选择器添加一个包含该属性的属性选择器,这样就让样式只作用于含有该属性的元素,从而实现样式隔离。
a.通过给组件里面的元素添加一个唯一的data属性来保证他的唯一性(如data-v-69538f99);
b.会在每句编译后的css选择器末尾添加一个当前组件的data属性选择器(如[data-v-69538f99])来私有化样式;
c.如果组件内部还有其他组件,只会给其他组件的最外层元素添加当前组件的data属性,这也就是为什么我们修改一些第三方ui库的样式时需要使用深度选择器(:deep())实现样式穿透的原因,因为第三方的子组件内部的元素不会添加当前组件的data属性,而转译后的css又会在末尾添加含有该data属性的属性选择器,这样就会导致设置的样式无法准确命中。
2. 深度选择器(:deep()): 通过改变属性选择器的位置实现样式穿透
先看例子:
有如下CssDemo组件,组件里面引入了antd的input组件,样式结构如下图:
设置input的样式:
使用:deep()前:样式不生效
不生效原因:从上面的html结构可以看出,input组件中class为ant-input的元素并不处于该组件的最外层,由于scoped的特性只会在子组件的最外层元素添加上父组件的data属性,因此ant-input对应的元素上并不存在父组件的data属性,因为编译后的css样式在.ant-input后面添加了带有父组件data属性的属性选择器,所以编译后的css并不能找到该元素。
使用:deep()后:样式生效
生效原因:带有父组件data属性的属性选择器从.ant-input后面移动到了.css-demo后面, 由于.css-demo对应的元素上存在该data属性,因此样式生效。
原理:从上面2组图的对比可以得出,深度选择器会将所选元素后面的属性选择器移动到它跟随的那个选择器后面,使样式生效。