在 Vue3 中,watch 的第三个参数是一个 配置选项对象(可选),用于精细控制监听行为。它支持多个属性,各自对应不同的功能,核心作用是调整监听的触发时机、深度监听、防抖节流等逻辑。以下是完整的配置属性及详细说明:
一、核心配置属性(常用)
- 作用 :控制监听是否在 初始渲染时立即执行一次回调函数(无需等待被监听值变化)。
 
- 场景:需要页面加载时就根据初始值执行逻辑(例如:初始化时请求接口、设置默认状态)。
 
        
          
            
            
              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' | 
被监听值变化时 同步立即执行 | 
需实时响应变化(极少用,可能影响性能) | 
        
          
            
            
              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 毫秒后执行回调,若期间值多次变化,仅执行最后一次)。
 
- 场景:监听输入框输入(避免频繁触发接口请求)、频繁变化的数值(如滚动位置)。
 
        
          
            
            
              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 毫秒最多执行一次回调,期间值多次变化仅执行一次)。
 
- 场景:监听滚动事件、窗口大小变化等高频触发的场景。
 
        
          
            
            
              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),高频变化时限制执行频率 | 
四、注意事项
- deep 的使用场景:
 
- 
- 监听 reactive 对象时,默认会 "惰性深度监听"(仅监听被访问过的属性),若需监听所有属性(包括未访问的),仍需设置 deep: true;
 
 
- 
- 监听 ref 包裹的对象时,必须设置 deep: true 才能监听内部属性变化。
 
 
- debounce / throttle 的限制:仅 Vue3.2+ 版本支持,低版本需手动通过 lodash 等库实现。
 
- 性能优化:避免不必要的 deep: true(会增加监听开销),尽量精准监听具体属性(如 () => user.info.age)。