09Vue3 侦听器详解
一、侦听器概念
侦听器(Watchers)是 Vue 3 中用于观察和响应数据变化的机制。当需要在数据变化时执行异步操作或复杂逻辑时,使用侦听器比计算属性更合适。
二、基本用法
1. 使用 watch 函数
import { ref, watch } from 'vue'
// 示例1:侦听单个响应式数据
const count = ref(0)
watch(count, (newValue, oldValue) => {
console.log(`count从 ${oldValue} 变为 ${newValue}`)
})
// 示例2:侦听多个数据源
const name = ref('张三')
const age = ref(25)
watch([name, age], (newValues, oldValues) => {
console.log('name或age发生了变化')
console.log('新值:', newValues)
console.log('旧值:', oldValues)
})
2. 在组件中使用
<script setup> import { ref, watch, reactive } from 'vue' // 侦听ref const count = ref(0) // 侦听reactive对象的属性 const user = reactive({ name: '张三', age: 25, address: { city: '北京' } }) // 侦听单个属性(需要函数返回值) watch( () => user.name, (newName, oldName) => { console.log(`姓名从 ${oldName} 变为 ${newName}`) } ) // 深度侦听对象 watch( () => user, (newUser, oldUser) => { console.log('user对象发生变化') }, { deep: true } ) // 立即执行 watch( count, (newValue) => { console.log('当前count值:', newValue) }, { immediate: true } ) </script>
三、选项配置
watch( source, callback, { // 深度侦听(用于对象/数组) deep: true, // 立即执行回调 immediate: true, // 回调执行时机 flush: 'pre' | 'post' | 'sync', // 默认 'pre' // 调试用 onTrack: (event) => {}, onTrigger: (event) => {} } )
四、watchEffect 函数
watchEffect 会自动追踪其内部依赖,并在依赖变化时重新执行。
import { ref, watchEffect } from 'vue'
const count = ref(0)
const double = ref(0)
// 自动追踪count依赖
watchEffect(() => {
double.value = count.value * 2
console.log(`double值更新为: ${double.value}`)
})
// 停止侦听
const stop = watchEffect(() => {
// 逻辑...
})
// 手动停止
stop()
watchEffect 的清理机制
watchEffect((onCleanup) => { const timer = setInterval(() => { console.log('定时器执行') }, 1000) // 清理函数 onCleanup(() => { clearInterval(timer) console.log('清理定时器') }) })
五、watch vs watchEffect
| 特性 | watch | watchEffect |
|---|---|---|
| 依赖收集 | 显式指定 | 自动收集 |
| 初始执行 | 需要 immediate: true |
立即执行 |
| 新旧值 | 可以获取 | 无法获取 |
| 适用场景 | 特定数据变化时执行 | 响应式副作用 |
六、实际应用示例
1. 搜索功能
<script setup> import { ref, watch } from 'vue' const searchQuery = ref('') const searchResults = ref([]) const isLoading = ref(false) // 防抖搜索 let timeoutId watch(searchQuery, (newQuery) => { clearTimeout(timeoutId) if (!newQuery.trim()) { searchResults.value = [] return } isLoading.value = true timeoutId = setTimeout(async () => { try { const response = await fetch(`/api/search?q=${newQuery}`) searchResults.value = await response.json() } catch (error) { console.error('搜索失败:', error) } finally { isLoading.value = false } }, 300) }) </script>
2. 表单验证
<script setup> import { ref, reactive, watch } from 'vue' const form = reactive({ email: '', password: '', confirmPassword: '' }) const errors = reactive({}) // 监听表单变化进行验证 watch( () => [form.email, form.password, form.confirmPassword], () => { errors.email = !form.email.includes('@') ? '邮箱格式不正确' : '' errors.password = form.password.length < 6 ? '密码至少6位' : '' errors.confirmPassword = form.password !== form.confirmPassword ? '两次密码不一致' : '' }, { immediate: true } ) </script>
七、性能优化建议
-
避免深度侦听:除非必要,尽量使用浅层侦听
-
及时停止侦听:组件卸载时确保停止不必要的侦听
-
使用防抖/节流:高频变化的数据使用防抖
-
合理使用
watchEffect:依赖明确时使用watch
八、注意事项
-
侦听器回调默认在组件更新前执行(
flush: 'pre') -
异步回调中访问 DOM 时,使用
flush: 'post' -
侦听响应式对象的属性时,需要使用 getter 函数
// 正确
watch(() => obj.count, (val) => console.log(val))
// 错误(不会触发)
watch(obj.count, (val) => console.log(val))
九、组合式 API 中的使用
<script setup>
import { watch, watchEffect } from 'vue'
// 可以多次调用
watch(source1, callback1)
watch(source2, callback2)
watchEffect(effect1)
</script>
侦听器是 Vue 3 响应式系统的核心功能之一,合理使用可以处理各种数据变化带来的副作用,但要注意避免过度使用导致性能问题。

浙公网安备 33010602011771号