该用计算属性还是侦听器,取决于需求本质:要派生值用 computed,要执行动作用 watch;computed 自动缓存、同步返回、适合格式化等;watch 支持异步、深度监听、新旧值对比,适合发请求等副作用操作。

计算属性和侦听器不是“选哪个更好”,而是“该用哪个更对”。核心判断标准就一条:你要的是一个值,还是一件事。
你要的是一个派生出来的值——用 computed
比如拼姓名、算总价、过滤列表、格式化日期。这类需求的特点是:结果可复用、依赖明确、逻辑纯(无副作用)。
- 自动缓存:firstName 和 lastName 没变,fullName 就不会重新执行函数
- 响应式接入自然:模板里直接写
{{ fullName }},就像访问普通数据一样 - 必须同步返回值:不能在 computed 里发请求、加 setTimeout,否则拿不到预期结果
- 支持 getter/setter:需要双向联动时(如输入全名反向拆解姓和名),可写成可写计算属性
你要做一件事——用 watch
比如搜索框输入后调接口、表单字段变化时校验、监听路由参数跳转、修改对象深层属性后更新图表。这类动作本质是“响应变化去干活”,不产出供别处复用的值。
Vue 3 组合式 API 与 最佳实践,涵盖代码组织、useXxx 模式、组合式函数设计、Store 集成、响应式优化及功能抽取。
- 支持异步:可在回调里调用
api.search()或nextTick() - 可选立即执行:
immediate: true让它在组件挂载时也跑一次 - 深度监听可控:监听对象时,默认只看引用是否变;加
deep: true才能捕捉内部属性变化 - 能拿到新旧值:
watch(() => user.age, (newVal, oldVal) => {...}),方便做差异判断
别踩的典型误区
把 watch 当成“更灵活的 computed”来用,容易引发问题:
立即学习“前端免费学习笔记(深入)”;
- 用 watch 去拼字符串并赋给 data 属性——这本该是 computed 的活,徒增冗余响应式数据
- 在 computed 里写
setTimeout或fetch——结果不可预测,缓存机制会失效,甚至报错 - 监听整个 reactive 对象却不加
deep: true——对象内部属性变了,watch 却没反应 - 频繁触发开销大的操作却没用
debounce或flush: 'post'控制时机
组合式 API 中的写法提示
Vue 3 下两者定位更清晰:
-
computed(() => ...)返回的是一个Ref,带.value,但模板中无需写 .value -
watch(source, callback, options)的 source 可以是 ref、reactive 属性、getter 函数,甚至数组(同时监听多个) - 想监听响应式对象的某个字段,推荐写
watch(() => obj.field, ...),比字符串路径更安全、类型更友好

















