03Vue3 计算属性详解及用法
一、什么是计算属性
计算属性是Vue3中用于声明式地处理响应式数据计算的特性。它基于依赖的响应式数据自动缓存计算结果,只有当依赖变化时才会重新计算。
二、基本用法
1. 使用 computed 函数
import { ref, computed } from 'vue'
// 创建响应式数据
const count = ref(0)
const price = ref(100)
// 创建计算属性
const total = computed(() => {
return count.value * price.value
})
// 使用计算属性
console.log(total.value) // 0
count.value = 2
console.log(total.value) // 200
2. 在组件中使用
<template>
<div>
<input v-model.number="count" type="number">
<input v-model.number="price" type="number">
<p>总价: {{ total }}</p>
<p>含税价: {{ totalWithTax }}</p>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const count = ref(1)
const price = ref(100)
const taxRate = ref(0.1)
// 计算总价
const total = computed(() => count.value * price.value)
// 计算含税价(依赖于另一个计算属性)
const totalWithTax = computed(() => total.value * (1 + taxRate.value))
</script>
三、计算属性的特性
1. 响应式依赖追踪
import { ref, computed, watchEffect } from 'vue'
const a = ref(1)
const b = ref(2)
const sum = computed(() => a.value + b.value)
// 当a或b变化时,sum会自动更新
watchEffect(() => {
console.log('sum changed:', sum.value)
})
a.value = 3 // 触发更新
b.value = 4 // 触发更新
2. 缓存机制
const expensiveCalculation = computed(() => {
console.log('计算中...')
return Date.now() // 假设这是昂贵的计算
})
console.log(expensiveCalculation.value) // 输出"计算中..."并返回时间戳
console.log(expensiveCalculation.value) // 直接返回缓存值,不输出"计算中..."
四、可写的计算属性
<template>
<div>
<input v-model="firstName">
<input v-model="lastName">
<p>全名: {{ fullName }}</p>
<button @click="updateName('张', '三')">设置为张三</button>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const firstName = ref('李')
const lastName = ref('四')
// 可写的计算属性
const fullName = computed({
// getter
get() {
return `${firstName.value} ${lastName.value}`
},
// setter
set(newValue) {
const [first, last] = newValue.split(' ')
firstName.value = first
lastName.value = last
}
})
// 使用方法
function updateName(first, last) {
fullName.value = `${first} ${last}`
}
</script>
五、计算属性 vs 方法
<template>
<div>
<!-- 使用计算属性(有缓存) -->
<p>计算属性结果: {{ reversedMessage }}</p>
<p>计算属性结果: {{ reversedMessage }}</p> <!-- 不会重新计算 -->
<!-- 使用方法(每次都会执行) -->
<p>方法结果: {{ reverseMessage() }}</p>
<p>方法结果: {{ reverseMessage() }}</p> <!-- 每次都会执行 -->
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const message = ref('Hello Vue3')
// 计算属性
const reversedMessage = computed(() => {
console.log('计算属性执行')
return message.value.split('').reverse().join('')
})
// 方法
function reverseMessage() {
console.log('方法执行')
return message.value.split('').reverse().join('')
}
</script>
六、计算属性 vs 侦听器
<template>
<div>
<input v-model="firstName">
<input v-model="lastName">
<!-- 使用计算属性(推荐) -->
<p>全名(计算属性): {{ fullName }}</p>
<!-- 使用侦听器实现相同功能 -->
<p>全名(侦听器): {{ watchedFullName }}</p>
</div>
</template>
<script setup>
import { ref, computed, watch } from 'vue'
const firstName = ref('李')
const lastName = ref('四')
// 方案1:使用计算属性(简洁高效)
const fullName = computed(() => `${firstName.value} ${lastName.value}`)
// 方案2:使用侦听器(更复杂)
const watchedFullName = ref('')
watch([firstName, lastName], ([first, last]) => {
watchedFullName.value = `${first} ${last}`
}, { immediate: true })
</script>
七、高级用法
1. 组合式计算属性
import { ref, computed } from 'vue'
const items = ref([
{ id: 1, name: '商品A', price: 100, quantity: 2 },
{ id: 2, name: '商品B', price: 200, quantity: 1 },
{ id: 3, name: '商品C', price: 150, quantity: 3 }
])
// 多个计算属性组合
const totalItems = computed(() =>
items.value.reduce((sum, item) => sum + item.quantity, 0)
)
const totalPrice = computed(() =>
items.value.reduce((sum, item) => sum + item.price * item.quantity, 0)
)
const averagePrice = computed(() =>
totalItems.value > 0 ? totalPrice.value / totalItems.value : 0
)
2. 在组合式函数中使用
// useCart.js import { ref, computed } from 'vue' export function useCart() { const cartItems = ref([]) const cartTotal = computed(() => cartItems.value.reduce((sum, item) => sum + item.price * item.quantity, 0) ) const itemCount = computed(() => cartItems.value.reduce((sum, item) => sum + item.quantity, 0) ) const hasItems = computed(() => cartItems.value.length > 0) return { cartItems, cartTotal, itemCount, hasItems } }
3. 性能优化:减少不必要的计算
<script setup> import { ref, computed, watchEffect } from 'vue' const list = ref([1, 2, 3, 4, 5]) const filterThreshold = ref(3) // 避免在计算属性中执行昂贵的过滤操作 const filteredList = computed(() => { // 只有当list或filterThreshold变化时才重新计算 return list.value.filter(item => item > filterThreshold.value) }) // 计算属性的结果可以被多次使用而不重复计算 const listLength = computed(() => filteredList.value.length) const listSum = computed(() => filteredList.value.reduce((sum, item) => sum + item, 0) ) </script>
八、最佳实践
-
优先使用计算属性:当需要基于响应式数据计算新值时
-
保持纯函数:计算属性的getter应该是纯函数,没有副作用
-
避免修改依赖:不要在计算属性中修改它的依赖
-
合理使用缓存:对于开销大的计算,利用计算属性的缓存特性
-
命名清晰:使用描述性的名称,如
userFullName、totalPrice等
九、注意事项
-
异步操作:计算属性不能包含异步操作,如有需要应使用
watch或组合式函数 -
副作用:避免在计算属性中执行有副作用的操作
-
循环依赖:避免计算属性之间的循环依赖
-
深度监听:计算属性自动深度追踪其依赖,无需额外配置
总结
Vue3的计算属性是处理响应式数据计算的强大工具。它通过自动的依赖追踪和智能缓存,让代码更简洁、性能更高效。在实际开发中,合理使用计算属性可以显著提升代码的可维护性和应用性能。

浙公网安备 33010602011771号