watch 监听 ref 数据
- watch 监听 ref 时如: watch(dataRef, …),则仅当更新 dataRef.value 时才会触发
- watch 监听 ref.value 时如: watch(dataRef.value, …),则 dataRef.value 值必须是一个引用数据且会自动开启深度监听
- watch 通过 getter 函数监听 ref 时如: watch(() => dataRef, …) 不带 .value,则必须开启深度监听 {deep: true} 才能监听数据变化,否则数据如何修改都不会被监听
- watch 通过 getter 函数监听 ref.value 时如: watch(() => dataRef.value, …) 带 .value,则仅有修改dataRef.value 值时才会触发,若要监听 dataRef.value.xxx 变化则必须开启深度监听 {deep: true}
watch 监听 reactive 数据
- watch 监听 reactive 数据时如: watch(dataReactive, …),则会自动开启深度监听,对 dataReactive 的内部修改都会被监听到
- watch 监听 reactive 内部某个数据时如: watch(dataReactive.xxx, …),则 dataReactive.xxx 必须是引用数据,不能是基本数据,并且会自动开启深度监听
- watch 通过 getter 函数监听 dataReactive 时如: watch(() => dataReactive, …),则必须开启深度监听 {deep: true} 才能监听数据变化,否则数据如何修改都不会被监听
- watch 通过 getter 函数监听 dataReactive.xxx 时如: watch(() => dataReactive.xxx, …),无论 dataReactive.xxx 是引用数据还是基本数据,仅有修改 dataReactive.xxx 值时才会被监听,若 dataReactive.xxx 为引用数据时,要监听它内部数据变化则必须开启深度监听 {deep: true}
watch 监听多个源
这里是一个普通数组,而数组中的数据是由 ref、reactive、getter 函数 组成
- watch 监听多个源时如 watch([dataReactive, dataRef], …),则 dataReactive 数据会自动开启深度;dataRef 数据仅监听 dataRef.value 值的变化,若想对 dataRef 所有数据监听,则需要开启深度监听{deep: true}
- watch 通过 getter 函数监听如:watch(() => [dataReactive, dataRef], …),此写法无论如何修改数据都不会被监听到,若开启深度监听 {deep: true},则修改 dataReactive, dataRef 内部数据时会被监听到 (不建议这样写)
- watch 通过 getter 函数监听如:watch(() => [dataReactive.obj, dataRef.value.obj], …),仅有修改dataReactive.obj, dataRef.value.obj 对应值时才会被监听,若开启深度监听 {deep: true},则修改 dataReactive.obj, dataRef.value.obj 内部数据时会被监听到 (建议这样使用)
watch 监听 ref、reactive (值为数组) 和监听多个源数组的区别
ref、reactive 对应值的数组是一个响应式的数组,而监听多个源的数组是一个普通数组而普通数组中的数据是由 ref、reactive、getter 函数 组成
ref 监听
监听 ref 值,ref.value 是基本数据类型
/**
* 通过 myName.value 更换值时会触发
* 通过 ref 定义基本数据类型时,不能监听 xxx.value 因为这获取的就是一个具体值
*/
let myName = ref('苹果')
watch(myName, (newValue, oldValue) => {
// myName: 香蕉 苹果
console.log('myName:', newValue, oldValue)
})
myName.value = '香蕉'
监听 ref 值,ref.value 是引用数据类型
/**
* 当监听的ref是引用类型时,仅通过 rex.value 更换值时才会触发监听
* 如果需要监听引用类型内部的变化,则需要添加深度监听 { deep: true }
*/
let myRefObj = ref({ name: '苹果' })
watch(myRefObj, (newValue, oldValue) => {
console.log('myRefObj:', newValue, oldValue)
})
myRefObj.value = '香蕉'
监听 ref.value 值
ref.value 必须是引用类型。如果 ref.value 是基本数据类型,则无法监听
/**
* myRefObj.value 为对象,等同于 监听一个 reactive 对象,侦听器会自动启用深层模式
* 当给 myRefObj.value 赋值新对象时监听不会执行,但 template 中数据还是响应式的
*/
let myRefObj = ref({name: '苹果'})
watch(myRefObj.value, (newValue, oldValue) => {
console.log('myRefObj:', newValue, oldValue)
})
myRefObj.value.name = '香蕉' // 会监听到
// myRefObj.value = {name: '栗子'} // 不会监听到
reactive 监听
监听 reactive 对象的基本数据类型
/**
* 通过 myObj.name 更换值时会触发(myObj.name 需是基本数据类型)
* 当直接侦听一个响应式对象时,侦听器会自动启用深层模式
*/
let myObj = reactive({ name: '小明', age: 20, info: { address: 'bj' } })
watch(myObj, (newValue, oldValue) => {
// myObj:都是 {name: '小红', age: 20}
console.log('myObj:', newValue, oldValue)
})
myObj.name = '小红'
监听 reactive 对象的引用数据类型
/**
* 监听 myObj.info 值
* 仅更换 myObj.info 内的数据时才会被监听到
* 通过 reactive 定义引用类型时,如果通过 xxx.xx 获取的是基本类型时,则不能监听 xxx.xx 数据;如果通过 xxx.xx 获取的是引用类型时,则可以监听 xxx.xx 数据
*/
let myObj = reactive({ name: '小明', age: 20, info: { address: 'bj' } })
watch(myObj.info, (newValue, oldValue) => {
console.log('myObj.info:', newValue, oldValue)
})
myObj.info.address = 'sh'
函数监听
一个函数,必须返回一个值,只有当值发生变化时,才会触发回调
监听 ref.value 数据时
- 当 ref.value 返回基本数据类型时,通过ref.value值就可以监听到
- 当 ref.value 返回引用数据类型时,仅通过修改 ref.value值时可以被监听到,当修改对象内部值时是无法被监听到,此时需要添加 { deep: true} 启用深度监听
let myName = ref('苹果')
watch(
() => myName.value,
(newValue, oldValue) => {
console.log('myName:fn:', newValue, oldValue)
}
)
myName.value = '香蕉'
监听 ref 对象时
不管是监听 reactive 对象,还是监听 ref 对象,都不会自动启用深度监听,必须通过添加 { deep: true },这样当修改对象内部数据时才会被监听到
let myName = ref('苹果')
watch(
() => myName,
(newValue, oldValue) => {
console.log('myName:deep:fn:', newValue, oldValue)
},
{ deep: true }
)
myName.value = '香蕉'
监听 reactive 数据的基本类型时
let myObj = reactive({ name: '小明', age: 20, info: { address: 'bj'} })
watch(
() => myObj.name,
(newValue, oldValue) => {
console.log('myObj:fn:', newValue, oldValue)
}
)
myObj.name = '小红'
监听 reactive 数据的引用类型时
/**
* 这里返回的是对象对应的地址
*/
let myObj = reactive({ name: '小明', age: 20, info: { address: 'bj'} })
watch(
() => myObj.info,
(newValue, oldValue) => {
console.log('myObj:deep:fn:', newValue, oldValue)
},
{ deep: true }
)
myObj.name = '小红'
注意:myObj.info 是一个对象,当启用深度监听后,修改 myObj.info 为另一个对象或修改 myObj.info 内部属性的值时都会触发回调
侦听多个来源
// 当侦听多个来源时,回调函数接受两个数组,分别对应来源数组中的新值和旧值
watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => {
/* ... */
})
watchEffect使用
watchEffect 首次加载先执行一次,即便是空函数也会执行
watchEffect(() => {
})
watch 和 watchEffect 特点
watch特点
- 懒执行,仅当数据变化时执行(immediate: true 除外)
- 更加明确需要侦听的数据源,更精准的控制回调函数的触发时机
- 可以访问所侦听状态的前一个值和当前值
watchEffect特点
- 首次加载会执行一次,即便是空函数
- 自动追踪所有能访问到的响应式属性,任一属性发生变化都会触发回调函数
- 无法获取前一个值和当前值
flush: 调整回调函数的刷新时机
- pre: 默认值,回调会在 Vue 组件更新之前被调用,此时在回调中访问的 DOM 将是 Vue 更新之前的状态
- post: Vue 组件更新之后调用侦听器的回调函数。此时在回调函数中访问的 DOM 将是 Vue 更新之后的状态
- sync: 同步执行,当侦听到变化时回调函数立即执行,执行完成后才接着执行后面的代码