文章目录

Vue3 useCssModule在组合式API中使用CSS Modules

发布于 2026-05-09 05:27:49 · 浏览 16 次 · 评论 0 条

Vue3 useCssModule在组合式API中使用CSS Modules

在 Vue3 的组合式 API 中,useCssModule 是一个非常有用的工具,它能让你方便地在 <script setup> 中访问 CSS Modules 生成的类名。本文将手把手教你如何使用它。


什么是 CSS Modules 和 useCssModule

  • CSS Modules:一种 CSS 范式,通过编译将类名转换成唯一的、作用域的标识符,从而避免不同组件间的样式冲突。它不是 Vue 独有的,而是 Webpack、Vite 等构建工具支持的一个标准。
  • useCssModule:一个 Vue3 的组合式 API 钩子函数。当你在组件的 <style> 标签上使用 module 属性时,useCssModule() 会返回一个对象,这个对象的键是你写的原始类名,值是编译后生成的唯一类名。

如何在组合式 API 中使用 useCssModule

1. 在 <style> 标签中启用 CSS Modules

首先,你需要在你的单文件组件 (SFC) 的 <style> 标签上添加 module 属性。这是启用 CSS Modules 的关键。

<style module>
/* 在这里编写你的 CSS */
.title {
  color: #42b983;
  font-weight: bold;
}
.content {
  padding: 20px;
}
</style>

2. 在 <script setup> 中引入并使用 useCssModule

<script setup> 代码块中,调用 useCssModule() 函数。它会返回一个对象,包含所有你在 <style module> 中定义的类名映射。

<script setup>
// 调用 useCssModule 获取类名映射对象
const $style = useCssModule();

// 现在,你可以像使用普通对象一样使用 $style
// 例如:$style.title, $style.content
</script>

注意:虽然你可以将返回的对象命名为任何变量名(如 cssModules),但 $style` 是一个约定俗成的命名,能清晰地表明它来自样式。 ### 3. 在 `<template>` 中绑定类名 最后,在模板中使用 `v-bind` 或 `:` 将类名绑定到你的 HTML 元素上。你需要使用 `$style 对象来访问编译后的类名。

<template>
  <div>
    <!-- 绑定类名 -->
    <h1 :class="$style.title">这是一个标题</h1>
    <p :class="$style.content">这是内容段落。</p>
  </div>
</template>

完整示例

下面是一个完整的 .vue 文件示例,展示了 useCssModule 的完整用法。

<template>
  <div class="container">
    <h1 :class="$style.title">欢迎来到我的页面</h1>
    <p :class="$style.description">这是一个使用 CSS Modules 和组合式 API 的示例。</p>
    <button :class="[$style.button, $style.primary]">主要按钮</button>
    <button :class="[$style.button, $style.secondary]">次要按钮</button>
  </div>
</template>

<script setup>
// 1. 调用 useCssModule 获取样式对象
const $style = useCssModule();
</script>

<style module>
/* 2. 编写 CSS Modules 样式 */
.container {
  font-family: 'Arial', sans-serif;
  max-width: 600px;
  margin: 0 auto;
  padding: 20px;
}

.title {
  color: #2c3e50;
  text-align: center;
}

.description {
  color: #7f8c8d;
  line-height: 1.6;
}

.button {
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 16px;
  margin-right: 10px;
}

.primary {
  background-color: #3498db;
  color: white;
}

.secondary {
  background-color: #95a5a6;
  color: white;
}
</style>
```

---

## 进阶用法与注意事项

### 动态类名

`useCssModule` 返回的对象可以无缝地与 Vue 的动态类名绑定结合使用。

```vue
<script setup>
const $style = useCssModule();
const isActive = ref(true);

// ... 其他逻辑
</script>

<template>
  <div :class="[$style.box, { [$style.active]: isActive }]">
    <!-- 当 isActive 为 true 时,会同时应用 $style.box 和 $style.active 类 -->
  </div>
</template>

<style module>
.box {
  width: 100px;
  height: 100px;
  background-color: #eee;
}

.active {
  border: 2px solid blue;
}
</style>

自定义模块名称

如果一个组件中有多个 <style module>,你可以给它们命名,然后在 useCssModule 中传入名称来获取对应的模块。

<style module="foo">
/* foo 模块样式 */
.foo-title {
  color: red;
}
</style>

<style module="bar">
/* bar 模块样式 */
.bar-title {
  color: blue;
}
</style>

<script setup>
const fooStyles = useCssModule('foo');
const barStyles = useCssModule('bar');

// 使用时
// :class="fooStyles['foo-title']"
// :class="barStyles['bar-title']"
</script>

<style scoped> 的区别

虽然两者都能实现样式隔离,但它们的工作原理和适用场景不同。下表总结了它们的区别:

特性 <style scoped> <style module>
原理 通过在元素和选择器上添加唯一的 data-v-xxx 属性来实现作用域。 通过编译将类名重命名(例如 .title 变为 _title_1jk23)来实现作用域。
使用方式 <template> 中可以直接使用类名(如 class="title")。 <template> 中需要通过 useCssModule() 获取的映射对象来使用类名(如 :class="$style.title"`)。 | | **标准** | Vue 特有的语法。 | Web 标准,被 Webpack、Vite 等广泛支持。 | | **适用场景** | 适用于简单的、组件内的样式隔离,代码更简洁。 | 适用于需要更精细控制、或与其它使用 CSS Modules 的库(如 React)协作的场景。 | 你可以根据项目需求选择使用 `scoped`、`module`,或者两者结合。例如,一个组件可以同时拥有一个 `scoped` 的样式块和一个 `module` 的样式块。 ### 命名约定 默认情况下,Vite 会将 CSS Modules 的类名转换为驼峰式(camelCase)。例如,`.my-class-name` 会被编译为 `$style.myClassName

你可以在 Vite 配置中修改这个行为,例如改为使用下划线(kebab-case):

// vite.config.js
export default defineConfig({
  css: {
    modules: {
      localsConvention: 'dashes' // 'camelCase' (default) or 'dashes'
    }
  }
})

如果设置为 'dashes',那么 .my-class-name 将被编译为 $style['my-class-name'],你需要使用方括号语法来访问。

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文