Vue3 中 watch 第三个参数怎么用?6 大配置属性 + 场景指南

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

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

1. immediate: boolean(默认 false)

  • 作用 :控制监听是否在 初始渲染时立即执行一次回调函数(无需等待被监听值变化)。
  • 场景:需要页面加载时就根据初始值执行逻辑(例如:初始化时请求接口、设置默认状态)。
  • 示例
xml 复制代码
<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 复制代码
<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 复制代码
<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 复制代码
<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 复制代码
<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 复制代码
<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)。
相关推荐
Larcher6 小时前
100 行代码搞定 AI Logo 生成网站!新手也能吃透的 AIGC 前端实战
前端·javascript
社恐的下水道蟑螂6 小时前
彻底搞懂 CSS 盒子模型:从 content-box 到 border-box 的实战指南
javascript
Data_Adventure7 小时前
Java 与 TypeScript 的核心对比
前端·后端
天蓝色的鱼鱼7 小时前
零代码Mock神器:json-server 快速上手
前端
鱼鱼块7 小时前
《从零开始掌握CSS盒模型:结构、计算与最佳实践》
前端
子醉7 小时前
html5 input[type=date]如何让日期中的年/月/日改成英文
前端·html·html5
Data_Adventure7 小时前
从前端到 Java 后端:一份详细转型路线指南
前端·后端
神秘的猪头7 小时前
CSS 盒子模型详解:从 `box-sizing` 理解布局本质
前端·javascript
UIUV7 小时前
CSS学习笔记:深入理解盒子模型与 box-sizing
前端·css·前端框架