一、计算属性的基本概念与核心价值
在Vue 3中,计算属性(Computed Property)是依赖响应式数据动态计算得出的衍生值,它的核心价值在于缓存机制——只有当依赖的响应式数据发生变化时,计算属性才会重新计算结果;否则直接复用之前的缓存值。这与方法(Method)的本质区别在于:方法每次调用都会重新执行函数体,而计算属性仅在依赖更新时“按需计算”。
举个生活中的类比:计算属性就像你手机里的“今日步数”——它依赖手机传感器的步数数据(响应式依赖),只有当你走路时(依赖变化),步数才会更新;而不是你每次打开APP都重新计算(像方法那样重复执行)。
二、Options API:计算属性的传统定义方式
Options API是Vue 2的经典语法,在Vue 3中依然兼容。它通过组件选项中的computed字段定义计算属性,语法遵循“选项式”组织逻辑。
1. 基础语法:函数式定义
在computed选项中,计算属性以函数形式声明,函数的返回值即为计算结果。函数内通过this访问组件实例的响应式数据(如data、props等)。
<script>
export default {
data() {
return {
firstName: 'John', // 响应式数据
lastName: 'Doe' // 响应式数据
}
},
computed: {
// 定义计算属性fullName
fullName() {
// this指向当前组件实例,可访问data中的属性
return this.firstName + ' ' + this.lastName
}
}
}
</script>
<template>
<p>全名:{{ fullName }}</p> <!-- 渲染结果:John Doe -->
</template>
关键说明:
- 计算属性会被挂载到组件实例上,模板中可直接通过
{{ fullName }}访问。 - 当
firstName或lastName变化时,fullName会自动重新计算。
2. 进阶:getter与setter
默认情况下,计算属性是只读的(仅包含getter)。若需要让计算属性支持双向绑定(即可以赋值),可通过get和set方法定义“读写型”计算属性。
<script>
export default {
data() {
return {
firstName: 'John',
lastName: 'Doe'
}
},
computed: {
fullName: {
// getter:读取fullName时执行
get() {
return this.firstName + ' ' + this.lastName
},
// setter:给fullName赋值时执行
set(newValue) {
// 将新值拆分为 firstName 和 lastName
const [first, last] = newValue.split(' ')
this.firstName = first
this.lastName = last
}
}
}
}
</script>
<template>
<input v-model="fullName" /> <!-- 输入“Jane Smith”,会触发setter -->
<p> firstName: {{ firstName }} </p> <!-- 输出:Jane -->
<p> lastName: {{ lastName }} </p> <!-- 输出:Smith -->
</template>
关键说明:
get方法用于计算并返回计算属性的值;set方法接收赋值的新值,可反向更新依赖的响应式数据。
三、Composition API:计算属性的现代定义方式
Composition API是Vue 3的新增语法,通过函数调用的方式组织逻辑,更适合复杂组件的逻辑拆分与复用。定义计算属性需使用computed函数(从vue中导入)。
往期文章归档
- Vue浅响应式如何解决深层响应式的性能问题?适用场景有哪些? - cmdragon's Blog
- Vue浅响应式如何解决深层响应式的性能问题?适用场景有哪些? - cmdragon's Blog
- Vue 3组合式API中ref与reactive的核心响应式差异及使用最佳实践是什么? - cmdragon's Blog
- Vue 3组合式API中ref与reactive的核心响应式差异及使用最佳实践是什么? - cmdragon's Blog
- Vue3响应式系统中,对象新增属性、数组改索引、原始值代理的问题如何解决? - cmdragon's Blog
- Vue 3中watch侦听器的正确使用姿势你掌握了吗?深度监听、与watchEffect的差异及常见报错解析 - cmdragon's Blog
- Vue响应式声明的API差异、底层原理与常见陷阱你都搞懂了吗 - cmdragon's Blog
- Vue响应式声明的API差异、底层原理与常见陷阱你都搞懂了吗 - cmdragon's Blog
- 为什么Vue 3需要ref函数?它的响应式原理与正确用法是什么? - cmdragon's Blog
- Vue 3中reactive函数如何通过Proxy实现响应式?使用时要避开哪些误区? - cmdragon's Blog
- Vue3响应式系统的底层原理与实践要点你真的懂吗? - cmdragon's Blog
- Vue 3模板如何通过编译三阶段实现从声明式语法到高效渲染的跨越 - cmdragon's Blog
- 快速入门Vue模板引用:从收DOM“快递”到调子组件方法,你玩明白了吗? - cmdragon's Blog
- 快速入门Vue模板里的JS表达式有啥不能碰?计算属性为啥比方法更能打? - cmdragon's Blog
- 快速入门Vue的v-model表单绑定:语法糖、动态值、修饰符的小技巧你都掌握了吗? - cmdragon's Blog
- 快速入门Vue3事件处理的挑战题:v-on、修饰符、自定义事件你能通关吗? - cmdragon's Blog
- 快速入门Vue3的v-指令:数据和DOM的“翻译官”到底有多少本事? - cmdragon's Blog
- 快速入门Vue3,插值、动态绑定和避坑技巧你都搞懂了吗? - cmdragon's Blog
- 想让PostgreSQL快到飞起?先找健康密码还是先换引擎? - cmdragon's Blog
- 想让PostgreSQL查询快到飞起?分区表、物化视图、并行查询这三招灵不灵? - cmdragon's Blog
- 子查询总拖慢查询?把它变成连接就能解决? - cmdragon's Blog
- PostgreSQL全表扫描慢到崩溃?建索引+改查询+更统计信息三招能破? - cmdragon's Blog
- 复杂查询总拖后腿?PostgreSQL多列索引+覆盖索引的神仙技巧你get没? - cmdragon's Blog
- 只给表子集建索引?用函数结果建索引?PostgreSQL这俩操作凭啥能省空间又加速? - cmdragon's Blog
- B-tree索引像字典查词一样工作?那哪些数据库查询它能加速,哪些不能? - cmdragon's Blog
- 想抓PostgreSQL里的慢SQL?pg_stat_statements基础黑匣子和pg_stat_monitor时间窗,谁能帮你更准揪出性能小偷? - cmdragon's Blog
- PostgreSQL的“时光机”MVCC和锁机制是怎么搞定高并发的? - cmdragon's Blog
- PostgreSQL性能暴涨的关键?内存IO并发参数居然要这么设置? - cmdragon's Blog
- 大表查询慢到翻遍整个书架?PostgreSQL分区表教你怎么“分类”才高效
- PostgreSQL 查询慢?是不是忘了优化 GROUP BY、ORDER BY 和窗口函数? - cmdragon's Blog
- PostgreSQL里的子查询和CTE居然在性能上“掐架”?到底该站哪边? - cmdragon's Blog
- PostgreSQL选Join策略有啥小九九?Nested Loop/Merge/Hash谁是它的菜? - cmdragon's Blog
- PostgreSQL新手SQL总翻车?这7个性能陷阱你踩过没? - cmdragon's Blog
- PostgreSQL索引选B-Tree还是GiST?“瑞士军刀”和“多面手”的差别你居然还不知道? - cmdragon's Blog
- 想知道数据库怎么给查询“算成本选路线”?EXPLAIN能帮你看明白? - cmdragon's Blog
- PostgreSQL处理SQL居然像做蛋糕?解析到执行的4步里藏着多少查询优化的小心机? - cmdragon's Blog
- PostgreSQL备份不是复制文件?物理vs逻辑咋选?误删还能精准恢复到1分钟前? - cmdragon's Blog
- 转账不翻车、并发不干扰,PostgreSQL的ACID特性到底有啥魔法? - cmdragon's Blog
- 银行转账不白扣钱、电商下单不超卖,PostgreSQL事务的诀窍是啥? - cmdragon's Blog
- PostgreSQL里的PL/pgSQL到底是啥?能让SQL从“说目标”变“讲步骤”? - cmdragon's Blog
- PostgreSQL视图不存数据?那它怎么简化查询还能递归生成序列和控制权限? - cmdragon's Blog
- PostgreSQL索引这么玩,才能让你的查询真的“飞”起来? - cmdragon's Blog
- PostgreSQL的表关系和约束,咋帮你搞定用户订单不混乱、学生选课不重复? - cmdragon's Blog
- PostgreSQL查询的筛子、排序、聚合、分组?你会用它们搞定数据吗? - cmdragon's Blog
- PostgreSQL数据类型怎么选才高效不踩坑? - cmdragon's Blog
- 想解锁PostgreSQL查询从基础到进阶的核心知识点?你都get了吗? - cmdragon's Blog
- PostgreSQL DELETE居然有这些操作?返回数据、连表删你试过没? - cmdragon's Blog
- PostgreSQL UPDATE语句怎么玩?从改邮箱到批量更新的避坑技巧你都会吗? - cmdragon's Blog
- PostgreSQL插入数据还在逐条敲?批量、冲突处理、返回自增ID的技巧你会吗? - cmdragon's Blog
- PostgreSQL的“仓库-房间-货架”游戏,你能建出电商数据库和表吗? - cmdragon's Blog
- PostgreSQL 17安装总翻车?Windows/macOS/Linux避坑指南帮你搞定? - cmdragon's Blog
- 能当关系型数据库还能玩对象特性,能拆复杂查询还能自动管库存,PostgreSQL凭什么这么香? - cmdragon's Blog
- 给接口加新字段又不搞崩老客户端?FastAPI的多版本API靠哪三招实现? - cmdragon's Blog
- 流量突增要搞崩FastAPI?熔断测试是怎么防系统雪崩的? - cmdragon's Blog
- FastAPI秒杀库存总变负数?Redis分布式锁能帮你守住底线吗 - cmdragon's Blog
- FastAPI的CI流水线怎么自动测端点,还能让Allure报告美到犯规? - cmdragon's Blog
- 如何用GitHub Actions为FastAPI项目打造自动化测试流水线? - cmdragon's Blog
- 如何用Git Hook和CI流水线为FastAPI项目保驾护航? - cmdragon's Blog
- FastAPI如何用契约测试确保API的「菜单」与「菜品」一致?
免费好用的热门在线工具
- RAID 计算器 - 应用商店 | By cmdragon
- 在线PS - 应用商店 | By cmdragon
- Mermaid 在线编辑器 - 应用商店 | By cmdragon
- 数学求解计算器 - 应用商店 | By cmdragon
- 智能提词器 - 应用商店 | By cmdragon
- 魔法简历 - 应用商店 | By cmdragon
- Image Puzzle Tool - 图片拼图工具 | By cmdragon
- 字幕下载工具 - 应用商店 | By cmdragon
- 歌词生成工具 - 应用商店 | By cmdragon
- 网盘资源聚合搜索 - 应用商店 | By cmdragon
- ASCII字符画生成器 - 应用商店 | By cmdragon
- JSON Web Tokens 工具 - 应用商店 | By cmdragon
- Bcrypt 密码工具 - 应用商店 | By cmdragon
- GIF 合成器 - 应用商店 | By cmdragon
- GIF 分解器 - 应用商店 | By cmdragon
- 文本隐写术 - 应用商店 | By cmdragon
- CMDragon 在线工具 - 高级AI工具箱与开发者套件 | 免费好用的在线工具
- 应用商店 - 发现1000+提升效率与开发的AI工具和实用程序 | 免费好用的在线工具
- CMDragon 更新日志 - 最新更新、功能与改进 | 免费好用的在线工具
- 支持我们 - 成为赞助者 | 免费好用的在线工具
- AI文本生成图像 - 应用商店 | 免费好用的在线工具
- 临时邮箱 - 应用商店 | 免费好用的在线工具
- 二维码解析器 - 应用商店 | 免费好用的在线工具
- 文本转思维导图 - 应用商店 | 免费好用的在线工具
- 正则表达式可视化工具 - 应用商店 | 免费好用的在线工具
- 文件隐写工具 - 应用商店 | 免费好用的在线工具
- IPTV 频道探索器 - 应用商店 | 免费好用的在线工具
- 快传 - 应用商店 | 免费好用的在线工具
- 随机抽奖工具 - 应用商店 | 免费好用的在线工具
- 动漫场景查找器 - 应用商店 | 免费好用的在线工具
- 时间工具箱 - 应用商店 | 免费好用的在线工具
- 网速测试 - 应用商店 | 免费好用的在线工具
- AI 智能抠图工具 - 应用商店 | 免费好用的在线工具
- 背景替换工具 - 应用商店 | 免费好用的在线工具
- 艺术二维码生成器 - 应用商店 | 免费好用的在线工具
- Open Graph 元标签生成器 - 应用商店 | 免费好用的在线工具
- 图像对比工具 - 应用商店 | 免费好用的在线工具
- 图片压缩专业版 - 应用商店 | 免费好用的在线工具
- 密码生成器 - 应用商店 | 免费好用的在线工具
- SVG优化器 - 应用商店 | 免费好用的在线工具
- 调色板生成器 - 应用商店 | 免费好用的在线工具
- 在线节拍器 - 应用商店 | 免费好用的在线工具
- IP归属地查询 - 应用商店 | 免费好用的在线工具
- CSS网格布局生成器 - 应用商店 | 免费好用的在线工具
- 邮箱验证工具 - 应用商店 | 免费好用的在线工具
- 书法练习字帖 - 应用商店 | 免费好用的在线工具
- 金融计算器套件 - 应用商店 | 免费好用的在线工具
- 中国亲戚关系计算器 - 应用商店 | 免费好用的在线工具
- Protocol Buffer 工具箱 - 应用商店 | 免费好用的在线工具
- IP归属地查询 - 应用商店 | 免费好用的在线工具
- 图片无损放大 - 应用商店 | 免费好用的在线工具
- 文本比较工具 - 应用商店 | 免费好用的在线工具
- IP批量查询工具 - 应用商店 | 免费好用的在线工具
- 域名查询工具 - 应用商店 | 免费好用的在线工具
- DNS工具箱 - 应用商店 | 免费好用的在线工具
- 网站图标生成器 - 应用商店 | 免费好用的在线工具
- XML Sitemap
1. 基础语法:computed函数
computed函数接收一个计算函数作为参数,返回一个只读的响应式引用(Ref)。计算函数内直接引用响应式变量(需通过.value访问ref类型的数据)。
<script setup>
// 从vue中导入ref(用于定义响应式数据)和computed(用于定义计算属性)
import { ref, computed } from 'vue'
// 定义响应式数据(ref包装)
const firstName = ref('John')
const lastName = ref('Doe')
// 定义计算属性fullName
const fullName = computed(() => {
// ref类型的数据需通过.value访问其值
return firstName.value + ' ' + lastName.value
})
</script>
<template>
<p>全名:{{ fullName }}</p> <!-- 渲染结果:John Doe -->
</template>
关键说明:
computed返回的fullName是一个Ref对象,模板中使用时会自动解包(无需.value);- 计算函数内的依赖(
firstName.value、lastName.value)会被Vue自动追踪,依赖变化时计算属性更新。
2. 进阶:带setter的计算属性
与Options API类似,computed函数也支持通过对象参数定义getter和setter,实现“读写型”计算属性。
<script setup>
import { ref, computed } from 'vue'
const firstName = ref('John')
const lastName = ref('Doe')
// 定义带setter的计算属性
const fullName = computed({
// getter:读取时执行
get() {
return firstName.value + ' ' + lastName.value
},
// setter:赋值时执行
set(newValue) {
const [first, last] = newValue.split(' ')
firstName.value = first // 更新响应式数据
lastName.value = last // 更新响应式数据
}
})
</script>
<template>
<input v-model="fullName" /> <!-- 输入“Jane Smith”,触发setter -->
<p> firstName: {{ firstName }} </p> <!-- 输出:Jane -->
<p> lastName: {{ lastName }} </p> <!-- 输出:Smith -->
</template>
三、Options API vs Composition API:核心差异对比
为了更清晰地理解两种语法的区别,我们通过表格总结核心差异:
| 维度 | Options API | Composition API |
|---|---|---|
| 语法形式 | 组件选项中的computed字段,函数声明 | 调用computed函数,参数为计算逻辑 |
| 上下文访问 | 通过this访问组件实例的响应式数据 | 直接引用响应式变量(ref/reactive) |
| 逻辑组织 | 按“选项类型”分类(data/computed/methods分开) | 按“逻辑关注点”组织(相关变量和计算属性放在一起) |
| 灵活性 | 适合简单组件,逻辑分散 | 适合复杂组件,支持逻辑复用(如useTodoFilter) |
四、实战场景:计算属性的实际运用
计算属性最常用的场景是基于响应式数据生成衍生值,比如过滤列表、格式化数据等。以下以“Todo列表过滤”为例,对比两种API的实现:
1. Options API实现
<script>
export default {
data() {
return {
todos: [ // 待办列表(响应式数据)
{ text: 'Learn Vue', done: true },
{ text: 'Write Blog', done: false },
{ text: 'Build App', done: true }
],
filter: 'all' // 过滤条件(响应式数据:all/done/active)
}
},
computed: {
// 计算属性:过滤后的待办列表
filteredTodos() {
if (this.filter === 'all') return this.todos
return this.todos.filter(todo => {
return todo.done === (this.filter === 'done')
})
}
}
}
</script>
2. Composition API实现
<script setup>
import { ref, computed } from 'vue'
// 待办列表(响应式数据)
const todos = ref([
{ text: 'Learn Vue', done: true },
{ text: 'Write Blog', done: false },
{ text: 'Build App', done: true }
])
// 过滤条件(响应式数据)
const filter = ref('all')
// 计算属性:过滤后的待办列表
const filteredTodos = computed(() => {
if (filter.value === 'all') return todos.value
return todos.value.filter(todo => {
return todo.done === (filter.value === 'done')
})
})
</script>
场景说明:
无论是哪种API,计算属性filteredTodos都会自动追踪 todos和filter的变化——当用户切换过滤条件(如从all到done),或待办项的done状态变化时,filteredTodos会自动更新,无需手动监听。
五、课后Quiz:巩固你的理解
问题1:
在Vue 3中,如何用Composition API定义一个带setter的计算属性?要求:
- 依赖两个
ref变量a(初始值1)和b(初始值2); - 计算属性
sum的getter返回a + b; - 当给
sum赋值时,将值平分给a和b(例如sum = 4,则a = 2,b = 2)。
答案与解析:
<script setup>
import { ref, computed } from 'vue'
const a = ref(1)
const b = ref(2)
const sum = computed({
get() {
return a.value + b.value // getter返回a+b
},
set(newValue) {
const average = newValue / 2 // 平分新值
a.value = average // 更新a
b.value = average // 更新b
}
})
</script>
问题2:
请说明计算属性与方法的核心区别,并解释计算属性的“缓存机制”是如何工作的?
答案与解析:
- 核心区别:方法每次调用都会重新执行函数体;计算属性仅在依赖的响应式数据变化时重新计算,否则复用缓存值。
- 缓存机制:Vue会自动追踪计算属性的响应式依赖(如
firstName、lastName),当依赖变化时,标记计算属性为“脏值”,下次访问时重新计算并缓存新值。
六、常见报错与解决方案
1. Options API中计算属性用箭头函数导致this错误
错误示例:
computed: {
fullName: () => this.firstName + this.lastName // this指向undefined
}
原因:箭头函数没有自己的this,会继承外层作用域的this(通常是window或undefined),而非组件实例。
解决方法:使用普通函数定义计算属性(普通函数的this指向组件实例)。
正确示例:
computed: {
fullName() {
return this.firstName + this.lastName
}
}
2. Composition API中忘记访问ref的.value
错误示例:
const firstName = ref('John')
const lastName = ref('Doe')
const fullName = computed(() => firstName + lastName) // 结果为"[object Object][object Object]"
原因:ref是包装对象,其值存储在.value属性中,直接使用ref变量会拿到对象本身。
解决方法:在计算函数中通过.value访问ref的值。
正确示例:
const fullName = computed(() => firstName.value + lastName.value)
3. 计算属性依赖非响应式数据
错误示例:
const firstName = 'John' // 非响应式
const lastName = 'Doe'
const fullName = computed(() => firstName + lastName) // 不会更新
原因:计算属性的缓存机制仅对响应式数据有效(ref/reactive包装的变量)。
解决方法:将非响应式数据改为ref或reactive。
正确示例:
const firstName = ref('John')
const lastName = ref('Doe')
const fullName = computed(() => firstName.value + lastName.value)