You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue数组Watcher未触发问题:push元素时回调不执行

Vue3中数组Ref的Watcher未触发问题解决

问题原因

Vue3的watch监听ref包裹的引用类型(如数组、对象)时,默认是浅监听:它只会检测ref.value的引用是否发生变化(比如给toasts.value重新赋值一个新数组),而数组的push/pop等修改内部元素的操作不会触发watch回调——因为数组本身的引用没有改变,只是内部元素变化了。

你之前误以为Watcher默认深度监听,这是混淆了Vue2的行为:Vue2中对数组的监听会自动处理内部变更,但Vue3的watch需要显式开启深度监听才能追踪引用类型的内部变化。

解决方案

有两种可行的解决方式,任选其一即可:

方案1:给watch添加deep: true选项

修改Toast组件中的watch代码,开启深度监听,这样数组内部元素的变化会被检测到:

import { watch } from 'vue'
import { ElMessageBox } from "element-plus";
import { toasts } from '~/lib/toast'

watch(toasts, () => {
    console.log("toasts changed")
    while (toasts.value.length) {
        const opts = toasts.value.pop()!
        ElMessageBox(opts)
    }
}, { deep: true }) // 添加深度监听选项

方案2:修改数组时替换整个引用

在showToast函数中,不要用push修改原数组,而是通过扩展运算符创建新数组并赋值给toasts.value,这样会改变ref.value的引用,触发默认的浅监听:

export const showToast = async (options: ElMessageBoxOptions) => {
    console.log("pushing", options)
    toasts.value = [...toasts.value, options] // 替换为新数组
}

这种方式不需要修改watch的配置,更符合Vue3响应式系统的设计思路,还能避免深度监听带来的额外性能开销。

额外说明

你在watch回调中使用while (toasts.value.length)配合pop()的方式,会在每次数组变化时清空所有未处理的toast。如果需要按顺序逐个处理,这种方式是可行的,但要注意ElMessageBox的异步行为可能导致多个弹窗同时弹出的问题,可以考虑添加队列处理逻辑优化。

内容的提问来源于stack exchange,提问作者nagylzs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 12:52:37