Vue3的计算属性——computed
在日常开发中我们可能会有这样的需求,当页面中某个变量发生改变时要同时修改另一个变量的值。一般我们会通过监听器或者回调事件的方式来实现同步更改,但是如果修改次数过多,内容复杂时就会导致代码冗余。为了解决这一问题,Vue3提供了 computed 计算属性。computed属性在Vue3中是一个非常重要的响应式特性。它可以根据其他响应式数据的变化自动更新自身的值,无需手动操作。computed属性可以
前言
在日常开发中我们可能会有这样的需求,当页面中某个变量发生改变时要同时修改另一个变量的值。一般我们会通过监听器或者回调事件的方式来实现同步更改,但是如果修改次数过多,内容复杂时就会导致代码冗余。为了解决这一问题,Vue3提供了 computed 计算属性。
什么是 computed 计算属性
computed属性在Vue3中是一个非常重要的响应式特性。它可以根据其他响应式数据的变化自动更新自身的值,无需手动操作。computed属性可以接收一个函数作为参数,这个函数会在需要时被调用,并使用其他响应式数据的值进行计算。当任何参与计算的响应式数据发生变化时, computed 属性会自动重新计算其值,并触发相关的依赖项更新。这使得在Vue应用程序中处理复杂的逻辑和数据操作变得更加方便和高效。
computed计算属性的使用
<script setup>
import { reactive, computed } from 'vue'
const dept = reactive({
name: 'Department01',
stuffs: [
'Zhang San',
'Li Si',
'Wang Wu'
]
})
// 一个计算属性 ref
const numberofStuff = computed(() => {
//将dept变量中stuffs列表的长度赋值给numberofStuff
return dept.stuffs.length
})
</script>
<template>
<p>The number of stuff in Department01:</p>
<span>{{ numberofStuff }}</span>
</template>
上述代码中numberofStuff是一个记录了部门员工数量的计算属性,会随着dept的变化而变化。
注意点
默认只读
computed计算属性默认是只读的。当你尝试修改一个计算属性时,你会收到一个运行时警告。但在某些特殊的业务场景下需要我们实现对computed的手动修改,那么可以通过同时提供 getter 和 setter 来创建计算属性的可写方法。
<script setup>
import { ref, computed } from 'vue'
const firstName = ref('John')
const lastName = ref('Doe')
const fullName = computed({
// getter
get() {
return firstName.value + ' ' + lastName.value
},
// setter
set(newValue) {
// 注意:我们这里使用的是解构赋值语法
[firstName.value, lastName.value] = newValue.split(' ')
}
})
</script>
通过上述代码,可以实现通过对fullName的手动赋值修改firstName以及lastName的效果,使computed属性具备了可写能力。
Getter 不应有副作用
计算属性的 getter 应只做计算而没有任何其他的副作用,这一点非常重要,请务必牢记。举例来说,不要改变其他状态、在 getter 中做异步请求或者更改 DOM!一个计算属性的声明中描述的是如何根据其他值派生一个值。因此 getter 的职责应该仅为计算和返回该值。
避免直接修改计算属性值
从计算属性返回的值是派生状态。可以把它看作是一个“临时快照”,每当源状态发生变化时,就会创建一个新的快照。更改快照是没有意义的,因此计算属性的返回值应该被视为只读的,并且永远不应该被更改——应该更新它所依赖的源状态以触发新的计算。
使用场景
过滤和排序
当我们需要根据其他响应式数据进行数据过滤和排序时,可以使用 computed 属性来计算得出过滤和排序后的结果。例如:
<script setup>
import { computed, reactive } from 'vue'
const state = reactive({
todos: [
{ id: 1, text: '学习Vue3', done: false },
{ id: 2, text: '学习React', done: false },
{ id: 3, text: '学习Angular', done: true }
],
filter: 'all'
})
const filteredTodos = computed(() => {
if (state.filter === 'all') {
return state.todos
} else if (state.filter === 'active') {
return state.todos.filter(todo => !todo.done)
} else if (state.filter === 'completed') {
return state.todos.filter(todo => todo.done)
}
})
console.log(filteredTodos.value) // 输出:[{ id: 1, text: '学习Vue3', done: false }, { id: 2, text: '学习React', done: false }, { id: 3, text: '学习Angular', done: true }]
state.filter = 'active'
console.log(filteredTodos.value) // 输出:[{ id: 1, text: '学习Vue3', done: false }, { id: 2, text: '学习React', done: false }]
</script>
数组计算
当我们需要对一个数组进行计算时,可以使用computed
属性来计算得出数组的值。例如:
<script setup>
import { computed, reactive } from 'vue'
const state = reactive({
todos: [
{ id: 1, text: '学习Vue3', done: false },
{ id: 2, text: '学习React', done: false },
{ id: 3, text: '学习Angular', done: true }
]
})
const totalTodos = computed(() => {
return state.todos.length
})
const completedTodos = computed(() => {
return state.todos.filter(todo => todo.done).length
})
console.log(totalTodos.value) // 输出:3
console.log(completedTodos.value) // 输出:1
</script>
计算属性缓存 vs 方法
比较下面两段代码:
// 一个计算属性 ref
const numberofStuff = computed(() => {
//将dept变量中stuffs列表的长度赋值给numberofStuff
return dept.stuffs.length
})
function getNumberofStuff(){
//函数返回dept变量中stuffs列表的长度
return dept.stuffs.length
}
它们分别使用了计算属性和函数方法来获取dept变量下stuffs的列表长度。两种方式在结果上确实是完全相同的,然而,不同之处在于计算属性值会基于其响应式依赖被缓存。也就是说一个计算属性仅会在其响应式依赖更新时才重新计算。这意味着只要目标变量不发生变化就不会重复执行 getter 函数。相比之下,方法调用总是会在重渲染发生时再次执行函数。
当需要拼接生成一个非常耗性能的复杂列表时,相较于函数方法使用计算属性可以大幅提升代码运行效率。
更多推荐
所有评论(0)