当前位置: 首页 > news >正文

Vue: 侦听器(Watch)

1. 侦听器概述

        侦听器(Watchers)是 Vue 中用于响应数据变化并执行副作用的重要机制。与计算属性不同,侦听器专注于在状态变化时执行操作(如 DOM 更改、异步操作等)。

1.1 基本语法

import { watch } from 'vue'watch(source, callback, options)

2. 侦听数据源类型

数据源类型示例说明
单个 refwatch(x, callback)直接侦听一个 ref
Getter 函数watch(() => x.value + y.value, callback)通过函数返回要侦听的值
多个数据源watch([x, () => y.value], callback)同时侦听多个数据源
响应式对象watch(obj, callback)隐式创建深层侦听器

2.1 注意事项

不能直接侦听响应式对象的属性值:

// 错误方式
watch(obj.count, (count) => {console.log(`Count is: ${count}`)
})// 正确方式:使用getter函数
watch(() => obj.count,(count) => {console.log(`Count is: ${count}`)}
)

3. 深层侦听器

3.1 自动深层侦听

当直接侦听响应式对象时,会自动创建深层侦听器:

const obj = reactive({ count: 0, nested: { value: 1 } })watch(obj, (newValue, oldValue) => {// 任何嵌套属性变化都会触发// 注意:newValue和oldValue是同一个对象
})obj.nested.value++ // 会触发侦听器

3.2 选择性深层侦听

对于getter函数返回的对象,默认只侦听引用变化:

watch(() => state.someObject,(newValue, oldValue) => {// 仅当state.someObject被替换时触发}
)

可以使用deep选项强制深层侦听:

watch(() => state.someObject,(newValue, oldValue) => {// 嵌套属性变化也会触发},{ deep: true } // 或 { deep: 3 } (Vue 3.5+,表示最大遍历深度)
)
watch(() => state.someObject,(newValue, oldValue) => {// 嵌套属性变化也会触发},{ deep: true } // 或 { deep: 3 } (Vue 3.5+,表示最大遍历深度)
)

4. watchEffect

watchEffect自动追踪其同步执行期间访问的所有响应式属性:

// 使用watch
watch(todoId,async () => {const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${todoId.value}`)data.value = await response.json()},{ immediate: true }
)// 使用watchEffect简化
watchEffect(async () => {const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${todoId.value}`)data.value = await response.json()
})

4.1 watch vs watchEffect 对比

特性watchwatchEffect
依赖追踪只追踪明确侦听的数据源自动追踪所有访问到的响应式属性
初始执行需要immediate: true立即执行
参数(source, callback, options)(effect, options)
适用场景需要精确控制触发时机依赖多个属性,简化代码

5. 高级选项

5.1 即时回调

watch(source,(newValue, oldValue) => {// 立即执行,且当source改变时再次执行},{ immediate: true }
)

5.2 一次性侦听器 (Vue 3.4+)

watch(source,(newValue, oldValue) => {// 当source变化时,仅触发一次},{ once: true }
)

5.3 回调触发时机

// 默认:父组件更新后,当前组件DOM更新前
watch(source, callback)// DOM更新后执行
watch(source, callback, { flush: 'post' })
// 或使用别名
watchPostEffect(() => {})// 同步执行
watch(source, callback, { flush: 'sync' })
// 或使用别名
watchSyncEffect(() => {})

6. 副作用清理

在处理异步操作时,可能需要清理过期的副作用:

6.1 Vue 3.5+ (推荐)

watch(id, (newId) => {const controller = new AbortController()fetch(`/api/${newId}`, { signal: controller.signal }).then(/* ... */)onWatcherCleanup(() => {controller.abort() // 终止过期请求})
})

6.2 兼容版本 (Vue 3.5之前)

// 在watch中
watch(id, (newId, oldId, onCleanup) => {const controller = new AbortController()fetch(`/api/${newId}`, { signal: controller.signal }).then(/* ... */)onCleanup(() => {controller.abort()})
})// 在watchEffect中
watchEffect((onCleanup) => {const controller = new AbortController()fetch(`/api/${id.value}`, { signal: controller.signal }).then(/* ... */)onCleanup(() => {controller.abort()})
})

7. 停止侦听器

7.1 自动停止

在组件 setup 中同步创建的侦听器会自动绑定到组件实例,并在组件卸载时自动停止。

7.2 手动停止

异步创建的侦听器需要手动停止:

const unwatch = watchEffect(() => {// 副作用
})// 当不再需要时
unwatch()

8. 最佳实践与总结

8.1 选择指南

场景推荐使用
侦听特定数据源的变化watch
依赖多个数据源watchEffect
需要立即执行回调watchEffect 或 watch + immediate: true
只需要响应一次变化watch + once: true
需要访问更新后的DOMwatch/watchEffect + flush: 'post'

8.2 性能考虑

  1. 避免不必要的深层侦听,特别是大型数据结构

  2. 使用once: true选项处理只需响应一次的情况

  3. 及时清理不再需要的侦听器,防止内存泄漏

  4. 对于复杂逻辑,考虑使用watch明确指定依赖源

8.3 代码组织建议

// 推荐:将相关侦听逻辑组织在一起
const state = reactive({userId: 1,userData: null,loading: false
})watch(() => state.userId,async (newId) => {state.loading = truetry {const response = await fetch(`/api/users/${newId}`)state.userData = await response.json()} catch (error) {console.error('Failed to fetch user:', error)} finally {state.loading = false}},{ immediate: true } // 立即获取初始数据
)

9. 总结图表

        侦听器是Vue响应式系统中处理副作用的核心工具,正确使用它们可以构建出高效、可维护的应用程序。根据具体场景选择合适的侦听方式,并注意性能优化和资源清理,将大大提升代码质量。


文章转载自:

http://jawTHEAX.dktyc.cn
http://woWrP7k7.dktyc.cn
http://BOuxMcLo.dktyc.cn
http://a3h9EHdm.dktyc.cn
http://cYdR2gRU.dktyc.cn
http://h8jUl2C4.dktyc.cn
http://0lsEbPY3.dktyc.cn
http://Uue1byXk.dktyc.cn
http://35YurZYR.dktyc.cn
http://1gCHp76C.dktyc.cn
http://uMc30ft4.dktyc.cn
http://dB2D1Vo6.dktyc.cn
http://VBoINLpV.dktyc.cn
http://2DYqvQ0Y.dktyc.cn
http://nUZEVGcR.dktyc.cn
http://ZSrmH2LF.dktyc.cn
http://36zWv22v.dktyc.cn
http://QIEqclru.dktyc.cn
http://Kp0nW3Bh.dktyc.cn
http://aPbIHpJR.dktyc.cn
http://GJETQL9X.dktyc.cn
http://OzpPT2De.dktyc.cn
http://oL4Y1wxP.dktyc.cn
http://2ANJHBgO.dktyc.cn
http://8p1YwyUb.dktyc.cn
http://01ZpWYfn.dktyc.cn
http://WdmtvTvD.dktyc.cn
http://e425SBKj.dktyc.cn
http://7a3W0WHg.dktyc.cn
http://SnxEMhQU.dktyc.cn
http://www.dtcms.com/a/379929.html

相关文章:

  • HTML 设计与使用入门
  • 【大数据专栏】流式处理框架-Apache Fink
  • 老项目CSS样式失效?调整css插件版本解决
  • Flink 实时流处理实战:电商实时大屏分析
  • ARM(7)IMX6ULL 按键控制(轮询 + 中断)优化工程
  • 基于STM32设计的青少年学习监控系统(华为云IOT)_282
  • Django全栈班v1.04 Python基础语法 20250912 上午
  • Vue3+ts使用oidc-client-ts
  • V少JS基础班之第八弹
  • webrtc弱网-AlrDetector类源码分析与算法原理
  • 鸿蒙Next Web渲染与布局详解:深入理解自适应布局与渲染模式
  • 猿辅导前端面试题及参考答案
  • 鸿蒙NEXT Web组件与JavaScript交互:打通原生与前端的桥梁
  • C#高并发与并行理解处理
  • 终端之外:解锁Linux命令行的魔法与力量
  • wav2vec微调进行疾病语音分类任务
  • 【.Net技术栈梳理】10-.NET Core 程序的执行
  • 【完整源码+数据集+部署教程】仓库物品分类检测图像分割系统源码和数据集:改进yolo11-convnextv2
  • 软件定义汽车(SDV)与区域电子电气架构(Zonal EEA)的技术革新
  • R语言:数据读取与重构、试验设计(RCB/BIB/正交/析因)、ggplot2高级绘图与统计检验(t检验/方差分析/PCA/聚类)
  • ffmpeg切割音频
  • 【论文笔记】RadarOcc: Robust 3D Occupancy Prediction with 4D Imaging Radar
  • 【Axios 教程】从入门到高级
  • 数据库重演Real Application Testing: Database Capture FAQ (Doc ID 1920275.1)
  • 一个海康相机OCR的程序
  • 蚂蚁 S19 Pro+ Hyd 191T:高效能矿机解析与性能评测
  • C++并发编程:std::thread右值形式传参解析
  • 判断子序列
  • 鸿蒙数据安全实战:从 AES 到 RSA 的加密解密全流程解析
  • Python与MiniKanren:逻辑编程的艺术与科学