一、前言
数据驱动视图的最后一公里是样式:Tab 激活高亮、状态标签红绿、行选中变色------这些都要样式"跟着数据变"。class 和 style 的动态绑定写法多而杂,这篇一次汇总到位,以后写样式直接来查表。
二、:class 对象语法:{ 类名: 布尔值 }
最常用写法------类名做 key,数据表达式做 value,为 true 就挂上该类:
vue
<template>
<button :class="{ active: isActive }">点我切换高亮</button>
<!-- 混合:静态 class 和动态 :class 共存,Vue 自动合并 -->
<button class="btn" :class="{ active: isActive, disabled: isDisabled }">
多条件高亮
</button>
</template>
<script setup>
import { ref } from 'vue'
const isActive = ref(true)
const isDisabled = ref(false)
</script>
<style scoped>
.btn { padding: 6px 16px; }
.active { background: #42b983; color: #fff; }
.disabled { opacity: 0.5; }
</style>
两个要点:
- 静态 class 和动态 :class 可以同时写,结果是合并,不会覆盖
- 对象里可以放任意表达式:
{ active: count > 5 }
三、:class 数组语法:多类名批量挂
类名组合比较动态时用数组:
vue
<template>
<!-- 数组:每个元素都是一个类名 -->
<p :class="[baseClass, activeClass]">数组组合样式</p>
<!-- 数组 + 对象混搭:数组里某一项用对象控制开关 -->
<p :class="[baseClass, { highlight: isHighlight }]">数组嵌对象</p>
<!-- 三元表达式:二选一场景 -->
<p :class="isError ? 'error' : 'success'">{{ isError ? '失败' : '成功' }}</p>
</template>
<script setup>
import { ref } from 'vue'
const baseClass = ref('text')
const activeClass = ref('active')
const isHighlight = ref(true)
const isError = ref(false)
</script>
选择心法:条件开关多 → 对象;类名本身是变量 → 数组;二选一 → 三元。三者可以无限组合。
四、:style 对象语法:CSS 内联的 JS 形态
:style 接一个对象,属性名两种写法二选一:
vue
<template>
<!-- camelCase 写法:fontSize(推荐) -->
<p :style="{ fontSize: size + 'px', color: textColor }">camelCase</p>
<!-- kebab-case 写法:'font-size',必须加引号 -->
<p :style="{ 'font-size': size + 'px', 'font-weight': 'bold' }">kebab-case</p>
</template>
<script setup>
import { ref } from 'vue'
const size = ref(20)
const textColor = ref('#42b983')
</script>
细节:fontSize 不用引号(JS 标识符合法);'font-size' 必须引号(有横线)。值需要单位就手动拼字符串。
五、:style 数组与自动前缀
多段样式来源不同时用数组合并:
vue
<template>
<p :style="[baseStyle, overrideStyle]">数组合并样式</p>
</template>
<script setup>
import { ref } from 'vue'
const baseStyle = ref({ fontSize: '18px', color: '#333' })
const overrideStyle = ref({ color: '#e74c3c' }) // 同名属性后者覆盖
</script>
另外,需要浏览器前缀的属性(transform 等)Vue 会自动补全(如 -webkit-transform),不用手写。
六、综合实战:Tab 高亮 + 状态标签
最常见的两个业务样式场景:
vue
<template>
<!-- Tab 高亮:对象语法 + v-for(016 篇知识联动) -->
<div class="tabs">
<button
v-for="tab in tabs"
:key="tab.id"
:class="{ active: currentTab === tab.id }"
@click="currentTab = tab.id"
>
{{ tab.name }}
</button>
</div>
<!-- 状态标签:三元表达式配色 -->
<ul>
<li v-for="order in orders" :key="order.id">
{{ order.name }}
<span :class="['tag', order.status === 'paid' ? 'green' : 'gray']">
{{ order.status === 'paid' ? '已支付' : '待支付' }}
</span>
</li>
</ul>
</template>
<script setup>
import { ref } from 'vue'
const currentTab = ref(1)
const tabs = [
{ id: 1, name: '商品' },
{ id: 2, name: '评价' },
{ id: 3, name: '详情' }
]
const orders = ref([
{ id: 1, name: '订单A', status: 'paid' },
{ id: 2, name: '订单B', status: 'unpaid' }
])
</script>
<style scoped>
.tabs button { margin-right: 8px; }
.active { background: #42b983; color: #fff; }
.tag { padding: 2px 8px; border-radius: 4px; font-size: 12px; }
.green { background: #e1f3d8; color: #529b2e; }
.gray { background: #f4f4f5; color: #909399; }
</style>
两个模式直接抄进项目:currentTab === tab.id 配对象语法做 Tab 高亮;['tag', 条件 ? 'a' : 'b'] 数组嵌三元做状态标签。
【截图位置:Tab 切换高亮与订单状态标签的运行效果】
七、踩坑记录
- 对象语法类名带特殊字符要引号 :
{ 'mt-10': isShow }这种带横线的类名必须加引号 - :style 忘写单位 :
{ fontSize: 20 }无效(部分属性可以,但 font-size 不行),写'20px'或size + 'px' - kebab-case 属性没加引号 :
{ font-size: '12px' }直接语法错误,JS 对象里横线属性必须引号 - :class 里用了不存在的类:不报错但也不生效,先确认 scoped 样式里真的定义了这个类
- 重要样式用内联 :style:内联优先级高但难维护,频繁复用的样式写进 class,:style 只管"高度动态"的那几个值
八、今日小结
- :class 三板斧:对象管开关、数组管组合、三元管二选一
- 静态 class 与动态 :class 自动合并共存
- :style 对象两种键名:fontSize(免引号)与 'font-size'(必须引号);数组合并时后者覆盖前者
- 经典模式:Tab 高亮、状态标签配色,直接复用
下篇预告
指令篇最后一课:把前面全部知识(v-model 修饰符、computed 校验、:class 配色、v-if 提示)合体,从零写一个注册页联动校验------纯 Vue3 不用 UI 库,做完这篇你就能独立写表单了。