Vue进阶 | scoped原理浅析

492 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第9天,点击查看活动详情

scope,可以理解为作用域

image.png

在Vue中,想必大家都知道用scoped来声明样式标签,在页面渲染完后各个页面的样式之间不会造成污染(即样式私有化,只能在当前组件中生效),为每一个Vue组件的style标签添加scoped,就是实现了样式的模块化。

代码如下:

<style scoped>
    .text-info{
	font-size:26px;
    }
</style>

在浏览器中查看样式,可以看到这样的变化:

  1. HTML中对应的的DOM节点添加一个data属性,就是代码中我们看到的的data-v-xxxx(data-v-hash),这会对这个元素进行唯一标识,data属性是一个唯一不重复的标记。

  2. 在样式的css选择器的末尾,增加了一个当前组件的data属性选择器来私有化样式

image.png

image.png

原理

本质上是使用 vue-loader 来实现的,具体步骤如下。

  1. vue-loader 解析vue组件,提取出 template、script、style 对应的代码块
  2. 构造组件实例,在组件实例的选项上绑定 ScopedId
  3. 对CSS 代码进行编译转化,应用 ScopedId 生成选择器的属性

所以,data-v-hash属性是一个唯一不重复的标记,通过解析 style 标签内容实现,同时通过 scopedPlugin 为每个选择器追加一个 [scopeId] 的属性选择器。

源码部分

  • resourceQuery:根据引入文件的路径参数的匹配路径
  • loader.pitch:调用 loader 上的 pitch 方法
  • VueLoaderPlugin:用来注册公共的 pitcher,以及复制 webpack 的 rules

总结

  • 当使用用scoped来声明样式标签的时候,PostCSS会给组件中的所有DOM添加一个唯一的动态属性
  • 当使用/deep/ ::v-deep>>> 深度选择器进行样式穿透的时候,也会在css中加上 [data-v-hash] 来控制组件样式(在vue3.0环境下,使用/deep/编译时会报错)
  • 如果父子组件的选择器相同,子组件的样式会被父组件覆盖,原因是在生命周期中,子组件相对于父组件会优先mounted