[vue] scope 是怎么做的样式隔离的【热度: 126】

关键词:vue 样式个例

Vue 中的样式隔离是通过 Vue 单文件组件(Single File Components,简称 SFC)的 <style> 标签中的 scoped 属性实现的。当你在一个 Vue 组件的 <style> 标签上添加 scoped 属性时,Vue 会自动将该样式限定在当前组件的范围内,从而防止样式冲突和不必要的样式泄漏。

实现原理

Vue 在编译带有 scoped 属性的 <style> 标签时,会按照以下步骤处理样式隔离:

  1. 生成唯一的作用域 ID:Vue 为每个带有 scoped 属性的组件生成一个唯一的作用域 ID(如 data-v-f3f3eg9)。这个 ID 是随机的,确保每个组件的作用域 ID 是独一无二的。

  2. 添加作用域 ID 到模板元素:Vue 会在编译组件模板的过程中,将这个作用域 ID 作为自定义属性添加到组件模板的所有元素上。例如,如果作用域 ID 是 data-v-f3f3eg9,那么在该组件模板的所有元素上都会添加一个属性 data-v-f3f3eg9

  3. 修改 CSS 选择器:对于组件内部的每个 CSS 规则,Vue 会自动转换其选择器,使其仅匹配带有对应作用域 ID 的元素。这是通过在 CSS 选择器的末尾添加相应的作用域 ID 属性选择器来实现的。例如,如果 CSS 规则是 .button { color: red; },并且作用域 ID 是 data-v-f3f3eg9,那么该规则会被转换成 .button[data-v-f3f3eg9] { color: red; }

示例

假设有如下 Vue 单文件组件:

<template>
  <button class="btn">Click Me</button>
</template>

<style scoped>
.btn {
  background-color: red;
}
</style>

编译后,CSS 规则会变成类似于这样(注意:实际的作用域 ID 是随机生成的):

.btn[data-v-f3f3eg9] {
  background-color: red;
}

并且模板里的 <button> 元素会被编译为类似这样:

<button class="btn" data-v-f3f3eg9>Click Me</button>

这样,.btn 样式规则只会应用到当前组件中的 <button> 元素上,而不会影响到其他组件中的同类元素,实现了样式隔离。

注意事项

  • 由于样式隔离是通过属性选择器和自定义属性实现的,因此这种方法的性能可能会略低于全局样式规则。
  • scoped 样式不能影响子组件,仅限于当前的组件。如果需要影响子组件,则需要使用深度选择器(>>>/deep/)。
  • 其他 Web 组件技术如 Shadow DOM 也可以提供样式隔离的功能,但 Vue 选择了这种不需要 polyfill、兼容性更好的实现方式。