uni-app 的 watch 非万能,其行为受 vue 版本、数据声明方式及平台限制影响;vue 3 setup 中须调用函数而非配置对象,监听需区分 ref/响应式对象、精准字段或 deep 深度监听,小程序端必须 deep:true 才能捕获内部变化,props 监听应改用 watcheffect,dom 操作需包裹 nexttick。

uni-app 中的 watch 不是“写个回调就能监听一切”的万能开关——它行为高度依赖 Vue 版本(Vue 2 / Vue 3)、数据声明方式(ref / reactive)、平台限制(小程序端更严格),稍不注意就「监听不到变化」。
watch 在 Vue 3 setup 里必须用函数调用,不能写对象配置
这是最常踩的坑:在 <script setup></script> 中,watch 是一个导入后调用的函数,不是组件选项。直接写 watch: { xxx() {} } 会静默失效。
- 监听基本值(如
ref):watch(count, (newVal, oldVal) => {}) - 监听对象某个字段(推荐精准监听):
watch(() => user.value.name, (newVal) => {}) - 监听整个
ref对象(需deep: true):watch(user, () => {}, { deep: true })—— 但别滥用,性能代价明显 -
immediate: true不是默认行为,要手动加才在绑定时执行一次
小程序端监听对象/数组内部变化必须显式加 deep: true
微信、支付宝等小程序运行时对 Proxy 的拦截更保守。比如你有 const list = ref([{ done: false }]),执行 list.value[0].done = true,不加 deep: true 就完全不会触发 watch。
- 数组索引赋值(
arr[0] = x)、对象属性修改(obj.a = 1)都属于「内部变化」,浅监听捕获不到 - 监听
.length或用push/pop等方法会触发(因为改变了引用或调用了重写方法),但这不可靠 - 大数据量时慎用
deep: true,递归遍历可能卡顿;优先考虑精准监听具体字段
props 变化监听不到?改用 watchEffect 或转成 ref
子组件中直接 watch(props.xxx, ...) 几乎必失败:一是 props 是只读的,Vue 3 会警告;二是父传静态值或非响应式数据时根本无响应。
- ✅ 推荐方案:
watchEffect(() => { console.log(props.fenshuj) })—— 自动收集依赖,无需指定监听源 - ✅ 备选方案:先
const fenshujRef = ref(props.fenshuj),再watch(fenshujRef, ...) - ❌ 避免:试图直接监听
props字段,或在onLoad后手动赋值再指望 watch 捕获(时机错乱+响应式丢失)
watch 回调里改 DOM 必须包 nextTick
常见现象:watch 到宽度变化,this.$refs.el.style.width = newVal + 'px' 却没生效。不是代码错,是 DOM 还没完成更新或元素尚未挂载。
-
watch触发时,模板重渲染可能还没开始,ref元素可能为undefined或旧状态 - 必须用
this.$nextTick(() => { /* DOM 操作 */ })(Vue 2)或nextTick(() => { /* ... */ })(Vue 3)确保操作在 DOM 更新后执行 - 如果涉及异步请求后更新 DOM,
nextTick要套在请求回调内,而不是 watch 回调顶层
真正麻烦的从来不是语法本身,而是跨端环境下响应式链路的断裂点:从父组件传值方式、到数据是否被 ref 包裹、再到小程序运行时对深层变更的忽略——任何一个环节断掉,watch 就成了摆设。










