前言
computed()
方法期望接收一个 getter 函数,返回值为一个计算属性 ref。和其他一般的 ref 类似,你可以通过 XXX.value
访问计算结果。计算属性 ref 也会在模板中自动解包,因此在模板表达式中引用时无需添加 .value
。
基本使用
先看一下以下代码
import {ref, computed } from 'https://cdn.bootcdn.net/ajax/libs/vue/3.3.4/vue.esm-browser.js'
let template = `
<table>
<tr>
<td>单价</td>
<td>数量</td>
<td>总额</td>
</tr>
<tr>
<td v-on:click='unit_price++'>{{unit_price}}</td>
<td v-on:click='quantity++'>{{quantity}}</td>
<td>{{total_price}}</td>
</tr>
</table>
`
export default {
setup: function () {
let unit_price = ref(11)
let quantity = ref(90)
let total_price = unit_price.value * quantity.value
return {unit_price, quantity, total_price}
},
template
}
如上,我们有两个响应式数据unit_price和quantity,还有一个总价total_price是这两个响应式数据相乘得出来的,在组件挂载时我们能看到total_price的正确结果990,但当我们通过点击unit_price或quantity改变响应式数据时,total_price却未能同步进行更新。
可能你会觉得在模板直接写逻辑不就好了吗,就像
<td>{{unit_price*quantity}}</td>
确实,这样也行,但如果逻辑较多较复杂的情况下,会让模板变得臃肿,难以维护。
因此我们推荐使用计算属性来描述依赖响应式状态的复杂逻辑。
import { ref, computed } from 'https://cdn.bootcdn.net/ajax/libs/vue/3.3.4/vue.esm-browser.js'
setup: function () {
let unit_price = ref(11)
let quantity = ref(90)
let total_price = computed(() => unit_price.value * quantity.value)
return {unit_price, quantity, total_price}
}
这样,无论我们改变unit_price还是quantity,total_price都能侦听到变化进行更新。
Vue 的计算属性会自动追踪响应式依赖。它会检测到 total_price
依赖于 unit_price
和quantity
,所以当二者改变时,任何依赖于 total_price
的绑定都会同时更新。
修改计算属性
其实,像上面那样子直接给computed传一个getter函数只能获取到计算属性的值,要想修改计算属性的值,需要给computed传一个对象,这个对象由一个getter函数和一个setter函数组成,通过setter函数我们就可以修改计算属性了。
<tr>
<td v-on:click='unit_price++'>{{unit_price}}</td>
<td v-on:click='quantity++'>{{quantity}}</td>
<td v-on:click='total_price=0'>{{total_price}}</td>
</tr>
setup: function () {
let unit_price = ref(11)
let quantity = ref(90)
let total_price = computed({
get: () => unit_price.value * quantity.value,
set: (newValue) => [unit_price.value, quantity.value] = [newValue, newValue]
})
return { unit_price, quantity, total_price }
}
当我们单击页面上总价的数值时,就会给total_price赋值为0,然后继续把0赋值给unit_price和quantity,就达到了结果清零的效果。计算属性返回的值是派生状态,更改它是没有意义的,应该更新它所依赖的源状态以触发新的计算。
使用计算属性的注意事项
-
不要改变其他状态、不要在 getter 中做异步请求或者更改 DOM!
-
计算属性描述的是如何根据其他值派生一个值。因此 getter 的职责应该仅为计算和返回该值。