Vue3侦听器watch
Vue3 的 watch
是响应式编程中用于监听数据变化的核心 API,适用于执行副作用操作(如异步请求、复杂逻辑处理等)。本文将详细介绍其用法、配置项及实战场景,并通过示例代码帮助开发者快速掌握。
一、基础用法
1. 监听简单值(Ref)
通过直接传入 ref
对象,监听基本类型数据的变化:
import { ref, watch } from 'vue';
const count = ref(0);
watch(count, (newVal, oldVal) => {
console.log(`值从 ${oldVal} 变为 ${newVal}`);
});
count.value++; // 触发回调:输出 "值从 0 变为 1"
2. 监听响应式对象(Reactive)
监听整个响应式对象时,需开启 deep
选项以捕获嵌套属性的变化:
const user = reactive({ name: 'Alice', age: 25 });
watch(user, (newVal) => {
console.log('用户信息变化:', newVal);
}, { deep: true });
user.age = 26; // 触发回调
3. 监听对象特定属性
使用 Getter 函数 监听对象中的单个属性,避免不必要的深度遍历:
watch(
() => user.name,
(newName, oldName) => {
console.log(`姓名从 ${oldName} 变为 ${newName}`);
}
);
二、高级配置选项
1. 立即执行(immediate)
组件初始化时立即触发回调,常用于数据预加载:
watch(count, (newVal) => {
fetchData(newVal); // 初始化时立即执行
}, { immediate: true });
2. 深度监听(deep)
强制监听对象内部所有属性变化(默认仅监听顶层属性):
watch(user, () => {
// 响应所有嵌套属性的变化
}, { deep: true });
3. 执行时机(flush)
控制回调触发时机:
pre
(默认):DOM 更新前执行post
:DOM 更新后执行sync
:同步执行(慎用,可能导致性能问题)
watch(source, callback, { flush: 'post' });
4. 单次监听(once)
Vue3.4+ 新增功能,回调仅执行一次:
watch(count, () => {
console.log('仅触发一次');
}, { once: true });
三、进阶用法
1. 监听多个数据源
通过数组形式同时监听多个响应式变量:
const [firstName, lastName] = [ref('A'), ref('B')];
watch([firstName, lastName], ([newFirst, newLast]) => {
console.log(`全名:${newFirst} ${newLast}`);
});
2. 处理异步操作
结合 onCleanup
清理过期请求,避免竞态问题:
watch(searchQuery, async (newVal, _, onCleanup) => {
let isCancelled = false;
onCleanup(() => (isCancelled = true)); // 清理前一次请求
const res = await fetch(`/api?q=${newVal}`);
if (!isCancelled) {
updateResults(res.data);
}
});
3. 停止侦听器
调用 watch
返回的停止函数,手动终止监听:
const stop = watch(count, () => { /* ... */ });
stop(); // 停止监听
四、注意事项
性能优化
- 避免滥用
deep: true
,尤其是大型对象 - 优先使用计算属性处理派生数据
- 避免滥用
对象监听陷阱
- 直接替换整个对象会触发回调,修改属性需依赖
deep
或 Getter 函数
- 直接替换整个对象会触发回调,修改属性需依赖
与
watchEffect
的区别watch
需显式指定依赖,适合需要旧值的场景watchEffect
自动追踪依赖,适合简单副作用
五、完整示例
<template>
<div>
<input v-model="name" placeholder="输入姓名">
<input type="number" v-model="age">
<p>历史记录: {{ logs }}</p>
</div>
</template>
<script setup>
import { ref, reactive, watch } from 'vue';
const name = ref('');
const age = ref(0);
const user = reactive({ details: { role: 'user' } });
const logs = ref([]);
// 监听多个数据源
watch([name, age], ([newName, newAge]) => {
logs.value.push(`姓名:${newName},年龄:${newAge}`);
});
// 深度监听嵌套对象
watch(
() => user.details.role,
(newRole) => {
console.log('角色变更:', newRole);
},
{ deep: true }
);
</script>
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 万家灯火