侦听内容(第一个参数)可以是:
- 一个函数,返回一个值
- 一个 ref
- 一个响应式对象
- 或是由以上类型的值组成的数组
ts
const x = ref(0)
const y = ref(0)
// 单个 ref
watch(x, (newX) => {
console.log(`x is ${newX}`)
})
// getter 箭头函数
watch(
() => x.value + y.value,
(sum) => {
console.log(`sum of x + y is: ${sum}`)
}
)
// 多个来源组成的数组,其中任何一个值的更新都会触发回调函数
watch([x, () => y.value], ([newX, newY]) => {
console.log(`x is ${newX} and y is ${newY}`)
})时机
默认父组件更新 (如有) 之后、所属组件的 DOM 更新之前被调用 DOM 更新后触发 如果希望拿到 DOM 更新后的数据,即在 DOM 更新之后被调用,需要使用 watchPostEffect(),等价于:
ts
watch(source, callback, {
flush: 'post'
})
watchEffect(callback, {
flush: 'post'
})所有更新前触发
ts
watchSyncEffect(() => {
/* 在响应式数据变化时同步执行 */
})等价于:
ts
watch(source, callback, {
flush: 'sync'
})
watchEffect(callback, {
flush: 'sync'
})停止侦听器
默认同步创建的侦听器在组件卸载的时候停止,而异步创建(例如使用了 setTimeOut 创建)的侦听器并不会和宿主组件绑定,此时必须手动停止(调用侦听器返回的函数),防止内存泄漏。
ts
const unwatch = watchEffect(() => {})
// ...当该侦听器不再需要时
unwatch()尽量使用同步的条件侦听代替异步创建侦听。
监视 ref 基本类型数据
js
import { ref,watch } from 'vue';
let num = ref(0);
const x = watch(num,(newVal,oldVal)=>{
console.log(newVal,oldVal);
if(num.value >= 10){
x() //
}
})监视 ref 对象类型数据
- 不能直接监视响应式对象的属性值,应该通过一个箭头
getter函数实现
js
const p = watch(person,(newVal,oldVal)=>{
console.log(newVal,oldVal);
})此时监视的是 person 对象,只有当对象地址改变时才会触发回调函数。
辨析
这里的 newValue 和 oldValue 的判定依据是对象是否变化,如果单独修改对象属性,此时对象地址并没有改变,因此 newValue 和 oldValue 值相同,都指向当前对象。 oldValue 值可被省略。
监视 reactive 对象数据
此时深度监视默认开启,且无法关闭。
js
watch(person,(newVal,oldVal)=>{
console.log(newVal,oldVal)
})监视 reactive 对象属性
由于不能监视基本类型,所以要写一个箭头函数返回一个值(即监视这个函数)
js
watch(()=>{return person.age},()=>{//可简写为()=>person.age
console.log('age changed');
})如果这里监视的属性是某个 reactive 对象属性中的对象,比如:
js
watch(()=>{return person.car},()=>{//car是一个对象
console.log('age changed');
})如果此时整体替换了源对象中的这个 car 对象,会导致声明的监视的对象的地址改变,导致失去对该对象的监视。 因此正确写法为:
js
watch(()=>person.name,(newVal,oldVal)=>{
console.log('person.age changed')
},{deep : true})同时修改 reactive 的多个值
直接令 reactive 对象为另一个对象是不行的,会导致对象失去响应性,要使用 Object.assign 将另一个对象的数据复制到 reactive 对象的相应属性上去。
js
function changeAllPerson() {
Object.assign(person,{name : 'lisi', age : 20})
}此时并没有替换原始对象的地址。
深度监视
开启深度监视 deep,此时属性变化也会触发回调函数, 开启 immediate,在侦听器创建的时候会触发一次回调函数:
js
const p = watch(person,(newVal,oldVal)=>{
console.log(newVal,oldVal);
},{deep:true,immediate:true})//第三个参数:配置对象,immediate是先输出监视信息(类似do-while)监视多个数据
js
watch([()=>person.name, ()=>person.car.c1],(newVal,oldVal)=>{
console.log('person.age changed')
},{deep : true})watchEffect
立即执行一次,自动监视回调函数中使用到的属性(类似于计算属性)
ts
watchEffect(async () => {
const response = await fetch(
`https://jsonplaceholder.typicode.com/todos/${todoId.value}`
)
data.value = await response.json()
})一次性侦听器
触发后即销毁
ts
watch(
source,
(newValue, oldValue) => {
// 当 `source` 变化时,仅触发一次
},
{ once: true }
)