Vue.js中监听属性变化获取变更前数据:简单值直接用watch回调的oldValue参数;复杂对象需手动缓存快照;路由/Vuex通过computed桥接后watch;清理副作用优先用watchEffect+onInvalidate。

Vue.js 中监听属性变化时,要拿到变更前的数据,关键看监听目标类型和写法。简单值直接可用参数,复杂对象需手动缓存旧值。
监听 ref 或顶层响应式变量:直接用回调参数
当监听的是一个 ref(如 count = ref(0))或 reactive 对象的顶层属性(如 () => state.count),watch 回调函数会自动传入新旧两个值:
- 第一个参数是变更后的新值(
newValue) - 第二个参数是变更前的旧值(
oldValue) - 注意:若设置了
immediate: true,首次执行时oldValue为undefined,需加判断
监听 reactive 对象、嵌套字段或数组:必须手动缓存旧值
直接监听整个 reactive 对象(如 user)或深层路径(如 user.profile.name)时,watch 的 oldValue 往往只是同一引用,无法反映内部变化。此时推荐以下做法:
- 用
ref显式保存上一次的结构化快照,例如const prevUser = ref(JSON.stringify(user)) - 在 watch 回调中用
JSON.stringify(cur)或structuredClone(cur)获取当前快照 - 对比前后字符串或克隆对象,确认是否真有变化,再更新缓存
- 对含循环引用或特殊值(
undefined、Symbol)的场景,建议用lodash.isEqual替代 JSON 方案
监听路由或 Vuex 数据:通过计算属性桥接再 watch
这类外部状态本身不直接暴露新旧值,但可通过标准方式接入:
立即学习“前端免费学习笔记(深入)”;
- 先用
computed映射 Vuex 的 getter 或路由信息(如computed(() => $route)) - 再对这个计算属性使用 watch,回调中即可正常接收
(to, from)或(newVal, oldVal) - 如果需要深度比对路由参数或 store 状态,仍需配合手动快照逻辑
不需要比对、只需清理上一次副作用:用 watchEffect + onInvalidate
若关注点不在“差异”,而在“上次执行留下的资源要不要清掉”,watchEffect 更简洁:
- 每次新回调运行前,自动触发上一次注册的
onInvalidate函数 - 适合处理定时器、请求取消、动画中断等场景
- 它不提供新旧值,但天然支持“基于上一次状态做清理”这一模式


















