在 Vue3 中,watch 的第三个参数是一个 配置选项对象(可选),用于精细控制监听行为。它支持多个属性,各自对应不同的功能,核心作用是调整监听的触发时机、深度监听、防抖节流等逻辑。以下是完整的配置属性及详细说明:

一、核心配置属性(常用)

1. immediate: boolean(默认 false)
  • 作用:控制监听是否在 初始渲染时立即执行一次回调函数(无需等待被监听值变化)。
  • 场景:需要页面加载时就根据初始值执行逻辑(例如:初始化时请求接口、设置默认状态)。
  • 示例

xml

体验AI代码助手

代码解读

复制代码

<script setup> import { ref, watch } from 'vue' const count = ref(0) // 初始渲染时立即执行一次,之后 count 变化时再执行 watch(count, (newVal) => { console.log('count 值:', newVal) // 初始输出 0,后续修改时输出新值 }, { immediate: true }) </script>

2. deep: boolean(默认 false)
  • 作用:控制是否 深度监听引用类型(对象 / 数组)的内部属性变化
  • 注意
    • Vue3 的 watch 对 响应式对象(如 reactive 创建的) 默认会进行 “深度监听”(无需手动设 deep: true),但仅监听 “被访问过的属性”(基于 Proxy 代理的惰性监听);
    • 非响应式对象(如 ref 包裹的普通对象)需要监听所有内部属性(包括未访问过的) 时,必须手动设置 deep: true。
  • 场景:监听对象的嵌套属性(如 user.info.age)、数组的元素变化。
  • 示例

xml

体验AI代码助手

代码解读

复制代码

<script setup> import { ref, watch } from 'vue' const user = ref({ name: '张三', info: { age: 20 } }) // 监听 user 内部属性变化(需 deep: true) watch(user, (newUser) => { console.log('age 变化:', newUser.info.age) // 修改 user.value.info.age 时触发 }, { deep: true }) // 触发监听:修改嵌套属性 setTimeout(() => { user.value.info.age = 21 }, 1000) </script>

3. flush: 'pre' | 'post' | 'sync'(默认 'pre')
  • 作用:控制回调函数的 执行时机(即:回调在 Vue 组件更新周期的哪个阶段运行)。
  • 三个取值说明:
取值 执行时机 场景示例
'pre'(默认) 组件更新 之前 执行 需在 DOM 更新前修改数据(避免 DOM 闪烁)
'post' 组件更新 之后 执行(DOM 已更新) 需操作更新后的 DOM(如获取元素尺寸、滚动位置)
'sync' 被监听值变化时 同步立即执行 需实时响应变化(极少用,可能影响性能)
  • 示例(操作更新后的 DOM):

xml

体验AI代码助手

代码解读

复制代码

<template> <div ref="box" :style="{ width: `${count * 100}px` }"></div> </template> <script setup> import { ref, watch } from 'vue' const count = ref(1) const box = ref(null) // 回调在 DOM 更新后执行,可获取最新的元素宽度 watch(count, () => { console.log('box 宽度:', box.value.offsetWidth) // 正确输出更新后的宽度 }, { flush: 'post' }) // 触发监听:修改 count setTimeout(() => { count.value = 2 }, 1000) </script>

二、其他实用配置(Vue3.2+ 支持)

4. once: boolean(默认 false)
  • 作用:控制监听是否 只触发一次(触发后自动停止监听)。
  • 场景:只需响应第一次变化(如:首次加载后的一次性初始化、仅需执行一次的回调)。
  • 示例

xml

体验AI代码助手

代码解读

复制代码

<script setup> import { ref, watch } from 'vue' const count = ref(0) // 仅在 count 第一次变化时触发(之后再修改不触发) watch(count, (newVal) => { console.log('count 首次变化:', newVal) // 仅输出 1(第一次修改时) }, { once: true }) // 触发两次修改 setTimeout(() => { count.value = 1 }, 1000) setTimeout(() => { count.value = 2 }, 2000) // 无输出 </script>

5. debounce: number(默认 undefined)
  • 作用:给监听添加 防抖(延迟 n 毫秒后执行回调,若期间值多次变化,仅执行最后一次)。
  • 单位:毫秒(ms)。
  • 场景:监听输入框输入(避免频繁触发接口请求)、频繁变化的数值(如滚动位置)。
  • 示例(输入框防抖):

xml

体验AI代码助手

代码解读

复制代码

<template> <input v-model="keyword" placeholder="搜索..."> </template> <script setup> import { ref, watch } from 'vue' const keyword = ref('') // 输入停止 500ms 后才执行回调(避免输入时频繁触发) watch(keyword, (newVal) => { console.log('搜索关键词:', newVal) // 输入停止 500ms 后输出 }, { debounce: 500 }) </script>

6. throttle: number(默认 undefined)
  • 作用:给监听添加 节流(每隔 n 毫秒最多执行一次回调,期间值多次变化仅执行一次)。
  • 单位:毫秒(ms)。
  • 场景:监听滚动事件、窗口大小变化等高频触发的场景。
  • 示例(滚动节流):

xml

体验AI代码助手

代码解读

复制代码

<script setup> import { ref, watch } from 'vue' const scrollTop = ref(0) // 监听滚动位置,每隔 300ms 最多执行一次 window.addEventListener('scroll', () => { scrollTop.value = window.scrollY }) watch(scrollTop, (newVal) => { console.log('滚动位置:', newVal) // 每 300ms 输出一次 }, { throttle: 300 }) </script>

三、配置属性总结表

属性名 类型 默认值 核心作用
immediate boolean false 初始渲染时是否立即执行回调
deep boolean false 是否深度监听引用类型内部属性变化
flush string 'pre' 回调执行时机(pre/post/sync)
once boolean false 是否只触发一次回调(触发后停止监听)
debounce number undefined 防抖延迟(ms),多次变化仅最后一次执行
throttle number undefined 节流间隔(ms),高频变化时限制执行频率

四、注意事项

  1. deep 的使用场景
    • 监听 reactive 对象时,默认会 “惰性深度监听”(仅监听被访问过的属性),若需监听所有属性(包括未访问的),仍需设置 deep: true;
    • 监听 ref 包裹的对象时,必须设置 deep: true 才能监听内部属性变化。
  1. debounce / throttle 的限制:仅 Vue3.2+ 版本支持,低版本需手动通过 lodash 等库实现。
  1. 性能优化:避免不必要的 deep: true(会增加监听开销),尽量精准监听具体属性(如 () => user.info.age)。

原文:https://juejin.cn/post/7568425510791888896

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐