Vue3 computed 属性(手把手讲解)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观
前言:为什么需要学习 Vue3 computed 属性?
在前端开发领域,Vue.js 作为主流框架之一,其响应式系统一直是开发者关注的核心特性。Vue3 作为 Vue.js 的重大升级版本,引入了 Composition API 和大量性能优化。在众多新特性中,computed
属性(计算属性)因其高效、简洁的特性,成为构建复杂 UI 逻辑的重要工具。
对于编程初学者而言,理解 computed
属性可以帮助快速掌握 Vue3 的响应式原理;而中级开发者则可以通过深入分析其底层机制,优化代码性能,提升开发效率。本文将通过循序渐进的方式,结合代码示例和实际场景,带您全面掌握 computed
属性的使用与原理。
一、基础概念:什么是 Vue3 computed 属性?
1.1 计算属性的定义与作用
计算属性(Computed Property) 是 Vue3 中用于处理响应式数据的函数,其核心作用是根据其他响应式数据的值,动态生成新的值。与普通方法不同,计算属性具有以下特点:
- 依赖追踪:自动追踪被访问的响应式数据
- 缓存机制:仅在依赖数据变化时重新计算
- 响应式输出:输出值会自动触发视图更新
形象比喻:可以将计算属性视为一个“智能计算器”。例如,当需要计算购物车总价时,计算属性会自动跟踪商品数量和单价的变化,并在数据变动时重新计算总价,而非每次渲染都执行计算。
1.2 基本语法与声明方式
在 Vue3 中,computed
属性主要通过 computed
函数或 setup
语法糖进行声明。以下是两种常见写法:
方法一:使用 computed
函数
import { ref, computed } from 'vue';
export default {
setup() {
const price = ref(100);
const quantity = ref(2);
const total = computed(() => price.value * quantity.value);
return {
price,
quantity,
total
};
}
}
方法二:组合式 API 的 computed
属性
import { ref, computed } from 'vue';
export default {
setup() {
const price = ref(100);
const quantity = ref(2);
const total = computed({
get() {
return price.value * quantity.value;
},
set(newValue) {
// 可选:设置双向绑定逻辑
}
});
return {
price,
quantity,
total
};
}
}
1.3 计算属性与方法的区别
特性 | 计算属性(Computed) | 普通方法(Methods) |
---|---|---|
依赖追踪 | 自动追踪响应式数据变化 | 需手动触发或依赖事件 |
缓存机制 | 仅在依赖变化时重新计算 | 每次调用都会执行 |
使用场景 | 需要频繁读取且依赖稳定的数据 | 处理一次性或无依赖的逻辑 |
响应式输出 | 输出值自动更新视图 | 需手动触发更新 |
二、核心原理:Vue3 computed 的响应式机制
2.1 依赖追踪的实现原理
Vue3 的响应式系统基于 Proxy 对象实现,而 computed
属性的依赖追踪分为以下步骤:
- 依赖收集:当计算属性被访问时,Vue3 会记录当前被访问的响应式数据
- 触发更新:当被记录的响应式数据变化时,计算属性会重新执行并更新缓存值
- 视图更新:新值会自动触发依赖该计算属性的组件视图重渲染
形象比喻:就像快递员跟踪包裹状态,计算属性会持续关注其依赖的数据变化。当包裹(数据)状态更新时,计算属性会立即重新计算物流信息(新值)并通知收件人(视图)。
2.2 缓存机制的性能优势
计算属性的缓存特性使其在复杂场景中表现优异。例如,当需要对大量数据进行聚合计算时:
// 假设有一个包含1000条商品的数组
const products = ref([{ price: 100 }, { price: 200 }, ...]);
// 普通方法(无缓存)
const total = () => {
return products.value.reduce((sum, item) => sum + item.price, 0);
};
// 计算属性(有缓存)
const totalComputed = computed(() =>
products.value.reduce((sum, item) => sum + item.price, 0)
);
当 products
数组未被修改时,调用 totalComputed.value
会直接返回缓存值,避免重复执行计算密集型操作。
2.3 响应式输出的实现
计算属性的值会被包装为响应式对象,其依赖的组件视图会自动订阅该值的变化。例如:
<template>
<div>Total: {{ totalComputed }}</div>
</template>
当 totalComputed
的值变化时,Vue3 的渲染系统会自动更新对应 DOM 内容。
三、使用场景与最佳实践
3.1 常见应用场景
场景一:动态数据聚合
const items = ref([10, 20, 30]);
const sum = computed(() => items.value.reduce((a, b) => a + b, 0));
场景二:条件过滤
const users = ref([{ active: true }, { active: false }, ...]);
const activeUsers = computed(() =>
users.value.filter(user => user.active)
);
场景三:格式化数据
const birthDate = ref('1990-01-01');
const formattedDate = computed(() =>
birthDate.value.split('-').reverse().join('/')
);
3.2 高级技巧与注意事项
技巧一:结合 watchEffect
实现双向绑定
const originalText = ref('');
const formattedText = computed({
get() {
return originalText.value.toUpperCase();
},
set(newValue) {
originalText.value = newValue.toLowerCase();
}
});
技巧二:避免副作用与复杂计算
- 避免副作用:计算属性应仅依赖响应式数据,避免包含网络请求或DOM操作
- 拆分复杂逻辑:当计算涉及多层依赖时,建议拆分为多个计算属性
注意事项
- 避免循环依赖:多个计算属性互相依赖可能导致无限循环
- 合理使用
shallowRef
:当处理嵌套对象时,考虑使用shallowRef
优化性能
四、实际案例:构建带搜索功能的 Todo List
4.1 需求分析
实现一个包含以下功能的 Todo List:
- 输入框添加待办事项
- 搜索框过滤待办事项
- 显示已完成/未完成的统计信息
4.2 代码实现
import { ref, computed } from 'vue';
export default {
setup() {
const todos = ref([]);
const newTodo = ref('');
const searchQuery = ref('');
// 添加待办事项
const addTodo = () => {
if (newTodo.value) {
todos.value.push({
text: newTodo.value,
completed: false
});
newTodo.value = '';
}
};
// 计算属性:过滤后的待办列表
const filteredTodos = computed(() =>
todos.value.filter(todo =>
todo.text.includes(searchQuery.value)
)
);
// 计算属性:统计已完成数量
const completedCount = computed(() =>
todos.value.filter(todo => todo.completed).length
);
return {
todos,
newTodo,
searchQuery,
addTodo,
filteredTodos,
completedCount
};
}
};
4.3 模板部分
<template>
<div>
<input v-model="newTodo" placeholder="输入新待办事项" />
<button @click="addTodo">添加</button>
<input v-model="searchQuery" placeholder="搜索待办事项" />
<ul>
<li v-for="todo in filteredTodos" :key="todo.text">
<input type="checkbox" v-model="todo.completed" />
{{ todo.text }}
</li>
</ul>
<p>已完成:{{ completedCount }} / {{ todos.length }}</p>
</div>
</template>
五、进阶话题:与其它特性结合使用
5.1 结合 watch
监听计算属性
import { watch } from 'vue';
watch(() => {
// 监听多个响应式数据
return [todos.value, searchQuery.value];
}, (newValues) => {
// 执行异步操作或数据持久化
});
5.2 在 provide/inject
中使用
// 父组件
const filteredTodos = computed(() => ...);
provide('filteredTodos', filteredTodos);
// 子组件
const filteredTodos = inject('filteredTodos');
5.3 结合 TypeScript 类型推导
const filteredTodos = computed<string[]>(() =>
todos.value.filter(todo => todo.text.includes(searchQuery.value))
);
结论:掌握 Vue3 computed 属性的实用价值
通过本文的讲解,我们系统学习了 Vue3 computed 属性的核心概念、实现原理及应用场景。以下是关键总结:
- 响应式计算:通过依赖追踪和缓存机制,实现高效的数据处理
- 代码简洁性:将复杂逻辑封装为声明式代码,提升可维护性
- 性能优化:避免重复计算,降低组件渲染开销
- 生态整合:与 Vue3 的其他特性(如
watch
、provide/inject
)无缝衔接
对于开发者而言,掌握 Vue3 computed 属性
是构建大型单页应用的必备技能。建议通过实际项目不断实践,结合本文案例深入理解其工作原理。当您需要动态计算、过滤或转换数据时,优先考虑使用计算属性,让代码更优雅、高效!
提示:本文通过代码示例和场景分析,系统讲解了 Vue3 computed 属性的使用方法与原理。建议读者在实际开发中多加实践,结合项目需求灵活运用这一强大工具。