一、前言
大家都知道,在vue2中,除了可以使用watch去监听数据的变化之外,还有一个computedAPI,同样也可以通过计算数据的变化得到新的响应式数据,computedAPI也是我们vue2中经常使用的属性,而vue3也保留了这个API,但是他的变化却是非常大,这篇文章我们就来说说vue3中的computed的用法。
二、回顾vue2
在学习vue3中的用法之前,我们先来回顾下vue2中computed的用法。
在vue2中,computed和data同级配置,并且不可以和data中的数据同名,看下面的例子:
export default {
data() {
return {
firstName: 'Kobe',
lastName: 'Bryant',
}
},
// 注意这里定义的变量,都要通过函数的形式来返回它的值
computed: {
// 普通函数可以直接通过熟悉的 this 来拿到 data 里的数据
fullName() {
return `${this.firstName} ${this.lastName}`
},
// 箭头函数则需要通过参数来拿到实例上的数据
fullName2: (vm) => `${vm.firstName} ${vm.lastName}`,
}
}
这样的话你就可以通过this.fullName就可以在你需要的地方获取到全名了;
三、vue3中的computed
在vue3中,和其他API一样,使用前需要先导入,还是上面的例子,我们换成vue3的写法:
<script lang="ts">
import { defineComponent, computed, ref } from 'vue'
export default defineComponent({
setup() {
const firstName = ref<string>('Kobe')
const lastName = ref<string>('Bryant')
const fullName = computed(() => {
return `${firstName.value} ${lastName.value}`
})
setTimeout(() => {
firstName.value = 'Tony'
console.log(fullName.value) // 'Kobe Bryant'
}, 3000)
return {
fullName,
}
},
})
</script>
在vue3中,computed的这种用法其实可以理解为传入一个回调函数,然后return一个值,而且是强制的,必须要有一个明确的返回值;
同时还需要注意的是,我们定义的computed变量和ref变量的用法一样,都需要使用.value去获取值,区别在于,computed变量是只读的;
类型定义
因为在defineComponent里,会自动帮我们推导vueAPI的类型,所以一般情况下,我们不需要显示的去定义computed出来的变量的类型,如果确实需要手动指定的情况下,你也可以导入它的类型然后定义:
import { computed } from 'vue'
import type { ComputedRef } from 'vue'
// 注意这里添加了类型定义
const fullName: ComputedRef<string> = computed(
() => `${firstName.value} ${lastName.value}`
)
像上面那样,如果你需要返回一个字符串,就写ComputedRef<string>,需要返回一个布尔值就写ComputedRef<boolean>,如果需要返回自定义类型,可以先定义好类型,如ComputedRef<UserInfo>等;
前面提到过,computed定义的变量是只读的,想必你也想知道为什么它是只读的,我们看ComputedRef的类型定义就知道了:
// 这是 ComputedRef 的类型定义:
export declare interface ComputedRef<T = any> extends WritableComputedRef<T> {
readonly value: T;
[ComoutedRefSymbol]: true;
}
由上可知,ComputedRef接口继承了只读的接口WriteComputedRef,所以它是只读的。
setter的使用
上面讲到,computed变量是只读的,但是在必要的情况下,我们可以使用setter属性来更新数据;
当我们需要使用setter的时候,就不能再传入一个回调函数了,而是需要传入一个带有两个方法的对象:
export default defineComponent({
setup() {
// 定义一个响应式变量
const name = ref<string>('Kobe')
const computedName = computed({
get() {
return name.value
},
set(value) {
computedName.value = value
},
})
return {
computedName,
}
},
})
这里的get就是computed的getter,跟原来传入的callback形式一样,必须要有明确的返回值用于computedName.value读取,set就是computed的setter,它接受一个参数,代表新的值,然后通过上面的形式赋值,需要注意的是,上面的get和set方法名是固定的,不可以换成其他的。
应用场景
对于计算属性,官网值举了一个非常简单的例子,在实际项目中,在什么样的情况下使用它会让我们更方便呢?可以简单的举几个例子:
数据的拼接和计算
正如我们上面的例子提到的一样,如果我们很多地方都要使用多个变量拼接或者求和等其他操作的情况下,我们就可以使用计算属性,比如购物车,购物车内有商品列表,同时还小于计算购物车内的商品中金额,这种情况就特别适合使用计算属性;
获取多级对象的值
比如我们经常要在template显示一些多级对象的字段,但是又可能存在某些字段不一定有,需要做一些判断,这个时候虽然我们呢可以使用v-if,但是如果嵌套的层级多的话,我们的模板就很难以维护了。
这个时候我们就可以使用计算属性,结合try/catch,这样就就不用再template做很多判断了:
const foo = computed(() => {
// 正常情况下返回需要的数据
try {
return store.state.foo3.foo2.foo1.foo
}
// 处理失败则返回一个默认值
catch (e) {
return ''
}
})
这样你在 template 里要拿到foo的值,完全不需要关心中间一级又一级的字段是否存在,只需要区分是不是默认值。
不同类型的数据转换
有时候你会遇到一些需求类似于,让用户在输入框里,按一定的格式填写文本,比如用英文逗号 , 隔开每个词,然后保存的时候,是用数组的格式提交给接口。
这个时候 computed 的 setter 就可以妙用了,只需要一个简单的 computed ,就可以代替 input 的 change 事件或者 watch 监听,可以减少很多业务代码的编写。
<template>
<input
type="text"
v-model="tagsStr"
placeholder="请输入标签,多个标签用英文逗号隔开"
/>
</template>
<script lang="ts">
import { defineComponent, computed, ref } from 'vue'
export default defineComponent({
setup() {
// 这个是最终要用到的数组
const tags = ref<string[]>([])
// 因为input必须绑定一个字符串
const tagsStr = computed({
// 所以通过getter来转成字符串
get() {
return tags.value.join(',')
},
// 然后在用户输入的时候,切割字符串转换回数组
set(newValue: string) {
tags.value = newValue.split(',')
},
})
return {
tagsStr,
}
},
})
</script>
四、总结
以上就是vue3中computed的用法了,总的来说变化还是很大的,不过用起来还是方便不少,同样的,内容还是比较基础,希望对大家有帮助。