Vue.js: Class 与 Style 绑定

最后更新:2026-08-26

:class:style 是 Vue 最常用的两个绑定——让你能根据数据动态切换 CSS 类名和内联样式。本质上是 v-bind 的两个特殊语法,因为它们用得太多所以做了"语法糖"。

掌握 5 种写法就够覆盖 95% 的场景:对象语法、数组语法、三元、计算属性、字符串拼接

1. 你将学到


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) 收益


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>
逻辑代码 43 行(超过 40 行限制,仅展示)

▶ 示例: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 高效。

📖 小节


📝 作业

  1. 基础题(难度⭐) 用 :class 对象语法实现 3 种按钮状态:

    • primary:蓝底白字
    • success:绿底白字
    • danger:红底白字

    数据:const variant = ref('primary')

  2. 进阶题(难度⭐⭐) 实现一个订单列表,每行根据订单状态显示不同颜色徽章:

    • 5 种状态(pending/paid/shipped/delivered/cancelled)
    • 用计算属性返回 class 对象
    • :style 添加状态对应的 icon 颜色
  3. 挑战题(难度⭐⭐⭐) 实现一个完整的主题切换系统:

    1. 3 套主题(light/dark/high-contrast)
    2. 用 CSS 变量绑定主题色(primary/secondary/background/text)
    3. :class 切换主题类名
    4. localStorage 记住用户选择
    5. 切换主题不刷新页面(响应式自动更新)
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏