Vue 3 核心进阶:深度解析计算属性 (Computed)
在 Vue 3 的 Composition API 中,computed 是最常用且最强大的响应式工具之一。它不仅能简化模板逻辑,还能通过缓存机制极大地优化应用性能。
一、 什么是计算属性?
计算属性(Computed Properties)本质上是一个响应式的派生值。它可以基于一个或多个响应式引用(ref 或 reactive)进行计算,并返回一个新的只读或可读写的响应式对象。
核心特性:
- 声明式逻辑:将复杂的逻辑从模板(Template)中抽离。
- 响应式依赖追踪:Vue 会自动追踪计算属性用到了哪些响应式数据。
- 缓存(Caching):这是它与普通函数最大的区别。计算属性会基于它们的响应式依赖进行缓存。只有在相关依赖发生改变时它们才会重新求值。
二、 基础用法:只读计算属性
在 <script setup> 中,我们从 vue 包中导入 computed 函数。最常见的用法是传入一个 getter 函数。
<script setup>
import { ref, computed } from 'vue'
const count = ref(0)
const price = ref(100)
// 创建一个计算属性:总价
// 只有当 count 或 price 改变时,totalPrice 才会重新计算
const totalPrice = computed(() => {
console.log('计算中...') // 测试缓存:多次访问模板,此行只打印一次
return count.value * price.value
})
const increment = () => count.value++
</script>
<template>
<div>
<p>单价: {{ price }} | 数量: {{ count }}</p>
<p>总价 (计算属性): {{ totalPrice }}</p>
<button @click="increment">增加数量</button>
</div>
</template>
三、 进阶用法:可写计算属性 (Getter & Setter)
虽然计算属性默认是只读的,但在某些场景(如:双向绑定 V-Model)下,你可能需要修改它。这时可以传入一个带有 get 和 set 函数的对象。
<script setup>
import { ref, computed } from 'vue'
const firstName = ref('张')
const lastName = ref('三')
/**
* 核心逻辑:可读写的计算属性
*/
const fullName = computed({
// 1. getter: 当读取 fullName.value 时触发
// 依赖项 firstName 或 lastName 改变,它会自动更新
get() {
return firstName.value + ' ' + lastName.value
},
// 2. setter: 当手动给 fullName.value 赋值时触发 (例如 v-model 改变了它)
// 参数 newValue 是用户输入的最新的全名字符串
set(newValue) {
// 简单的解析逻辑:按空格拆分姓和名
const names = newValue.split(' ')
firstName.value = names[0] || ''
lastName.value = names[1] || ''
console.log('Setter 触发,新值已同步至响应式源数据')
}
})
</script>
<template>
<label>姓 (First Name): </label>
<input v-model="firstName" type="text" /><br/>
<label>名 (Last Name): </label>
<input v-model="lastName" type="text" /><br/>
<label><strong>全名 (Full Name - 可编辑): </strong></label>
<input v-model="fullName" type="text" class="full-name-input" /><br/>
<p>当前状态预览:</p>
<code>{ "firstName": "{{ firstName }}", "lastName": "{{ lastName }}" }</code>
</template>
四、 计算属性 vs 监听器 vs 函数
| 特性 | 计算属性 (Computed) | 监听器 (Watch) | 普通函数 (Methods) |
|---|---|---|---|
| 目的 | 派生出新状态(1变N/N变1) | 执行副作用(如 API 请求、DOM 操作) | 响应事件或处理临时逻辑 |
| 缓存 | 有 | 无 | 无 |
| 返回值 | 必须有返回值 | 通常没有返回值 | 视情况而定 |
| 懒执行 | 依赖不变不执行 | 默认立即执行或改变时执行 | 每次调用都执行 |
五、 最佳实践与注意事项
1. 避免副作用
计算属性的 getter 应该只做纯计算。不要在计算属性中修改 DOM、发起异步请求或修改其他的响应式状态。如果有这些需求,请使用 watch。
2. 不要直接修改计算属性的返回值
除非你定义了 set,否则计算属性应该是“只读”的快照。应该修改它依赖的源数据来触发更新。
3. 性能优化
如果一个复杂的计算逻辑在页面中被多次引用,请务必使用计算属性而不是函数。缓存机制能避免重复的 CPU 消耗。
六、 实战案例:列表搜索过滤
下面是通过搜索用户的 Demo,展示了 computed 如何简化逻辑:
<script setup>
import { ref, computed } from 'vue'
const searchText = ref('')
const users = ref([
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 3, name: 'Charlie' }
])
// 过滤后的列表:自动随输入内容变化
const filteredUsers = computed(() => {
return users.value.filter(user =>
user.name.toLowerCase().includes(searchText.value.toLowerCase())
)
})
</script>
<template>
<input v-model="searchText" placeholder="搜索用户..." />
<ul>
<li v-for="user in filteredUsers" :key="user.id">{{ user.name }}</li>
</ul>
</template>

浙公网安备 33010602011771号