本质
computed 计算属性
依赖缓存的派生值:基于已有数据计算出新数据,有缓存,只有依赖变量改变才重新执行函数,模板直接渲染结果。
语法:key: 函数 / {get, set}
用途:数据转换、多数据合并、复杂表达式简化。
watch 侦听器
数据变化的回调监听:监听指定变量,变量一变就执行一段逻辑(无返回值,侧重动作),无缓存,每次数据更新都会触发。
语法:key: 处理函数 / {handler, deep, immediate}
用途:异步操作、复杂业务逻辑、多步骤操作、深度监听对象/数组。
对比表
| 对比维度 | computed(计算属性) | watch(侦听器) |
|---|---|---|
| 核心目的 | 得到一个计算后的值(供页面渲染) | 数据变化后执行一段行为/逻辑 |
| 缓存机制 | 有缓存;依赖不变,多次访问只算一次 | 无缓存;数据一更新就执行 |
| 返回值 | 必须 return 结果,模板可直接插值使用 | 不需要 return,函数内写业务操作 |
| 使用场景 | 1. 模板复杂表达式简化 2. 多变量合并计算 3. 简单数据格式化 | 1. 异步请求(接口) 2. 复杂多步逻辑 3. 对象/数组深度监听 4. 数据变更触发DOM、定时器 |
| 写法限制 | 不能写异步、复杂副作用逻辑 | 适合写异步、定时器、赋值、请求 |
| 初始化执行 | 页面渲染时自动执行一次(计算初始值) | 默认页面初始化不执行,需加 immediate: true |
| 监听深度 | 只能监听基础依赖,对象内部属性不追踪 | 配置 deep: true 可深度监听对象、数组 |
| 多依赖 | 天然支持多个依赖变量,任意一个变化就更新 | 一个 watch 只能监听一个目标,多变量需写多个watch |
使用场景
选择
- 要生成新值、页面渲染用 → 优先 computed
- 简单拼接、四则运算、字符串格式化一律用 computed
- 数据变了要做异步、请求、定时器、复杂操作 → 用 watch
- 监听对象内部属性、数组内容变化、初始化就要执行逻辑,用 watch 加
deep/immediate
computed 计算属性适用场景
页面展示需要组合/加工现有数据
比如拼接姓名、总价求和、数字格式化、状态文字转换(0=禁用,1=启用)、多条件判断展示标签文本。简化模板复杂表达式
模板里大量三元、加减、数组过滤,提取成计算属性让页面更简洁。同一计算结果多处复用
页面多个地方用到同一个加工后的值,有缓存,不会重复计算,性能更好。需要双向改写派生数据
由多个基础字段合成一个字段,同时支持修改该字段反向拆分更新原数据(get+set)。
watch 侦听器适用场景
表单值变化实时 校验、提示错误。如:年龄、价格不能是负数,也不能超过最大值;密码复杂度不符合要求;两次密码不一致;
在数据变化时,发送 ajax请求。如:百度的输入框的提示;输入验证码,自动向服务器发请求校验是否正确;
数据变动触发副作用逻辑
值改变开启/关闭定时器、弹窗、路由跳转、打印日志、重置表单。监听对象、数组内部深层修改
修改表单对象里某一个属性、数组新增删除元素后执行逻辑。页面初始化就要执行一次监听逻辑
进入页面立刻根据当前数据执行一遍业务,不需要等手动修改数据。单一数据变化触发多步骤复杂流程
一个值改动要连续执行赋值、判断、调用多个方法等一系列操作。
快速区分选用规则
- 目的是得到一个新值给页面渲染 → computed
- 目的是数据变了去做某一件事 → watch
易错点
- computed 内部不要写异步(定时器、axios),缓存机制会失效;
- watch 监听数组:数组push/splice等方法能触发,但直接赋值对象需要deep;
- 能用 computed 绝不写 watch,computed 性能更好;
- computed 依赖必须是响应式数据,普通全局变量不会触发更新。
总结
计算属性(computed)的函数必须有返回值;侦听属性(watch)不需要
计算属性(computed)能实现的功能,侦听属性(watch)都能实现,可能会啰嗦些
侦听属性(watch)能实现的功能,计算属性(computed)不一定能实现,可以实现异步
侦听属性例子
侦听属性可以实现异步功能(计算属性无法实现),如:延时1秒后执行
<div id="app">
输入出生年份:<input type="text" v-model="birthday"><br>
年龄:<span>{{age}}</span>(表达式只写监听属性名,会自动调用 监听方法)<br>
年龄:<span>{{age}}</span><br>
年龄:<span>{{age}}</span><br>
年龄:<span>{{age}}</span>(计算属性会缓存结果,如:显示4次年龄,初始化时只执行1次监听方法)
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
<script>
var vm = new Vue({
el: '#app',
data:{
birthday:'',
age:''
},
watch:{
// 侦听 birthday 属性值变化
birthday:function(newValue,oldValue){
setTimeout(() => {
console.log("birthday值从 "+oldValue+" 改为 "+newValue)
this.age=new Date().getFullYear() - this.birthday.substr(0,this.birthday.indexOf("-"))
}, 1000);
}
}
})
</script>