4.1 computed概述
计算属性是 Vue 实例的一个选项,可以用来定义一个属性,该属性的值是经过计算后的结果。它的特点是:
1、依赖于其他的响应式属性
2、会进行缓存,只有在依赖发生变化时,才会重新计算
3、计算属性可以定义为一个函数,也可以定义为一个对象,包含 getter 和 setter
4.2 computed使用场景
这里举一个例子,例如页面上需要显示一个人的姓名,它是由firstName和lastName两个字段组合而成,我们的第一反应肯定是firstName+lastName就完事了。如以下代码:
<template>
<div class="person">
姓:<input type="text" v-model="firstName"> <br>
名:<input type="text" v-model="lastName"> <br>
全名:<span>{{firstName}}-{{lastName}}</span> <br>
</div>
</template>
<script lang="ts" setup name="Person">
import {ref} from 'vue'
let firstName = ref('zhang')
let lastName = ref('san')
</script>
如果这里添加一个需求,firstName首字母需要大写,这里只有两种解决方法,要么就是给firstName变量赋值的时候先进行处理,要么直接在html模板里处理,其实两种方式都不太好。
<template>
<div class="person">
姓:<input type="text" v-model="firstName"> <br>
名:<input type="text" v-model="lastName"> <br>
全名:<span>{{firstName.slice(0,1).toUpperCase() + firstName.slice(1)}}-{{ lastName }}</span> <br>
</div>
</template>
这样虽然实现了需求,但是违背了一个原则,Vue官方文档标明,尽可能让模板简化,也就是尽量不要涉及业务代码。
计算属性针对这些情况是非常友好的,我们可以使用一个计算属性fullName,将firstName与lastName整合,然后让模板读取,也可以把业务需求在计算属性里一并处理。
4.3 Vue2与Vue3语法对比
1、Vue2
在Vue2中,computed是一个对象,里面包含各个计算属性,它们都是一个函数。
computed: {
fullName() {
return firstName.value.slice(0,1).toUpperCase() + firstName.value.slice(1) + '-' + lastName.value
}
}
2、Vue3
在Vue3里使用computed要先import引入,而且computed里面传入一个回调函数。
<template>
<div class="person">
姓:<input type="text" v-model="firstName"> <br>
名:<input type="text" v-model="lastName"> <br>
全名:<span>{{fullName}}</span> <br>
</div>
</template>
<script lang="ts" setup>
import {ref,computed} from 'vue'
let firstName = ref('zhang')
let lastName = ref('san')
let fullName = computed(() => {
return firstName.value.slice(0,1).toUpperCase() + firstName.value.slice(1) + '-' + lastName.value
})
</script>
4.4 computed缓存特性
computed属性无论使用多少次,它只会计算一次,只要它依赖的变量没有发生变化,它就不会重新计算。
<template>
<div class="person">
姓:<input type="text" v-model="firstName"> <br>
名:<input type="text" v-model="lastName"> <br>
全名:<span>{{fullName}}</span> <br>
全名:<span>{{fullName}}</span> <br>
全名:<span>{{fullName}}</span> <br>
全名:<span>{{fullName}}</span> <br>
全名:<span>{{fullName}}</span> <br>
全名:<span>{{fullName}}</span> <br>
全名:<span>{{fullName}}</span> <br>
</div>
</template>
<script lang="ts" setup name="Person">
import {ref,computed} from 'vue'
let firstName = ref('zhang')
let lastName = ref('san')
// fullName是一个计算属性,且是只读的
let fullName = computed(()=>{
console.log('执行computed计算')
return firstName.value.slice(0,1).toUpperCase() + firstName.value.slice(1) + '-' + lastName.value
})
</script>
如果不使用computed计算属性,使用的是一个函数来计算返回,是没有缓存的,每使用一次就计算一次:
<template>
<div class="person">
姓:<input type="text" v-model="firstName"> <br>
名:<input type="text" v-model="lastName"> <br>
全名:<span>{{fullName2()}}</span> <br>
全名:<span>{{fullName2()}}</span> <br>
全名:<span>{{fullName2()}}</span> <br>
全名:<span>{{fullName2()}}</span> <br>
全名:<span>{{fullName2()}}</span> <br>
全名:<span>{{fullName2()}}</span> <br>
全名:<span>{{fullName2()}}</span> <br>
</div>
</template>
<script lang="ts" setup name="Person">
import {ref,computed} from 'vue'
let firstName = ref('zhang')
let lastName = ref('san')
function fullName2() {
console.log('执行函数计算')
return firstName.value.slice(0,1).toUpperCase() + firstName.value.slice(1) + '-' + lastName.value
}
</script>
4.5 computed的get与set
computed计算属性如果传入回调函数,那么它是一个只读属性,不能修改。我们可以做一个尝试,写一个方法直接给fullName进行赋值:
<template>
<div class="person">
姓:<input type="text" v-model="firstName"> <br>
名:<input type="text" v-model="lastName"> <br>
全名:<span>{{fullName}}</span> <br>
<button @click="changeFullName">将全名改为li-si</button> <br>
</div>
</template>
<script lang="ts" setup name="Person">
import {ref,computed} from 'vue'
let firstName = ref('zhang')
let lastName = ref('san')
// fullName是一个计算属性,且是只读的
let fullName = computed(()=>{
return firstName.value.slice(0,1).toUpperCase() + firstName.value.slice(1) + '-' + lastName.value
})
function changeFullName(){
fullName.value = 'li-si'
}
</script>
其实在vscode的代码编辑器已经有非常友好的提示:你不能给它赋值,因为它是一个只读属性。在浏览器控制台也一样会提示:这个计算属性的value值是一个只读属性。
如果我们想定义一个可读可写的computed属性,那就不要传回调函数,而是传一个对象,里面包含get和set两个方法:
1、get方法:get方法比较简单,它其实就是显示在模板的内容,也就是我们刚才写回调函数return的内容。
2、set方法:
set方法在你修改这个计算属性的时候它就会执行,它会把最新的值接收回来。我们知道,想让computed重新计算,实际上是让它所依赖的变量发生改变,那么我们只需要在set方法里把它依赖的变量重新赋值,即可重新计算最新值。
例如刚才的例子,我们在set方法拿到最新值之后,将fullName所依赖的firstName和lastName进行赋值,就可以更新fullName属性了。
<template>
<div class="person">
姓:<input type="text" v-model="firstName"> <br>
名:<input type="text" v-model="lastName"> <br>
全名:<span>{{fullName}}</span> <br>
<button @click="changeFullName">将全名改为li-si</button> <br>
</div>
</template>
<script lang="ts" setup name="Person">
import {ref,computed} from 'vue'
let firstName = ref('zhang')
let lastName = ref('san')
// fullName是一个计算属性,可读可写
let fullName = computed({
// 当fullName被读取时,get调用
get(){
return firstName.value.slice(0,1).toUpperCase() + firstName.value.slice(1) + '-' + lastName.value
},
// 当fullName被修改时,set调用,且会收到修改的值
set(val){
const [str1,str2] = val.split('-')
firstName.value = str1
lastName.value = str2
}
})
function changeFullName(){
fullName.value = 'li-si'
}
</script>