Vue 局部样式作用域---scoped、CSS Modules

101 阅读3分钟

Scoped定义

在Vue中,scoped属性通过PostCSS插件来实现样式的局部作用域。当你在一个Vue组件的<style>标签中使用scoped属性时,这个插件会自动给组件模板中的每个元素添加一个独一无二的属性(通常是一个带有哈希值的data-v-*属性)。同时,它还会转换相应的CSS选择器,使它们包含这个独一无二的属性。

scoped原理

通过给组件中DOM元素和CSS各自都添加一个相同且唯一的属性选择器,让当前的CSS文件的样式只对当前组件生效。

scoped过程

  • 扫描模板:PostCSS插件首先会扫描Vue组件的模板,收集所有的元素和组件。

  • 添加唯一属性:为每个元素生成一个唯一的属性(如data-v-f3f3eg9),并在模板渲染时将这些属性添加到对应的DOM元素上。

  • 转换CSS选择器:然后,插件会遍历组件的CSS样式,将每个选择器转换为包含这个唯一属性的形式。例如,一个原本的选择器.my-class会被转换为.my-class[data-v-f3f3eg9]

  • 应用转换后的样式:最终,转换后的CSS样式被应用到组件的DOM元素上,确保了样式的局部作用域。

scoped属性的作用优点:

样式隔离

使用scoped可以确保组件的样式不会与其他组件的样式发生冲突。即使两个组件使用了相同的类名或选择器,由于样式作用域的隔离,它们的样式也不会相互干扰。

组件化开发

在组件化开发中,每个组件都应该有自己独立的样式。通过scoped,你可以为每个组件编写独立的CSS样式,使得组件更加模块化和可重用。

维护性

使用scoped可以提高样式的可维护性。由于样式只应用于当前组件,因此在修改或调试样式时,你可以更加专注于当前组件的样式,而无需担心对其他组件的影响。

scoped样式的缺点:

  • 样式权重增加: Scoped 样式会给每个样式增加特定的选择器属性,导致了样式的权重增加。这可能会导致样式覆盖和继承方面的问题,需要更高的权重来覆盖 Scoped 样式。

  • 无法直接操作子组件样式: Scoped 样式限制了父组件对子组件样式的直接操作。如果需要修改子组件内部的样式,就需要使用深度作用选择器或其他特殊方式来解决。

  • 性能问题: 使用 Scoped 样式时,浏览器需要额外处理样式选择器,可能会对性能产生一定影响。尤其是当使用标签选择器时,性能下降更为显著。

CSS Modules[推荐使用]

CSS Modules,在 <style> 上增加 module 属性,即<style module>
<style module> 代码块会被编译为 CSS Modules 并且将生成的 CSS 类作为 $style 对象的键暴露给组件,可以直接在模板中使用 $style。而对于如 <style module="content"> 具名 CSS Modules,编译后生成的 CSS 类作为 content 对象的键暴露给组件,即module 属性值什么,就暴露什么对象。

useCssModule模块名使用

<script setup lang="ts">
import { useCssModule } from 'vue'

// 不传递参数,获取<style module>代码块编译后的css类对象
const style = useCssModule()
console.log(style.success)  // 获取到的是success类名经过 hash 计算后的类名
    
// 传递参数content,获取<style module="content">代码块编译后的css类对象
const contentStyle = useCssModule('content')
</script>

<template>
  <div class="success">普通style red</div>

  <div :class="$style.success">默认CssModule pink</div>
  <div :class="style.success">默认CssModule pink</div>

  <div :class="contentStyle.success">具名CssModule blue</div>
  <div :class="content.success">具名CssModule blue</div>
</template>

<!-- 普通style -->
<style>
.success {
  color: red;
}
</style>

<!-- 无值的css module -->
<style module lang="less">
.success {
  color: pink;
}
</style>

<!-- 具名的css module -->
<style module="content" lang="less">
.success {
  color: blue;
}
</style>