前端vue3 watch
watch作用:监视数据的变化
当你监视的是 「基本类型值」(字符串 / 数字 / 布尔值,比如person2.name/ref(18).value)→ watch监视的是 **【值本身】**;
当你监视的是 「引用类型」(对象 / 数组 / Proxy/RefImpl,比如person2/ref({name:''}))→ watch监视的是 **【内存地址】**;
1、监视ref定义的基本数据类型:
let a=ref(0)
直接监视:
watch(a,(new,old)=>{
//操作内容
})
监视的是基本类型,所以值变化了,new和old就不同
2、监视ref定义的对象类型:
let person=ref({ name:"张三", age:18 }) function changeName(){ person.value.name+='~' } function changeAge(){ person.value.age+=1 } function changePerson(){ person.value={ //地址值会发生变化 name:"李四", age:20 } }使用方式:
watch(person,(newValue,oldValue)=>{
console.log("person的值变化了",newValue,oldValue);
})
此时,由于watch监视的是引用类型,看地址变化,因此调用changeName或changeAge改变单个属性时,地址不变化,不会触发监视,而调用changePerson时,person.value的地址会发生变化,因此会触发监视
解决方法:手动开启深度监视:
watch(person,(newValue,oldValue)=>{
console.log("person的值变化了",newValue,oldValue);
},{deep:true,immediate:true})//深度监视,立即监视(页面一刷新就先执行watch,而不是等person变化了再执行)
在这个watch的回调函数中,newValue和oldValue都是ref对象,需要.value才能获取到里面的值
此时,如果只有单个属性发生变化,newValue和oldValue的值是一样的,因为地址值没有变化,但是如果是全部发生了变化,也就是如果触发了changePerson函数,newValue和oldValue的值就不一样了,因为地址值发生了变化。
3、监视reactive定义的对象类型:
let person1=reactive({ name:"张三", age:18 }) function changeName1(){ person1.name+='~' } function changeAge1(){ person1.age+=1 } function changePerson1(){ Object.assign(person1, {//地址没有变化 name:"李四", age:20 }) }开启监视:
watch(person1,(newValue,oldValue)=>{
console.log("person1的值变化了",newValue,oldValue);
})
监视的是reactive定义的对象,默认开启深度监视,隐式创建深度监视,无法关闭,同上,由于地址没有发生变化(Object.assign不改变地址),所以newValue和oldValue的值是一样的
4、监视ref或reactive定义的对象类型中的某个属性:
let person2=reactive({ name:"张三", age:18, job:{ a:10, b:20 } }) function changeName2(){ person2.name+='~' } function changeAge2(){ person2.age+=1 } function changeJob1(){ person2.job.a+=1 } function changeJob2(){ person2.job.b+=1 } function changeJob(){ person2.job={ //地址值会发生变化 a:100, b:200 } }(1)如果该属性不是对象类型,而是比如name,需要写成函数形式,才能监视到变化,开启监视方式:
watch(()=>{return person2.name},(new,old)=>{
//内容
})
Vue 执行这个函数后,拿到的返回值是 person2.name → 也就是一个 字符串(基本数据类型),值为 '张三'。watch 最终监视的,是这个函数的【返回值】,而不是函数本身,也不是 person2 这个对象。所以值变化了,new和old就会不同
(2)若该属性值是**依然**是【对象类型】,可直接编,也可写成函数,建议写成函数。
直接写:
watch(person2.job,(new,old)=>{})
此时,如果job中的单个属性发生变化,会触发监视,但由于地址不变,new和old是相同的。但是如果调用了:
function changeJob(){
person2.job={ //地址值会发生变化
a:100,
b:200
}
}
来改变job中的内容的话,person2.job的地址就发生变化,相当于此时的person2.job就不是原来的person2.job,就不会触发watch,甚至之后再单单改变a或者b,也不会再触发了(因为watch是挂载在原来的person2.job上的而不是这个person2.job上)

写成函数形式,并开启深度监视后,无论是修改单个属性,还是全部属性,都会触发:
watch(()=>{return person2.job},(newValue,oldValue)=>{
console.log('person2的job变化了11',newValue,oldValue)
},{deep:true})//深度监视
5、监视上述多个数据,组成数组
//监视名字和单个车:
watch([()=>{return person2.name},()=>{return person2.job.a}],(newValue,oldValue)=>{
console.log('person2的name或job.a变化了',newValue,oldValue)
//value是数组[],new和oldvalue不同
},{deep:true})
个人学习记录,如果错误,欢迎指正,也欢迎补充!