Vue.js: Class 与 Style 绑定
最后更新:2026-08-26
:class 和 :style 是 Vue 最常用的两个绑定——让你能根据数据动态切换 CSS 类名和内联样式。本质上是 v-bind 的两个特殊语法,因为它们用得太多所以做了"语法糖"。
掌握 5 种写法就够覆盖 95% 的场景:对象语法、数组语法、三元、计算属性、字符串拼接。
1. 你将学到
:class对象语法:根据条件切换单个/多个 class:class数组语法:同时应用多个 class- 数组 + 对象混合:复杂的类名组合
:style对象语法:动态内联样式:style数组语法:合并多个样式对象- CSS 变量绑定(Vue 3 推荐)
2. 一个订单状态标签的样式难题
(1) 痛点:5 种状态,5 个 if 判断
Alice 需要在后台中用不同颜色显示 5 种订单状态:
HTML
<!-- ❌ 翻车版:5 个 v-if 加 class -->
<span v-if="status === 'pending'" class="badge yellow">Pending</span>
<span v-else-if="status === 'paid'" class="badge green">Paid</span>
<span v-else-if="status === 'shipped'" class="badge blue">Shipped</span>
<span v-else-if="status === 'delivered'" class="badge gray">Delivered</span>
<span v-else class="badge red">Cancelled</span>
产品经理 Charlie:
"Alice,这太丑了。下个月要加 3 个状态怎么办?你不能一直复制粘贴。我们需要一种干净的动态方案。"
(2) Vue :class 解法:1 行搞定 5 状态
VUE
<template>
<span :class="['badge', statusClass]">{{ statusText }}</span>
</template>
<script setup>
const { computed } = Vue
const props = defineProps({ status: String })
const statusClass = computed(() => ({
pending: 'yellow',
paid: 'green',
shipped: 'blue',
delivered: 'gray',
cancelled: 'red'
}[props.status]))
const statusText = computed(() => ({
pending: 'Pending',
paid: 'Paid',
shipped: 'Shipped',
delivered: 'Delivered',
cancelled: 'Cancelled'
}[props.status]))
</script>
(3) 收益
- HTML 减少:5 行 if-else → 1 行 :class
- 可维护:加新状态只需改 computed,模板不动
- 可读:状态类映射集中在一处,逻辑清晰
3. :class 5 种写法
(1) 字符串语法
VUE
<template>
<!-- 静态 -->
<div class="active">Static</div>
<!-- 动态字符串 -->
<div :class="className">Dynamic</div>
</template>
<script setup>
const { ref } = Vue
const className = ref('active text-bold')
</script>
(2) 对象语法(最常用)
VUE
<template>
<!-- 基础:isActive 为 true 时添加 active class -->
<div :class="{ active: isActive }">Single</div>
<!-- 多个条件 -->
<div :class="{
active: isActive,
'text-danger': hasError,
disabled: !canEdit
}">
Multiple
</div>
<!-- 计算属性返回对象 -->
<div :class="classObject">Computed</div>
</template>
<script setup>
const { ref, computed } = Vue
const isActive = ref(true)
const hasError = ref(false)
const canEdit = ref(true)
// 计算属性:动态返回 class 对象
const classObject = computed(() => ({
active: isActive.value && !hasError.value,
'text-danger': hasError.value,
'bg-success': isActive.value
}))
</script>
(3) 数组语法
VUE
<template>
<!-- 数组:多个 class 拼接 -->
<div :class="[activeClass, errorClass]">Array</div>
<!-- 三元表达式 -->
<div :class="[isActive ? 'active' : '', errorClass]">Ternary</div>
<!-- 数组 + 对象混用 -->
<div :class="[activeClass, { 'text-danger': hasError }]">Mixed</div>
<!-- 数组中嵌套对象 -->
<div :class="[{ active: isActive }, errorClass]">Nested</div>
</template>
<script setup>
const { ref } = Vue
const activeClass = ref('active')
const errorClass = ref('text-danger')
const isActive = ref(true)
const hasError = ref(false)
</script>
(4) 与静态 class 共存
VUE
<template>
<!-- 静态 + 动态合并(Vue 自动合并) -->
<div class="static-class" :class="{ active: isActive }">
Both
</div>
<!-- 最终 class: "static-class active" 或 "static-class" -->
</template>
(5) 组件上的 class
VUE
<!-- 父组件 -->
<UserCard class="shadow-lg" :class="{ active: isActive }" />
<!-- 子组件 UserCard.vue -->
<template>
<!-- 接收 -->
<div :class="$attrs.class">
<!-- 渲染 "shadow-lg active" -->
</div>
</template>
4. :style 5 种写法
(1) 对象语法
VUE
<template>
<!-- 基础对象 -->
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }">
Object
</div>
</template>
<script setup>
const { ref } = Vue
const activeColor = ref('red')
const fontSize = ref(16)
</script>
(2) CSS 属性名转换
Vue 自动把 JS 命名转为 CSS 命名:
VUE
<template>
<div :style="{
backgroundColor: 'red', // → background-color
fontSize: '16px', // → font-size
marginTop: '10px', // → margin-top
WebkitTransform: 'scale(2)' // → -webkit-transform
}">
CSS naming
</div>
</template>
(3) 数组语法(合并多个对象)
VUE
<template>
<!-- 数组:按顺序合并样式对象(后面的覆盖前面)-->
<div :style="[baseStyles, overrideStyles]">Array</div>
</template>
<script setup>
const { ref } = Vue
const baseStyles = ref({
color: 'blue',
fontSize: '14px'
})
const overrideStyles = ref({
color: 'red', // 覆盖 baseStyles.color
fontWeight: 'bold'
})
</script>
(4) 自动加前缀
Vue 3 自动给 CSS 属性加浏览器前缀(用浏览器引擎判断):
JS
// 写:
{ transform: 'rotate(45deg)' }
// Vue 自动加:
{
-webkit-transform: 'rotate(45deg)',
transform: 'rotate(45deg)'
}
(5) CSS 变量(Vue 3 推荐)
VUE
<template>
<div :style="{
'--main-color': mainColor,
'--spacing': spacing + 'px'
}">
CSS Variables
</div>
</template>
<script setup>
const { ref } = Vue
const mainColor = ref('#42b883')
const spacing = ref(20)
</script>
<style>
.dynamic {
color: var(--main-color);
padding: var(--spacing);
}
</style>
5. 完整示例:动态订单状态
▶ 示例:5 种 :class 写法
HTML
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<div id="app">
<!-- 1. 字符串 -->
<div :class="className">1. 字符串</div>
<!-- 2. 对象 -->
<div :class="{ active: isActive, error: hasError }">2. 对象</div>
<!-- 3. 数组 -->
<div :class="[activeClass, errorClass]">3. 数组</div>
<!-- 4. 数组 + 对象 -->
<div :class="[activeClass, { disabled: !canEdit }]">4. 数组+对象</div>
<!-- 5. 计算属性 -->
<div :class="dynamicClass">5. 计算属性</div>
</div>
<script>
const { createApp, ref, computed } = Vue
createApp({
setup() {
const isActive = ref(true)
const hasError = ref(false)
const canEdit = ref(true)
const className = ref('badge')
const activeClass = ref('active')
const errorClass = ref('error')
const dynamicClass = computed(() => ({
active: isActive.value,
error: hasError.value,
'cursor-not-allowed': !canEdit.value
}))
return { isActive, hasError, canEdit, className, activeClass, errorClass, dynamicClass }
}
}).mount('#app')
</script>
▶ 示例:5 种 :style 写法
HTML
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<div id="app">
<div :style="{ color: 'red', fontSize: '16px' }">1. 基础对象</div>
<div :style="{ backgroundColor: bg, padding: p + 'px' }">2. 多个属性</div>
<div :style="[baseStyles, themeStyles]">3. 数组合并</div>
<div :style="{ '--theme-color': theme }">4. CSS 变量</div>
<div :style="computedStyle">5. 计算属性</div>
</div>
<script>
const { createApp, ref, computed } = Vue
createApp({
setup() {
const bg = ref('#42b883')
const p = ref(20)
const theme = ref('#35495e')
const baseStyles = ref({ color: 'white' })
const themeStyles = ref({ backgroundColor: '#42b883' })
const computedStyle = computed(() => ({
color: 'white',
backgroundColor: theme.value,
padding: `${p.value}px`
}))
return { bg, p, theme, baseStyles, themeStyles, computedStyle }
}
}).mount('#app')
</script>
▶ 示例:订单状态徽章(5 状态切换)
HTML
📖 仅展示
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<style>
.order-badge { padding: 4px 12px; border-radius: 12px; color: white; font-size: 12px; display: inline-block; margin: 4px; }
.bg-yellow { background: #f59e0b; } .bg-green { background: #10b981; }
.bg-blue { background: #3b82f6; } .bg-gray { background: #6b7280; }
.bg-red { background: #ef4444; } .bg-default { background: #999; }
</style>
<div id="app">
<span :class="['order-badge', statusClass]">{{ statusText }}</span>
<p>
<button @click="status = 'pending'">pending</button>
<button @click="status = 'paid'">paid</button>
<button @click="status = 'shipped'">shipped</button>
<button @click="status = 'delivered'">delivered</button>
<button @click="status = 'cancelled'">cancelled</button>
</p>
</div>
<script>
const { createApp, ref, computed } = Vue
createApp({
setup() {
const status = ref('pending')
// 5 状态 → 5 class
const statusClass = computed(() => {
const map = {
pending: 'bg-yellow',
paid: 'bg-green',
shipped: 'bg-blue',
delivered: 'bg-gray',
cancelled: 'bg-red'
}
return map[status.value] || 'bg-default'
})
const statusText = computed(() => {
const map = {
pending: 'Pending', paid: 'Paid', shipped: 'Shipped',
delivered: 'Delivered', cancelled: 'Cancelled'
}
return map[status.value] || 'Unknown'
})
return { status, statusClass, statusText }
}
}).mount('#app')
</script>
▶ 示例:5 个常见错误
| 错误 | 现象 | 解决 |
|---|---|---|
| 字符串 class 不响应 | class 写死不切换 | 用 :class 绑定 |
| 数组 class 拼错 | 多个 class 重名覆盖 | 用对象语法 |
| style 单位遗漏 | 数字 16 当成 16px 失效 | 写 '16px' 字符串 |
| CSS 属性名错 | font-size 应为 fontSize |
用驼峰或引号 |
| :class 冲突 | 静态 + 动态重名 | Vue 自动合并,OK |
▶ 示例:5 个性能对比
| 写法 | 编译产物 | 性能 | 适用 |
|---|---|---|---|
| 字符串 | 直接字符串拼接 | ⭐⭐⭐⭐⭐ | 简单 |
| 对象 | 静态分析 | ⭐⭐⭐⭐ | 中等 |
| 数组 | 字符串拼接 | ⭐⭐⭐⭐ | 多 class |
| 数组+对象 | 混合处理 | ⭐⭐⭐ | 复杂 |
| 计算属性 | 缓存值 | ⭐⭐⭐⭐⭐ | 复杂逻辑 |
▶ 示例:class vs style 5 大区别
| 维度 | class | style |
|---|---|---|
| 推荐度 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
| CSS 复用 | 容易(class 名复用) | 难(style 散落) |
| 性能 | 更高(浏览器优化) | 略低 |
| 优先级 | 取决于选择器 | 内联(最高) |
| 主题切换 | 容易(换 class) | 容易(换 CSS 变量) |
❓ 常见问题
Q class 和 style 绑定可以共存吗?
A 可以。静态
class="x" + 动态 :class="{active: y}" 会自动合并(最终 class="x active" 或 "x")。Q 为什么 style 要写成对象,不能直接写 CSS 字符串?
A 可以。
<div style="color: red"> 是 HTML 原生写法,<div :style="'color: red'"> 也是字符串写法。但用对象 :style="{ color: 'red' }" 能动态绑定变量。推荐对象。Q CSS 变量怎么用?
A 在 :style 中用
{'--my-var': value},CSS 中用 var(--my-var)。Vue 3 推荐用 CSS 变量做主题切换,比直接绑定 style 更高效(只需更新 1 个变量,DOM 不重排)。Q 组件怎么接收外部 class?
A 单根组件自动继承
class 属性(Vue 3 默认行为)。多根组件用 $attrs.class 显式绑定到某个元素。Q 数组语法的 class 顺序?
A 按数组顺序拼接,但顺序不影响 CSS 优先级(优先级由 CSS 选择器特异性决定)。
Q :class 和 v-if 一起用?
A 可以。
<div v-if="show" :class="{ active: isActive }"> 当 show=false 时整个不渲染,isActive 也不生效。Q 动态切换主题怎么做?
A 推荐 CSS 变量。
:style="{ '--primary': theme.primary }",所有元素 color: var(--primary)。切换主题只改 1 个变量,比切换 100 个 class 高效。📖 小节
:class和:style是 v-bind 的语法糖,用得最多所以简化- :class 5 种写法:字符串、对象、数组、数组+对象、计算属性
- :style 5 种写法:对象、数组、数组+对象、CSS 变量、计算属性
- 静态 class 和动态 :class 自动合并
- Vue 3 自动加 CSS 浏览器前缀
- CSS 变量是 Vue 3 推荐的主题切换方案(比 style 切换高效)
- 性能:对象/计算属性 > 数组 > 字符串
📝 作业
-
基础题(难度⭐) 用 :class 对象语法实现 3 种按钮状态:
- primary:蓝底白字
- success:绿底白字
- danger:红底白字
数据:
const variant = ref('primary') -
进阶题(难度⭐⭐) 实现一个订单列表,每行根据订单状态显示不同颜色徽章:
- 5 种状态(pending/paid/shipped/delivered/cancelled)
- 用计算属性返回 class 对象
- :style 添加状态对应的 icon 颜色
-
挑战题(难度⭐⭐⭐) 实现一个完整的主题切换系统:
- 3 套主题(light/dark/high-contrast)
- 用 CSS 变量绑定主题色(primary/secondary/background/text)
- :class 切换主题类名
- localStorage 记住用户选择
- 切换主题不刷新页面(响应式自动更新)