Vue3 Class 与 Style 绑定
- [1. 绑定 HTML class](#1. 绑定 HTML class)
-
- [1.1 绑定对象(3种方式)](#1.1 绑定对象(3种方式))
-
- [1.1.1 直接用法(一个class变量或者多个class和html元素自由组合时推荐)](#1.1.1 直接用法(一个class变量或者多个class和html元素自由组合时推荐))
- [1.1.2 将多个 class 绑定在一个对象变量中(多个class时推荐)](#1.1.2 将多个 class 绑定在一个对象变量中(多个class时推荐))
- [1.1.3 使用对象的计算属性(多个复杂的class判断时推荐)](#1.1.3 使用对象的计算属性(多个复杂的class判断时推荐))
- [1.2 绑定数组](#1.2 绑定数组)
-
- [1.2.1 直接用法(直接修改类值)](#1.2.1 直接用法(直接修改类值))
- [1.2.2 结合三目运算符(多个判断时不推荐,过于冗余)](#1.2.2 结合三目运算符(多个判断时不推荐,过于冗余))
- [1.2.3 数组中嵌套对象(和使用对象没有太大区别)](#1.2.3 数组中嵌套对象(和使用对象没有太大区别))
- [1.3 组件上使用](#1.3 组件上使用)
-
- [1.3.1 单个根元素子组件添加 class 时,会直接合并](#1.3.1 单个根元素子组件添加 class 时,会直接合并)
- [1.3.2 多个根元素子组件添加 class 时,指定根元素合并](#1.3.2 多个根元素子组件添加 class 时,指定根元素合并)
-
- [1.3.2.1 指定单个根元素接收 class(可以)](#1.3.2.1 指定单个根元素接收 class(可以))
- [1.3.2.1 指定多个根元素接收 class(可以)](#1.3.2.1 指定多个根元素接收 class(可以))
- [2. 绑定内联样式](#2. 绑定内联样式)
-
- [2.1 绑定对象](#2.1 绑定对象)
-
- [2.1.1 绑定单个属性值(不推荐变量多时使用,模板代码不够整洁)](#2.1.1 绑定单个属性值(不推荐变量多时使用,模板代码不够整洁))
- [2.1.2 绑定整个对象(模板更加整洁)](#2.1.2 绑定整个对象(模板更加整洁))
- [2.2 绑定数组(更好操控每组样式)](#2.2 绑定数组(更好操控每组样式))
- [3. 最佳实践建议](#3. 最佳实践建议)
-
- [3.1 先掌握其中一种,不合适再看其他方式](#3.1 先掌握其中一种,不合适再看其他方式)
- [3.2 属性名称 推荐驼峰式命名](#3.2 属性名称 推荐驼峰式命名)
1. 绑定 HTML class
1.1 绑定对象(3种方式)
1.1.1 直接用法(一个class变量或者多个class和html元素自由组合时推荐)
我们可以给 :class (v-bind:class
的缩写) 传递一个对象来动态切换 class
javascript
<div :class="{ active: isActive }"></div>
active 类是否存在,取决于isActive 的值。
javascript
<template>
<div
class="demo"
:class="{
active: isActive,
'text-danger': hasError
}"
>
绑定样式类
</div>
</template>
<script setup>
import { ref } from 'vue'
const isActive = ref(true)
const hasError = ref(false)
setTimeout(() => {
hasError.value = true
}, 3000)
</script>
<style scoped>
.text-danger {
color: red;
}
</style>

3s 后
1.1.2 将多个 class 绑定在一个对象变量中(多个class时推荐)
将多个class绑定在一个对象变量中,这样代码相对清爽些,效果相比于1.1.1是相同的。
javascript
<template>
<div class="demo" :class="classObject">
绑定样式类
</div>
</template>
<script setup>
import { reactive } from 'vue'
const classObject = reactive({
active: true,
'text-danger': false
})
setTimeout(() => {
classObject['text-danger'] = true
}, 3000)
</script>
<style scoped>
.text-danger {
color: red;
}
</style>
1.1.3 使用对象的计算属性(多个复杂的class判断时推荐)
如果类的存在,取决于多个值的判断,则可以将对象包装成一个计算属性:
javascript
<template>
<div class="demo" :class="classObject">
绑定样式类
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const isActive = ref(true)
const error = ref(null)
const classObject = computed(() => ({
active: isActive.value && !error.value,
'text-danger': error.value && error.value.type === 'fatal'
}))
setTimeout(() => {
error.value = { type: 'fatal' }
}, 3000)
</script>
<style scoped>
.text-danger {
color: red;
}
</style>

3s 后
1.2 绑定数组
1.2.1 直接用法(直接修改类值)
直接将多个类名变量放在数组中,可以直接通过修改变量的值,改变类名或者移除:
javascript
<template>
<div class="demo" :class="[isActive, error]">绑定样式类</div>
</template>
<script setup>
import { ref } from 'vue'
const isActive = ref('active')
const error = ref('text-danger')
setTimeout(() => {
isActive.value = 'normal' // 修改样式类
error.value = '' // 移除样式类
}, 3000)
</script>
<style scoped>
.text-danger {
color: red;
}
</style>

1.2.2 结合三目运算符(多个判断时不推荐,过于冗余)
javascript
<template>
<div :class="[isActive ? activeClass : '', errorClass]">绑定样式类</div>
</template>
<script setup>
import { ref } from 'vue'
const isActive = ref(false)
const activeClass = ref('active')
const errorClass = ref('text-danger')
setTimeout(() => {
isActive.value = true // 3秒后激活activeClass类
}, 3000)
</script>
<style scoped>
.text-danger {
color: red;
}
</style>

3s 后
1.2.3 数组中嵌套对象(和使用对象没有太大区别)
数组中使用三目运算符虽然可以达到筛选目的,但是需要判断的类一旦变多,代码就会变得格外臃肿。因此 Vue3
也提供了数组中嵌套对象的方式。
javascript
<template>
<div :class="[{ [activeClass]: isActive }, errorClass]">绑定样式类</div>
</template>
<script setup>
import { ref } from 'vue'
const isActive = ref(false)
const activeClass = ref('active')
const errorClass = ref('text-danger')
</script>
<style scoped>
.text-danger {
color: red;
}
</style>
加入我们删除中括号[]:
javascript
<div :class="[{ activeClass: isActive }, errorClass]">绑定样式类</div>

1.3 组件上使用
1.3.1 单个根元素子组件添加 class 时,会直接合并
子组件:
javascript
<template>
<!-- 子组件模板 -->
<p class="foo bar">Hi!</p>
</template>
<script setup>
</script>
<style lang="scss" scoped></style>
父组件:
javascript
<template>
<!-- 在使用组件时,添加额外的class -->
<MyComponent class="baz boo" />
</template>
<script setup>
import MyComponent from '@/components/MyComponent.vue'
</script>
<style scoped>
</style>

1.3.2 多个根元素子组件添加 class 时,指定根元素合并
1.3.2.1 指定单个根元素接收 class(可以)
多个根元素的子组件(指定添加class的根元素):
javascript
<template>
<!-- MyComponent 模板使用 $attrs 时 -->
<p :class="$attrs.class">Hi!</p>
<span>This is a child component</span>
</template>
<script setup>
</script>
<style lang="scss" scoped></style>
父组件:
javascript
<template>
<!-- 在使用组件时,添加额外的class -->
<MyComponent class="baz" />
</template>
<script setup>
import MyComponent from '@/components/MyComponent.vue'
</script>
<style scoped>
</style>
1.3.2.1 指定多个根元素接收 class(可以)
官方给出的例子,只告诉我们 如何让多个根元素组件中的一个根元素接收class。
但是通过观察,不难发现,$attr.class
是指定一个属性class暴露给外部。那么,我们不同根组件指定不同的 attr 名称暴露给外部,不就可以实现多个根元素接收class了吗?让我们尝试一下。
子组件多个根元素 class
暴露给不同attr:
javascript
<template>
<!-- MyComponent 模板使用 $attrs 时 -->
<p :class="$attrs.pClass">Hi!</p>
<span :class="$attrs.spanClass">This is a child component</span>
</template>
<script setup>
</script>
<style lang="scss" scoped></style>
父组件给子组件暴露出的多个 attr
分别进行赋值
2. 绑定内联样式
2.1 绑定对象
2.1.1 绑定单个属性值(不推荐变量多时使用,模板代码不够整洁)
javascript
<template>
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }">hello world</div>
</template>
<script setup>
import { ref } from 'vue'
const activeColor = ref('red')
const fontSize = ref(30)
</script>
<style scoped></style>
2.1.2 绑定整个对象(模板更加整洁)
javascript
<template>
<div :style="styleObject">hello world</div>
</template>
<script setup>
import { reactive } from 'vue'
const styleObject = reactive({
color: 'red',
fontSize: '30px'
})
</script>
<style scoped></style>
2.2 绑定数组(更好操控每组样式)
javascript
<template>
<div :style="styleArr">使用数组绑定内联样式</div>
</template>
<script setup>
import { ref, reactive } from 'vue'
const styleObj = reactive({
color: 'red',
fontSize: '30px'
})
const styleObj2 = reactive({
textDecoration: 'underline'
})
const styleArr = ref([styleObj, styleObj2])
setTimeout(() => {
styleArr.value.pop()
}, 3000)
</script>
<style lang="scss" scoped></style>

3s 后
通过这种绑定数组的方式,可以很方便地操作一组样式。
3. 最佳实践建议
3.1 先掌握其中一种,不合适再看其他方式
其实对于初学者而言,不必在多种class绑定方式之中过多纠结。我的建议是,优先熟练使用其中一种,比如 1.1.2 将多个 class 绑定在一个对象变量中:
javascript
<template>
<div class="demo" :class="classObject">
绑定样式类
</div>
</template>
<script setup>
import { reactive } from 'vue'
const classObject = reactive({
active: true,
'text-danger': false
})
setTimeout(() => {
classObject['text-danger'] = true
}, 3000)
</script>
<style scoped>
.text-danger {
color: red;
}
</style>
在绝大多数情况下,这种绑定方式尤为清晰整洁。
当然,不能一概而论,当不同class需要在不同的html元素中自由组合时,则 1.1.1 直接用法 则可能更为合适。
javascript
<template>
<div
class="demo"
:class="{
active: isActive,
'text-danger': hasError
}"
>
绑定样式类
</div>
</template>
<script setup>
import { ref } from 'vue'
const isActive = ref(true)
const hasError = ref(false)
setTimeout(() => {
hasError.value = true
}, 3000)
</script>
<style scoped>
.text-danger {
color: red;
}
</style>
只要熟练掌握其中一种,在遇到不合适的时候,再回头看看其他绑定方式,更加便捷时即可进行替换。
3.2 属性名称 推荐驼峰式命名
Vue3 官方推荐使用 camelCase
(驼峰式命名)来书写 CSS
的属性key
,比如:
javascript
<div :style="{ fontSize: fontSize + 'px' }"></div>
虽然 Vue3 也支持 kebab-cased 形式的 CSS 属性 key (对应其 CSS 中的实际名称),例如:
html
<div :style="{ 'font-size': fontSize + 'px' }"></div>
但很明显 fontSize
比 font-size
书写更加方便直观。
上一章 《Vue3 计算属性》
下一章 《Vue3 条件渲染》