谷歌电子书google play 图书app
20.64M · 2025-09-24
watchEffect
会立即执行传入的函数,并响应式地追踪其依赖,当依赖发生变化时重新执行。
import { ref, watchEffect } from 'vue'
const count = ref(0)
const name = ref('张三')
// 自动追踪依赖并立即执行
watchEffect(() => {
console.log(`count: ${count.value}, name: ${name.value}`)
})
// 输出: count: 0, name: 张三
count.value++ // 输出: count: 1, name: 张三
name.value = '李四' // 输出: count: 1, name: 李四
const stop = watchEffect(() => {
console.log(count.value)
})
// 停止监听
stop()
watchEffect((onInvalidate) => {
const timer = setTimeout(() => {
console.log('定时器执行')
}, 1000)
// 在下次执行前或组件卸载时清除
onInvalidate(() => {
clearTimeout(timer)
})
})
watch
需要明确指定监听的数据源,只有当数据源发生变化时才会执行回调函数。
import { ref, watch } from 'vue'
const count = ref(0)
watch(count, (newValue, oldValue) => {
console.log(`count 从 ${oldValue} 变为 ${newValue}`)
})
count.value = 1 // 输出: count 从 0 变为 1
const firstName = ref('张')
const lastName = ref('三')
watch([firstName, lastName], ([newFirst, newLast], [oldFirst, oldLast]) => {
console.log(`姓名从 ${oldFirst}${oldLast} 变为 ${newFirst}${newLast}`)
})
import { reactive, watch } from 'vue'
const user = reactive({ name: '张三', age: 25 })
// 监听整个对象
watch(user, (newUser, oldUser) => {
console.log('用户信息发生变化', newUser)
}, { deep: true })
// 监听对象的特定属性
watch(() => user.name, (newName, oldName) => {
console.log(`姓名从 ${oldName} 变为 ${newName}`)
})
watch(
source,
callback,
{
immediate: true, // 立即执行一次
deep: true, // 深度监听
flush: 'post' // 回调执行时机
}
)
在 Vue 3 中,watch
监听对象和对象属性有很大的区别,让我详细解释一下:
import { reactive, watch } from 'vue'
const user = reactive({
name: '张三',
age: 25,
address: {
city: '北京',
street: '朝阳区'
}
})
// 监听整个对象 - 默认是深度监听
watch(user, (newUser, oldUser) => {
console.log('用户对象发生变化')
console.log('新值:', newUser)
console.log('旧值:', oldUser)
// 注意:newUser 和 oldUser 指向同一个对象!
})
user.name = '李四' // 触发监听
user.age = 26 // 触发监听
user.address.city = '上海' // 触发监听
重要特点:
reactive
对象的监听默认是深度的newUser
和 oldUser
实际上是同一个对象引用import { ref, watch } from 'vue'
const user = ref({
name: '张三',
age: 25
})
// 需要显式开启深度监听
watch(user, (newUser, oldUser) => {
console.log('用户对象发生变化')
}, { deep: true }) // 必须设置 deep: true
// 或者监听 .value
watch(user.value, (newUser, oldUser) => {
console.log('用户对象发生变化')
})
user.value.name = '李四' // 触发监听
const user = reactive({
name: '张三',
age: 25,
address: {
city: '北京',
street: '朝阳区'
}
})
// 监听单个属性
watch(() => user.name, (newName, oldName) => {
console.log(`姓名从 ${oldName} 变为 ${newName}`)
})
// 监听嵌套属性
watch(() => user.address.city, (newCity, oldCity) => {
console.log(`城市从 ${oldCity} 变为 ${newCity}`)
})
// 监听嵌套对象(需要深度监听)
watch(() => user.address, (newAddress, oldAddress) => {
console.log('地址对象发生变化')
}, { deep: true })
user.name = '李四' // 只触发 name 的监听
user.address.city = '上海' // 只触发 city 的监听
user.age = 26 // 不触发任何上述监听
监听方式 | 语法 | 触发条件 | 新旧值 | 性能 |
---|---|---|---|---|
整个对象 | watch(obj, callback) | 对象任何属性变化 | 同一个对象引用 | 较低(监听所有属性) |
特定属性 | watch(() => obj.prop, callback) | 只有该属性变化 | 真实的新旧值 | 较高(只监听指定属性) |
// 表单数据整体验证
const formData = reactive({
username: '',
email: '',
password: ''
})
watch(formData, (newData) => {
// 任何表单字段变化都重新验证整个表单
validateForm(newData)
})
// 只关心特定字段的变化
watch(() => formData.email, (newEmail) => {
// 只有邮箱变化时才验证邮箱格式
validateEmail(newEmail)
})
watch(() => formData.username, (newUsername) => {
// 只有用户名变化时才检查是否重复
checkUsernameAvailability(newUsername)
})
// 监听多个特定属性
watch(
[() => user.name, () => user.age],
([newName, newAge], [oldName, oldAge]) => {
console.log(`姓名: ${oldName} -> ${newName}`)
console.log(`年龄: ${oldAge} -> ${newAge}`)
}
)
// 监听对象的多个嵌套属性
watch(
[() => user.address.city, () => user.address.street],
([newCity, newStreet], [oldCity, oldStreet]) => {
console.log('地址信息发生变化')
}
)
// 性能较差 - 监听整个对象
watch(largeObject, (newVal) => {
// 任何属性变化都会触发
updateUI()
})
// 性能较好 - 只监听需要的属性
watch(() => largeObject.importantProperty, (newVal) => {
// 只有重要属性变化才触发
updateUI()
})
// 按需监听多个属性
watch(
[() => obj.prop1, () => obj.prop2],
([newProp1, newProp2]) => {
// 只有这两个属性变化才触发
updateSpecificUI(newProp1, newProp2)
}
)
const user = reactive({
profile: { name: '张三' }
})
// 监听嵌套对象属性时的陷阱
watch(() => user.profile, (newProfile, oldProfile) => {
// newProfile 和 oldProfile 是同一个对象!
console.log(newProfile === oldProfile) // true
}, { deep: true })
// 如果需要真正的新旧值对比,监听具体属性
watch(() => user.profile.name, (newName, oldName) => {
// 这里的 newName 和 oldName 是不同的值
console.log(newName === oldName) // false
})
总的来说,watchEffect
更适合简单的副作用操作和自动依赖收集,而 watch
更适合需要精确控制监听目标和获取新旧值的场景。
20.64M · 2025-09-24
60.56MB · 2025-09-24
28.31MB · 2025-09-24