- Overview
-
watch 主要用于监听响应式数据的变化,并在变化时执行副作用操作
监听响应式数据源;当数据源发送变化时,在回调函数中处理响应的逻辑
使用 watch 函数在每次响应式状态发生变化时触发回调函数
侦听的是响应式数据,不能直接侦听响应式数据的属性
三个:数据源 source、回调函数 callback、配置项 options
import { watch } from 'vue'
function watch<T>(
source: WatchSource<T>,
callback: WatchCallback<T>,
options?: WatchOptions
): StopHandle
- Source
-
侦听数据类型 - 4种
. 一个 ref 对象 (包括计算属性)
. 一个 reactive 对象
. 一个 getter 函数:一个有返回的函数
. 多个响应式数据源组成的数组
- Callback
-
侦听时,回调函数会使用2个参数来区分新值 newValue 和旧值 oldValue
通常我们只关心新值 newValue,即:一个参数就够了
若侦听的是 ref 对象的属性,则新值旧值一样,是同一个对象
若侦听的是 ref 对象,则新值是新对象,旧值是老对象,不是同一个对象
onCleanup:回调函数的可选参数,是一个函数,用来注册清理回调;清理回调会在该副作用下一次执行前被调用
- Options
-
1 立即侦听 immediate
watch 默认是懒执行的:仅当数据源变化时,才会执行回调
有时,需要在源变化之前就开始执行回调:设置配置项 immediate为true
如购物车总价,每次进入页面时都先结算一次;此时新值是当前值,而旧值未定义;同初恋一样,无前任
2 深度侦听 deep
默认情况下,只侦听简单类型响应式对象,不能侦听对象的属性或子对象
侦听复合对象内部属性时,需要开启深度侦听:设置 deep 为true
侦听 reactive 对象时,默认开启 deep,且无法关闭
深度侦听需要遍历被侦听对象中的所有嵌套的属性,当用于大型数据结构时,开销很大。因此请只在必要时才使用它,并且要留意性能
- 一个简单数据
-
当单击执行增加函数 inc 时,Vue 可以检测到 num 的变化,从而做出反应;如商品数量增加或减少时,总价发现变化
let num = ref(0)
const inc = () =>{
num.value++
}
watch(num, (newv, oldv) => {
console.log('num old vs new', oldv, newv);
})
如果侦听 num.value,则会提示
Invalid watch source: 0 A watch source can only be a getter/effect function, a ref, a reactive object, or an array of these types.at ...
- 多个简单数据
-
任何一个对象发生变化都会被监听到;是或的关系,不是与的关系
以数组的形式 分别 表示多个数据源:1个数据源变成多个数据源
以数组的形式 分别 显示新值和旧值:1个新值变成多个新值;一个旧值变成多个旧值
[] 信用卡年费免除 - 消费达到一定金额(10000)或消费多少次(6),免除当年年费
let times = ref(0)
let sum = ref(0)
function incTimes() {
times.value++
}
function incSum() {
sum.value += 1000
}
watch([times, sum], ([new1, new2], [old1, old2]) => {
console.log(old1, new1, old2, new2);
})
- 复合数据
-
侦听复合数据,需开启深度侦听:设置 deep为 true
任一属性变化都会被 Vue 捕获;但是变化前后都是同一个对象;所以 newv 和 oldv 是一样的,其内部的属性也是一样的
结论:仅仅知道数据属性发生变化,无法获知前后变化情况
let user = ref({
id: 100,
name: 'glpla',
age: 18,
addr: {
city: 'cq',
code: '541000'
}
})
watch(user, (newv, oldv) => {
console.log('user is watched', newv.age, oldv.age);
}, { deep: true })
更多的是侦听复合数据某个指定属性
利用 函数 获取侦听属性 - getter 函数
仅仅当该属性变化时才触发回调
age 变化时,触发侦听;code 变化时,不触发
watch(() => user.value.age, (n, o) => {
console.log(o, n);
})
官文没有使用 value!!!
无需开启 deep
- 属性变化
-
侦听的是对象某个属性的变化;当某个属性变化时,会被 Vue 捕获
新值旧值是 reactive 对象,变化前后都是同一个对象;所以 newv 和 oldv 是一样的,其内部的属性也是一样的
体会对象的引用特性
结论:可以捕获到数据属性变化,但是无法查看属性前后的变化
let user = reactive({
id: 100,
name: 'glpla',
age: 18,
addr: {
city: 'cq',
code: '541000'
}
})
watch(user, (newv, oldv) => {
console.log('user is watched', newv, oldv);
console.log('user is watched', newv.age, oldv.age);
})
const incAge = () => {
user.age++
}
- 捕获属性前后变化
-
利用 函数 获取侦听的属性 - 简单属性
watch(() => user.age, (newv, oldv) => {
console.log(oldv, newv);
})
利用 函数 获取侦听的属性 - 复合属性
watch(() => user.addr.code, (n, o) => {
console.log(o, n);
})
- 多个属性变化
-
watch([() => user.age, () => user.addr.code], ([n0, n1], [o0, o1]) => {
console.log(o0, n0, o1, n1);
})