04Vue 3 类与样式绑定详解
Vue 3 提供了多种灵活的方式来操作元素的 class 和 style 绑定,让我们能够根据应用状态动态切换样式。
一、Class 绑定
1. 对象语法
<template>
<!-- 根据 isActive 布尔值决定是否添加 active 类 -->
<div :class="{ active: isActive, 'text-danger': hasError }"></div>
<!-- 可以直接绑定一个对象 -->
<div :class="classObject"></div>
</template>
<script setup>
import { reactive, computed } from 'vue'
const isActive = ref(true)
const hasError = ref(false)
// 响应式对象
const classObject = reactive({
active: true,
'text-danger': false
})
// 使用计算属性
const classObject = computed(() => ({
active: isActive.value && !hasError.value,
'text-danger': hasError.value && hasError.value.type === 'fatal'
}))
</script>
2. 数组语法
<template>
<!-- 数组中可以包含字符串、对象和计算属性 -->
<div :class="[activeClass, errorClass]"></div>
<div :class="[isActive ? activeClass : '', errorClass]"></div>
<div :class="[{ active: isActive }, errorClass]"></div>
</template>
<script setup>
const activeClass = ref('active')
const errorClass = ref('text-danger')
const isActive = ref(true)
</script>
3. 与普通 class 共存
<template>
<!-- 静态 class 和动态 class 可以共存 -->
<div class="static" :class="{ active: isActive, 'text-danger': hasError }"></div>
<!-- 渲染结果:<div class="static active"></div> -->
</template>
4. 在组件上使用
<template>
<!-- 子组件(MyComponent.vue) -->
<div>
<p :class="$attrs.class">子组件内容</p>
</div>
</template>
<template>
<!-- 父组件 -->
<MyComponent class="my-class" />
</template>
二、Style 绑定
1. 对象语法
<template>
<!-- 直接绑定样式对象 -->
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
<!-- 绑定样式对象变量 -->
<div :style="styleObject"></div>
<!-- 自动添加前缀(如 transform) -->
<div :style="{ transform: 'scale(' + scale + ')' }"></div>
</template>
<script setup>
import { reactive } from 'vue'
const activeColor = ref('red')
const fontSize = ref(30)
// 样式对象
const styleObject = reactive({
color: 'red',
fontSize: '13px',
fontWeight: 'bold'
})
</script>
2. 数组语法
<template> <!-- 合并多个样式对象 --> <div :style="[baseStyles, overridingStyles]"></div> </template> <script setup> const baseStyles = reactive({ color: 'black', fontSize: '14px' }) const overridingStyles = reactive({ color: 'red', // 会覆盖 baseStyles 中的 color fontWeight: 'bold' }) </script>
3. 多重值
<template>
<!-- 提供多个带前缀的值,Vue 只会渲染浏览器支持的最后一个 -->
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
</template>
三、高级用法
1. 使用计算属性
<template> <div :class="computedClasses" :style="computedStyles"></div> </template> <script setup> import { computed } from 'vue' const isActive = ref(true) const error = ref(null) const computedClasses = computed(() => ({ 'btn': true, 'btn-active': isActive.value, 'btn-error': error.value !== null, 'text-large': isActive.value && !error.value })) const computedStyles = computed(() => ({ color: error.value ? 'red' : 'blue', fontSize: isActive.value ? '16px' : '14px', opacity: isActive.value ? 1 : 0.5 })) </script>
2. 动态类名和样式名
<template>
<!-- 动态属性名 -->
<div :class="{[dynamicClassName]: true}"></div>
<div :style="{[dynamicStyleName]: 'value'}"></div>
</template>
<script setup>
const dynamicClassName = ref('my-dynamic-class')
const dynamicStyleName = ref('margin-top')
</script>
3. CSS 模块支持
<template> <!-- 使用 CSS Modules --> <div :class="$style.myClass"></div> <div :class="[$style.myClass, $style.anotherClass]"></div> </template> <style module> .myClass { color: red; } .anotherClass { font-size: 20px; } </style>
4. 自定义指令处理类/样式
<template>
<div v-custom-class="{ active: isActive }"></div>
</template>
<script setup>
const vCustomClass = {
mounted(el, binding) {
const classes = binding.value
Object.keys(classes).forEach(className => {
if (classes[className]) {
el.classList.add(className)
} else {
el.classList.remove(className)
}
})
},
updated(el, binding) {
const classes = binding.value
Object.keys(classes).forEach(className => {
if (classes[className]) {
el.classList.add(className)
} else {
el.classList.remove(className)
}
})
}
}
</script>
四、最佳实践
1. 性能优化
<template> <!-- 避免在模板中写复杂逻辑 --> <!-- 不推荐 --> <div :class="{ active: status === 'active' || isEnabled, error: hasError && attempts > 3 }"></div> <!-- 推荐:使用计算属性 --> <div :class="statusClasses"></div> </template> <script setup> import { computed } from 'vue' const statusClasses = computed(() => ({ active: status.value === 'active' || isEnabled.value, error: hasError.value && attempts.value > 3 })) </script>
2. 组织样式类
<template> <!-- 使用有意义的类名组合 --> <button :class="[ 'btn', `btn-${variant}`, `btn-${size}`, { 'btn-disabled': disabled } ]" :style="{ '--custom-property': customValue }" > 按钮 </button> </template> <script setup> const variant = ref('primary') // primary, secondary, danger const size = ref('medium') // small, medium, large const disabled = ref(false) const customValue = ref('#ff0000') </script>
3. 结合 CSS 变量
<template> <div class="progress-bar" :style="{ '--progress-width': `${progress}%`, '--progress-color': progressColor }" ></div> </template> <style scoped> .progress-bar { width: 100%; height: 20px; background-color: #eee; } .progress-bar::before { content: ''; display: block; width: var(--progress-width, 0%); height: 100%; background-color: var(--progress-color, #42b983); transition: width 0.3s ease; } </style>
五、TypeScript 支持
<template> <div :class="classObject" :style="styleObject"></div> </template> <script setup lang="ts"> import { computed, ref } from 'vue' interface ClassObject { [key: string]: boolean } interface StyleObject { [key: string]: string | number } const isActive = ref<boolean>(true) const progress = ref<number>(50) const classObject = computed<ClassObject>(() => ({ active: isActive.value, disabled: !isActive.value })) const styleObject = computed<StyleObject>(() => ({ width: `${progress.value}%`, opacity: isActive.value ? 1 : 0.5 })) </script>
总结
Vue 3 的类与样式绑定提供了:
-
灵活性:对象语法、数组语法多种方式
-
响应式:自动响应数据变化
-
性能优化:智能的更新机制
-
类型安全:完整的 TypeScript 支持
-
CSS 集成:支持 CSS Modules、Scoped CSS
掌握这些绑定技巧,可以让你更高效地创建动态、响应式的用户界面。

浙公网安备 33010602011771号