scoped原理
# scoped 原理
# scoped 的作用及优缺点
实现组件的私有化, 当前 style 属性只属于当前模块.
scoped 的缺点:
scoped CSS 里每个样式的权重加重了(由于添加了 data 属性选择器),理论上我们可以修改某一个样式,但是却需要更高的权重去覆盖这个样式;
无论父组件样式的权重多大,也可能无法修改子组件的样式,除了子组件的根节点。
使用标签选择器时 scoped 会严重降低性能,而使用 class 或 id 则不会。
# scoped 的实现原理
scopeId 的生成方式:
(1)id 根据文件路径名和内容 hash 生成,通过组合形成 scopeId。每个 Vue 文件都将对应一个唯一的 id
(2)编译 template(使用 templateLoader) 标签时,会为每个标签添加了当前组件的 scopeId
在 templateLoader 中,会通过 vue-template-compiler 将 template 转换为 render 函数,在此过程中,
会将传入的 scopeId 追加到每个标签的 segments 上,最后作为 vnode 的配置属性传递给 createElemenet 方法, 在 render 函数调用并渲染页面时,会将 scopeId 属性作为原始属性渲染到页面上
(3)编译 style (使用 stylePostLoader)标签时,会根据当前组件的 scopeId 通过属性选择器和组合选择器输出样式
在 stylePostLoader 中,通过 PostCSS 解析 style 标签内容,同时通过 scopedPlugin 为每个选择器追加一个[scopeId]
的属性选择器
总结:在 DOM 结构中可以发现,vue 通过在 DOM 结构以及 css 样式上加了唯一标记,达到样式私有化,不污染全局的作用,
可以看出,加上 scoped 后的组件里的会多 data-v-5db9451a 属性, css 样式中可以看出;
给 DOM 节点加一个不重复属性 data-v-5db9451a 标志唯一性.
使每个样式选择器后添加类似于"不重复属性"的字段, 类似于作用域的作用,不影响全局.
如果组件内部还有组件,只会给最外层的组件里的标签加上唯一属性字段,不影响组件内部引用的组件.
谨慎使用:
父组件无 scoped 属性,子组件带有 scoped,父组件是无法操作子组件的.
父组件有 scoped 属性,子组件无 scoped.父组件也无法设置子组件样式.因为父组件的所有标签都会带有 data-v-5db9451a 唯一标志,但子组件不会带有这个唯一标志属性.
父子组件都有,同理也无法设置样式,更改起来增加代码量.
# scoped 穿透
- 穿透 scoped
stylus 的样式穿透 使用 >>>
sass 和 less 的样式穿透 使用/deep/
- 添加单独的 style 标签
参考:刨根问底,揭开 Vue 中 Scope CSS 实现的幕后(原理) (opens new window) 浅析 Vue scoped 底层原理 (opens new window) 从 vue-loader 源码分析 CSS Scoped 的实现 (opens new window)