watch监听
watch监听
特别注意:凡是监视对象类型,只要引用没有发生变化,oldValue和newValue一致。
作用:监视数据的变化(和Vue2
中的watch
作用一致)
特点:Vue3
中的watch
只能监视以下四种数据:
ref
定义的数据。
reactive
定义的数据。
函数返回一个值(getter
函数)。
一个包含上述内容的数组。
我们在Vue3
中使用watch
的时候,通常会遇到以下几种情况:
情况一 监视ref
定义的【基本类型】数据
监视ref
定义的【基本类型】数据:直接写数据名即可,不用添加.value,监视的是其value
值的改变。
<template> <div class="person"> <h2>监视ref定义的【基本类型】数据:直接写数据名即可,监视的是其value值的改变。</h2> <h2>当前求和数据: {{sum}}</h2> <button @click="changeSum">点我sum + 1</button> </div> </template> <script setup lang="ts" name="Person"> import {ref, watch} from 'vue' //数据 let sum = ref(0) //方法 function changeSum() { sum.value += 1; } //监视 const stopWatch = watch(sum, (newVlaue, oldValue) => { //参数说明:监视对象, 回调函数 console.log('sum变化了从' + oldValue + "变为了" + newVlaue); if(sum.value >= 10) { stopWatch() //返回的是一个停止监听的函数 } }) </script> <style> .person { background-color: skyblue; box-shadow: 0 0 10px; /* 盒子阴影 */ border-radius: 10px; padding: 20px; } button { margin: 0 5px; } </style>
情况二 监视ref
定义的【对象类型】数据
监视ref
定义的【对象类型】数据:直接写数据名,监视的是对象的【地址值】,若想监视对象内部的数据,要手动开启深度监视。
注意:
若修改的是ref
定义的对象中的属性,newValue
和 oldValue
都是新值,因为它们是同一个对象。
若修改整个ref
定义的对象,newValue
是新值, oldValue
是旧值,因为不是同一个对象了。
<template> <div class="person"> <h2>监视ref定义的【对象类型】数据</h2> <h2>姓名: {{person.name}}</h2> <h2>年龄: {{person.age}}</h2> <button @click="changeName">修改名字</button> <button @click="changeAge">修改年龄</button> <button @click="changePerson">修改人</button> </div> </template> <script setup lang="ts" name="Person"> import {ref, watch} from 'vue' //数据 let person = ref({ name: '张三', age: 18 }) //方法 function changeName() { person.value.name += "~"; } function changeAge() { person.value.age += 1; } function changePerson() { person.value = {name: '李四', age: 90}; } //监视 // watch(person, (newValue, oldValue) => { //直接这样写,只会监视person这个对象的变化,对于其内部的变化不会触发 // console.log('person从: ', oldValue, "变为: ", newValue); // }); //深度监视 watch(person, (newValue, oldValue) => { //需要传递第三个参数 {deep:true} console.log('person从: ', oldValue, "变为: ", newValue); }, {deep: true}); //### 还可以添加参数 {immediate:?} 这样初始化的时候也会监视一下 </script> <style> .person { background-color: skyblue; box-shadow: 0 0 10px; /* 盒子阴影 */ border-radius: 10px; padding: 20px; } button { margin: 0 5px; } </style>
情况三 监视reactive
定义的【对象类型】数据
监视reactive
定义的【对象类型】数据,且默认开启了深度监视。
<template> <div class="person"> <h2>监视reactive定义的【对象类型】数据,且默认开启了深度监视。</h2> <h2>姓名: {{person.name}}</h2> <h2>年龄: {{person.age}}</h2> <button @click="changeName">修改名字</button> <button @click="changeAge">修改年龄</button> <button @click="changePerson">修改人</button> </div> </template> <script setup lang="ts" name="Person"> import {reactive, watch} from 'vue' //数据 let person = reactive({ name: '张三', age: 18 }) //方法 function changeName() { person.name += "~"; } function changeAge() { person.age += 1; } function changePerson() { // person = {name: '李四', age: 90}; //这里由于使用了reactive所以不能直接修改对象 //注意:这里这个引用没有发生变化哦 Object.assign(person, {name: '李四', age: 90}); //需要使用这种方式,响应式才不会被破坏 } //监视 因为person是reactive定义的 默认深度监视,无法关闭 watch(person, (newValue, oldValue) => { //因为person是reactive定义的,直接这样写,默认就开启了deep监视 console.log('person从: ', oldValue, "变为: ", newValue); }); </script> <style> .person { background-color: skyblue; box-shadow: 0 0 10px; /* 盒子阴影 */ border-radius: 10px; padding: 20px; } button { margin: 0 5px; } </style>
情况四 监视ref
或reactive
定义的【对象类型】数据中的某个属性
监视ref
或reactive
定义的【对象类型】数据中的某个属性,注意点如下:
- 若该属性值不是【对象类型】,需要写成函数形式。
- 若该属性值是依然是【对象类型】,可直接编,也可写成函数,建议写成函数。
结论:监视的要是对象里的属性,那么最好写函数式,注意点:若是对象监视的是地址值,需要关注对象内部,需要手动开启深度监视。
<template> <div class="person"> <h2>姓名:{{ person.name }}</h2> <h2>年龄:{{ person.age }}</h2> <h2>汽车:{{ person.car.c1}}、{{ person.car.c2 }}</h2> <button @click="changeName">修改名字</button> <button @click="changeAge">修改年龄</button> <button @click="changeOneCar">修改第一台车</button> <button @click="changeTwoCar">修改第二台车</button> <button @click="changeCar">修改整个车</button> </div> </template> <script setup lang="ts" name="Person"> import {reactive, watch} from 'vue' //数据 let person = reactive({ name: '张三', age: 20, car: { c1: '小米', c2: '奔驰' } }) //方法 function changeName() { person.name += '~'; } function changeAge() { person.age += 1; } function changeOneCar() { person.car.c1 += '~'; } function changeTwoCar() { person.car.c2 += '~'; } function changeCar() { Object.assign(person, { name: '李四', age: 30, car: { c1: '大众', c2: '马自达' } }) } //监听, 为了监视响应式对象中的某个对象,且该属性是:基本数据类型,要写为函数式 watch(() => person.name, (newValue, oldValue) => { console.log('person.name变化了', newValue, oldValue); }) //##### 监听对象中的对象 ###### // watch(person.car, (newValue, oldValue) => { //可以发现监视响应式对象中的对象属性ok的,但是修改整个外层对象时,又无法监听到 // console.log('person.car变化了', newValue, oldValue); // }) // watch(() => person.car, (newValue, oldValue) => { //而使用函数式后 car整体变化ok了,但是细节变化又不行了,因为监听变化的是car变量的引用了 // console.log('person.car变化了', newValue, oldValue); // }) //##### 所以得出如果想要 监听对象中的对象 细枝末节变和整体变都可以监听到的最佳实践 ###### watch(() => person.car, (newValue, oldValue) => { console.log('person.car变化了 或者 car中的属性变化了', newValue, oldValue); }, {deep: true}) // watch(() => person.car.c1, (newValue, oldValue) => { // console.log('person.car.c1变化了', newValue, oldValue); // }) </script> <style> .person { background-color: skyblue; box-shadow: 0 0 10px; /* 盒子阴影 */ border-radius: 10px; padding: 20px; } button { margin: 0 5px; } </style>
监听对象中的对象最佳实践:
//##### 监听对象中的对象 ###### // watch(person.car, (newValue, oldValue) => { //可以发现监视响应式对象中的对象属性ok的,但是修改整个外层对象时,又无法监听到 // console.log('person.car变化了', newValue, oldValue); // }) // watch(() => person.car, (newValue, oldValue) => { //而使用函数式后 car整体变化ok了,但是细节变化又不行了,因为监听变化的是car变量的引用了 // console.log('person.car变化了', newValue, oldValue); // }) //##### 所以得出如果想要 监听对象中的对象 细枝末节变和整体变都可以监听到的最佳实践 ###### watch(() => person.car, (newValue, oldValue) => { console.log('person.car变化了 或者 car中的属性变化了', newValue, oldValue); }, {deep: true})
情况五 监视上诉的多个数据
监视上述的多个数据,即我们的watch使用时第一个参数可以传递一个数组,只要其中的一个发生变化都会执行回调函数。这里对应的写法都推荐函数式。说明:基本类型也可以使用函数式写法如:() => name.value
<template> <div class="person"> <h2>姓名:{{ person.name }}</h2> <h2>年龄:{{ person.age }}</h2> <h2>汽车:{{ person.car.c1}}、{{ person.car.c2 }}</h2> <button @click="changeName">修改名字</button> <button @click="changeAge">修改年龄</button> <button @click="changeOneCar">修改第一台车</button> <button @click="changeTwoCar">修改第二台车</button> <button @click="changeCar">修改整个车</button> </div> </template> <script setup lang="ts" name="Person"> import {reactive, ref, watch} from 'vue' //数据 let name = ref(0); let person = reactive({ name: '张三', age: 20, car: { c1: '小米', c2: '奔驰' } }); //方法 function changeName() { person.name += '~'; } function changeAge() { person.age += 1; } function changeOneCar() { person.car.c1 += '~'; } function changeTwoCar() { person.car.c2 += '~'; } function changeCar() { Object.assign(person, { name: '李四', age: 30, car: { c1: '大众', c2: '马自达' } }) } //监听 watch([() => person.name, () => person.car.c1], (newValue, oldValue) => { console.log('person.name变化了 或者 person.car.c1', newValue, oldValue); }, {deep: true}) </script> <style> .person { background-color: skyblue; box-shadow: 0 0 10px; /* 盒子阴影 */ border-radius: 10px; padding: 20px; } button { margin: 0 5px; } </style>
本文作者:如此而已~~~
本文链接:https://www.cnblogs.com/fragmentary/p/18626669
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步