Vue 3 的 watch 支持数组形式监听多个响应式源,需确保每个元素为 ref、computed 或 toRef/箭头函数包装的 reactive 属性;直接使用普通值、解构副本或未 deep 的 reactive 对象将失效。

Vue 3 的 watch 支持用数组形式同时监听多个响应式源,但必须确保数组中每个元素都是**可追踪的响应式引用**——即 ref、computed,或从 reactive 中正确提取的响应式属性(不能是普通值或解构后的非响应式副本)。
数组监听的基本写法(ref + reactive 属性混合)
你可以把 ref 和从 reactive 中提取的响应式属性(如用 toRef 或箭头函数包装)一起放进数组:
-
正确示例:使用
toRef提取reactive对象的单个属性,保证响应性
复制AI写代码
import { ref, reactive, toRef, watch } from 'vue'const search = ref('')
const filters = reactive({ type: 'all', category: 'tech' })
const typeRef = toRef(filters, 'type')
const categoryRef = toRef(filters, 'category')
// 同时监听 ref 和 reactive 的两个字段
watch([search, typeRef, categoryRef], ([newSearch, newType, newCat], [oldSearch, oldType, oldCat]) => {
console.log('搜索或筛选条件变化:', { newSearch, newType, newCat })
})
用 getter 函数包装 reactive 属性(更灵活)
当需要监听 reactive 对象中多个字段,又不想逐个 toRef 时,可用箭头函数返回一个数组——这是官方推荐的“安全组合方式”:
- 函数体里访问的每个属性都会被自动追踪
- 避免手动管理
toRef,也兼容深层嵌套字段
复制AI写代码
const form = reactive({username: '',
email: '',
profile: { avatar: null }
})
watch(
() => [form.username, form.email, form.profile.avatar],
([u, e, a], [ou, oe, oa]) => {
if (u !== ou) console.log('用户名变了')
if (a !== oa) console.log('头像变了')
}
)
注意事项:哪些写法会失效?
以下常见错误会导致监听不触发:
- 直接写
[search, filters.type]——filters.type是普通值,不是响应式引用 - 用解构赋值
const { type } = filters后再放进数组 —— 解构后丢失响应性 - 监听整个
reactive对象(如[search, filters])却不加deep: true—— 只能捕获对象引用变化,无法感知内部字段更新
进阶:配合 immediate 和防抖使用
实际业务中常需首次加载就执行,或避免高频触发。可在选项中加入:
-
immediate: true:绑定时立即执行一次回调 -
flush: 'post':把回调延迟到 DOM 更新后执行(适合依赖视图的操作) - 手动加防抖:在回调内用
setTimeout或lodash.debounce
复制AI写代码
watch([search, typeRef], () => {// 防抖逻辑放在这里
if (debounceTimer) clearTimeout(debounceTimer)
debounceTimer = setTimeout(() => fetchData(), 300)
}, { immediate: true })


















