vue 的 watch 回调能否准确获取新旧值取决于监听源类型、配置选项和初始化时机;监听 ref 或 getter 时直接可用,watch reactive 对象需 deep 才捕获深层变化,多源监听推荐用 computed 聚合,数组/对象浅层变更需监听具体属性或启用 deep。

Vue 的 watch 回调天然支持新值与旧值对比,但实际使用中是否能拿到、是否准确,取决于监听源类型、配置选项和初始化时机。关键不是“能不能”,而是“怎么组织才可靠”。
监听 ref 或 getter 函数:新旧值直接可用
当监听单个 ref 或返回响应式值的函数时,回调参数 (newVal, oldVal) 会自动传入变化前后的值,无需额外配置:
-
newVal是变化后的新值,oldVal是上一次的值(首次触发时为undefined) - 适用于基础类型(字符串、数字、布尔)和简单对象引用变化
- 若需首次就执行逻辑,加
{ immediate: true },但要主动判断oldVal === undefined
监听 reactive 对象或嵌套结构:必须开启 deep 才能捕获内部变更
默认情况下,watch 只检测对象引用是否更换。想监听 user.name 或 form.email 这类深层字段变化,必须启用深度监听:
递归分析 Vue 项目组件依赖,从入口文件生成组件层级图,支持 Vue 2/3,输出组件名、文件路径和属性。适用于分析组件结构、排查依赖或了解项目架构。
- 配置
{ deep: true }后,newVal和oldVal仍是整个对象,但它们是响应式代理的深拷贝快照 - 注意:
oldVal在首次 deep 监听时也可能为undefined,尤其配合immediate使用时 - 避免无差别监听大对象——性能开销大且无法定位具体哪个字段变,建议用
computed提取关注字段再 watch
同时响应多个数据源:聚合后监听,新旧结构一致更易比对
不推荐为 keyword、status、page 分别写多个 watch。统一包装成计算属性再监听,能让 newVal 和 oldVal 结构完全一致,逐字段对比清晰直观:
- 用
computed(() => ({ keyword, status }))构建监听源 - 必须配
{ deep: true },否则对象引用未变时不会触发 - 回调内可直接比较
newVal.keyword !== oldVal.keyword,无需遍历或猜测变化点 - 首次触发时
oldVal为undefined,建议判空后再解构
区分“值变”和“引用变”:避免误判与漏判
数组或对象的浅层赋值(如 arr.push()、obj.name = 'x')不会改变引用,但内容已变。此时:
- 监听原始 ref/ reactive 本身,默认不触发(除非开了
deep) - 监听
arr.length或obj.name这样的具体属性,无需deep,变化即触发 - 监听整个数组时,
deep: true能捕获增删改,但要注意性能;更轻量的方式是监听其长度或用toRefs拆解关键字段
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!









