源本科技 | 码上会

Vue3 侦听器

2026/04/22
33
0

引言

Vue 3 中的侦听器通过 watchwatchEffect 函数实现,用于监听响应式数据的变化,并在变化发生时执行回调函数。这些工具提供了精确的数据追踪和处理机制,支持深度监听对象或数组属性的变化,以及对监听选项进行细粒度控制,有助于实现复杂的数据依赖逻辑与副作用管理。

watch 侦听器

watch 是 Vue 3 核心侦听 API,用于显式监听指定的响应式数据源,数据变化时执行回调。它支持获取新值、旧值,可控性更强,是 Vue 3 最常用的侦听方式。

参数说明

  • 源(source):必填,监听的目标,可以是 ref / reactive 对象、对象属性、返回值的 getter 函数、数据源数组。

  • 回调函数(callback):必填,数据源变化时执行,接收 新值、旧值 两个参数。

  • 选项(options):可选,配置侦听行为:

    • immediate:布尔值,true 表示组件初始化时立即执行一次回调

    • deep:布尔值,true 表示开启深度监听,监听嵌套对象 / 数组的内部变化。

    • flush:控制回调执行时机,默认 pre(组件更新前),可选 post(DOM 更新后)、sync(同步执行,极少使用)。

    • onTrack / onTrigger:调试用,追踪响应式依赖的触发逻辑。

基础用法

监听单个 ref 基础类型

<template>
  <button @click="count++">count + 1</button>
</template>

<script setup lang="ts">
import { ref, watch } from 'vue';
const count = ref(0);

// 监听基础数据类型
watch(count, (newValue, oldValue) => {
  console.log(`count 从 ${oldValue} 变为 ${newValue}`);
});
</script>

监听 reactive 对象(默认深度监听)

监听 reactive 对象时,无需配置 deep: true,会自动深度监听。

<script setup lang="ts">
import { reactive, watch } from 'vue';
const user = reactive({ name: 'Tom', age: 18 });

// 自动深度监听,无需 deep
watch(user, (newVal) => {
  console.log('用户信息更新:', newVal);
});
</script>

监听对象单个属性(推荐写法)

精准监听对象属性,避免不必要的触发,使用 getter 函数 声明源。

<script setup lang="ts">
import { reactive, watch } from 'vue';
const user = reactive({ name: 'Tom', age: 18 });

// 仅监听 name 属性
watch(() => user.name, (newVal) => {
  console.log('姓名更新:', newVal);
});
</script>

监听多个数据源

可同时监听多个数据,回调参数为数组格式。

<script setup lang="ts">
import { ref, watch } from 'vue';
const name = ref('Tom');
const age = ref(18);

watch([name, age], ([newName, newAge], [oldName, oldAge]) => {
  console.log(`姓名:${oldName} → ${newName},年龄:${oldAge} → ${newAge}`);
});
</script>

深度监听 ref 嵌套对象

ref 包裹的对象 / 数组,需要手动配置 deep: true 开启深度监听。

<script setup lang="ts">
import { ref, watch } from 'vue';
const userProfile = ref({ name: 'John Doe', age: 30 });

watch(
  userProfile,
  (newProfile) => console.log('资料更新'),
  { deep: true } // 必须开启深度监听
);
</script>

立即执行侦听

配置 immediate: true,组件初始化时自动执行一次回调。

watch(count, () => console.log('初始化/数据变化'), { immediate: true });

高级用法:停止侦听

watch 会返回一个停止函数,调用后可手动终止侦听。

const stopWatch = watch(count, () => {});
// 停止侦听
stopWatch();

watchEffect 副作用侦听器

watchEffect自动追踪依赖的副作用侦听器,无需手动指定监听源,回调中使用的响应式数据会被自动监听,初始化立即执行

核心特性

  • 自动依赖追踪:回调内使用的响应式数据,变化后自动重新执行。

  • 立即执行:组件初始化时默认执行一次,无需配置 immediate

  • 无新值旧值:专注于执行副作用逻辑,不关注值的变化细节。

  • 副作用清理:内置清理函数,可清除定时器、取消请求等。

基础用法

<template>
  <button @click="count++">count + 1</button>
</template>

<script setup lang="ts">
import { ref, watchEffect } from 'vue';
const count = ref(0);

// 自动追踪 count,初始化执行 + 变化后执行
watchEffect(() => {
  console.log(`Count is: ${count.value}`);
});
</script>

副作用清理函数

用于清理定时器、取消网络请求、解绑事件,避免内存泄漏

<script setup lang="ts">
import { ref, watchEffect } from 'vue';
const count = ref(0);

watchEffect((onInvalidate) => {
  // 开启定时器
  const timer = setInterval(() => console.log(count.value), 1000);
  
  // 清理函数:下次执行前 / 组件卸载时自动调用
  onInvalidate(() => clearInterval(timer));
});
</script>

高级配置

通过 flush 控制执行时机,用法与 watch 一致。

// DOM 更新完成后执行
watchEffect(() => {}, { flush: 'post' });

watch 与 watchEffect

特性

watch

watchEffect

监听方式

显式指定数据源

自动追踪回调内依赖

初始化执行

默认不执行,需配置 immediate

默认立即执行

新值 / 旧值

支持获取

不支持

适用场景

需要精准监听、获取值变化

简单副作用、联动逻辑、数据处理

最佳实践

推荐使用 watch

  1. 监听数据变化后发送异步请求(如搜索、表单提交);

  2. 需要获取新值、旧值做对比逻辑;

  3. 精准监听单个 / 多个指定数据源,避免不必要的触发。

推荐使用 watchEffect

  1. 简单的数据联动逻辑(如表单验证、状态同步);

  2. 需要自动清理副作用(定时器、请求、事件);

  3. 无需关心数据源,只关注执行副作用的场景。

通用规范

  1. 组件卸载时,Vue 会自动停止侦听器,无需手动清理;

  2. 优先精准监听,避免滥用深度监听,提升性能;

  3. 异步操作优先在 watch 中处理,逻辑更清晰。


总结

  1. watch:显式监听、可控性强,支持新值旧值,适合复杂业务逻辑;

  2. watchEffect:自动追踪、开箱即用,适合简单副作用处理;

  3. 核心配置:immediate(立即执行)、deep(深度监听)、flush(执行时机);

  4. 必备能力:清理副作用、停止侦听,是避免内存泄漏的关键。