六维教程

Vue3 动态样式

Vue 把”样式动态化”拆成三个能力:

  • 样式跟着数据走:动态 class、动态 style
  • 把样式锁在本组件<style scoped>
  • 用 JS 变量写 CSS:样式里的 v-bind()

动态 class

class 的绑定支持字符串、对象、数组三种形式,从简单到复杂依次介绍。

字符串语法(最简单)

一个变量直接存类名isActive 的值是什么,class 就是什么:

<script setup>
import { ref } from 'vue'
const isActive = ref('active')
</script>

<template>
  <p :class="isActive">状态文本</p>
</template>

isActive'active',所以渲染出的真实 HTML 是:

<p class="active">状态文本</p>

字符串语法就是”把 class 静态字符串换成表达式”,改 isActive 的值就能换类名。但它一次只能管一个类——多个状态就不好维护了,于是有下面的对象语法。

对象语法(最常用)

先看最简单的场景——只有一种状态,一个布尔变量控制一个类名:

<script setup>
import { ref } from 'vue'
const isActive = ref(true)
</script>

<template>
  <p :class="{ active: isActive }">状态文本</p>
</template>

:class 里写一个 JS 对象,语法是”给哪个类名 → 由哪个布尔决定”。拆开看三部分:

  • : 的意思:把后面的内容当表达式计算,而不是普通字符串(和 class="..." 的静态写法区分)。
  • 大括号 {} 是一个 JS 对象,表示类名与条件的对应关系
  • 每项写法 "类名: 布尔条件"键是类名,值是决定加不加的布尔值,值为 true 就把这个类加到元素上,为 false 就不加。

上面 isActivetrue,所以最终渲染出的真实 HTML 是:

<p class="active">状态文本</p>

CSS 里把样式写到 .active 上即可。以后只要改 isActive 的值,类名、样式就会自动跟着变,这就是”样式跟着数据走”。

再扩展一步——多个状态、多个类,对象里写几项就行:

<script setup>
import { ref } from 'vue'
const isActive = ref(true)   // 真 → active 这个类被加上
const isError  = ref(false)  // 假 → error 这个类不加
</script>

<template>
  <p :class="{ active: isActive, error: isError }">状态文本</p>
</template>

对照着看,isErrorfalse,所以 error 不加,渲染结果和上面一样:

<p class="active">状态文本</p>

再扩展一步——类名和变量名可以不一样,比如 isError 对应类名 has-error'has-error': isError 即可(类名带横线时需要加引号)。

数组语法(组合多个)

数组语法是把多种来源拼在一起:固定类名、字符串变量、对象都可以放进去:

<script setup>
import { ref } from 'vue'
const typeClass = ref('card')   // 字符串:类名字符串变量
const hasError  = ref(false)    // 布尔:对象语法里的条件
</script>

<template>
  <!-- 数组里可以是固定类名、字符串变量、对象 -->
  <div :class="['base', typeClass, { error: hasError }]"></div>
</template>

hasErrorfalse,所以渲染结果是这些类名合并、去重:

<div class="base card"></div>

数组语法最灵活,但可读性一般,一般用于”固定类 + 条件类”混搭的复杂场景。

和静态 class 共存

class="static":class自动合并,不用担心互相覆盖:

<div class="card" :class="{ active: isActive }"></div>

动态 style

style 用对象语法,属性名用驼峰或加引号的 kebab-case 都行:

<script setup>
import { ref } from 'vue'
const color = ref('#f60')
const fontSize = ref(16)
</script>

<template>
  <p :style="{ color: color, fontSize: fontSize + 'px' }">动态样式</p>
  <!-- 背景色换成用户选的颜色 -->
  <div :style="{ backgroundColor: color }"></div>
</template>

单位不会自动补全,数字需要自己拼 'px' 等。

数组语法(多个样式对象合并)用得少,了解即可。

样式里的 v-bind():用 JS 变量写 CSS

Vue3 支持在 <style> 里用 v-bind() 直接引用 <script setup> 里的变量:

<script setup>
import { ref } from 'vue'
const primaryColor = ref('#f60')
</script>

<style scoped>
.button {
  /* 变量改变自动更新样式 */
  background: v-bind(primaryColor);
}
</style>

这是”数据驱动视觉”的利器:主题色、深浅模式切换都不用再铺一层内联样式。

scoped:把样式锁在本组件

<style scoped> 会给组件里的元素加一个随机 data-v-xxx 属性,让样式只作用于本组件的元素,避免”多个组件的样式互相污染”:

<style scoped>
.active {
  color: #f60;
}
</style>

打开浏览器控制台能看到,元素上多了 data-v-xxx 那串随机属性,CSS 编译后也带上了同样的限定,从而实现”只作用于此组件”。

(它牵扯到子组件时还有更多细节,比如能否改到子组件内部的样式,等学到Vue3 组件通信入门再展开。)

速查卡片

场景 写法
条件加类(推荐) :class="{ active: isActive }"
多类组合 :class="['base', cond ? 'x' : '']"
动态内联样式 :style="{ color, fontSize: n+'px' }"
本地样式隔离 <style scoped>
用 JS 变量写 CSS background: v-bind(themeColor);
上一篇
Vue3 表单绑定
下一篇
Vue3 模板引用