【Vue3 入门到实战】5. Watch 监视

server/2025/1/17 23:42:25/

目录

1. 监听ref定义的数据

1.1 监视ref定义的基本类型数据

1.2  监视ref定义的引用类型

1.2.1 修改属性 

1.2.2 修改整个对象 

2. 监视reactive定义的数据

3. 监视ref 和 reactive定义的对象类型中的某个属性

3.1 属性值为基本类型

3.2 属性值为引用类型

4. 监视上述多个数据

5. 总结


在 Vue 3 中,watch 是一个非常强大的工具,用于侦听响应式数据的变化,并在变化时执行相应的逻辑。它不仅可以监听单个 ref 或 reactive 对象,还可以监听多个源或更复杂的表达式。以下是关 watch 的详细说明。

vue3 中,官方规定 watch只能监听以下四种数据

我会根据平时项目中经常遇到的四种情况来进行分段讲解,不是根据上面四种数据分段,但会在四种情况中涵盖以上四种监听数据。

1. 监听ref定义的数据

在之前的文章中,我们得知,ref可以定义基本数据类型,也可以定义引用数据类型。

【Vue3 入门到实战】3. ref 和 reactive区别和适用场景-CSDN博客

1.1 监视ref定义的基本类型数据

代码如下

<template><div class="person">当前求和为{{ sum }}<button @click="total">点击求和</button></div>
</template><script setup lang="ts">import { ref,watch } from 'vue'let sum = ref(0)function total() {sum.value++;}watch(sum, (newValue, oldValue) => {console.log('watch', newValue, oldValue);})
</script><style>
.person {padding: 20px;
}
</style>

控制台输出

1.2  监视ref定义的引用类型

注意:

(1) 直接写数据名,监视的是对象的【地址值】,若想监视对象内部的数据,要开启深度监视。

(2) 若修改的是 ref 定义对象的属性,newValue 和 oldValue 都是新值,因为它们是同一个对象。

(3) 若修改整个 ref 定义的对象,newValue 是新值, oldValue 是旧值,因为不是同一个对象了。

代码如下

<template><div class="person"><h1>情况二:监视【ref】定义的【对象类型】数据</h1><h2>姓名:{{ person.name }}</h2><h2>年龄:{{ person.age }}</h2><button @click="changeName">修改名字</button><button @click="changeAge">修改年龄</button><button @click="changePerson">修改整个人</button></div></template><script lang="ts" setup 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)=>{console.log('person变化了',newValue,oldValue)},{deep:true})</script>
1.2.1 修改属性 

当修改年龄名字属性时,控制台打印如下。

详细说明:

修改对象属性:如果你只是修改 ref 对象的某个属性,实际上并没有改变对象本身的引用,只是改变了对象内部的数据。由于对象本身没有变,所以 newValue 和 oldValue 指向相同的对象。可以得出两个都是都是新的值,所以相等。

1.2.2 修改整个对象 

当修改整个对象时,控制台打印如下。

详细说明:

修改整个对象:当直接赋值一个新的对象给 ref 时,你实际上是改变了 ref 内部的引用。这意味着newValue 和 oldValue 指向了两个不同的对象。newValue 是新对象,而 oldValue 是旧对象。所以不等。

2. 监视reactive定义的数据

注意:

(1) watch 监听 reactive 定义的数据默认是开启深度监视的,也就是不需要手动写 deep换句话说就是 隐式的创建了深层监听

(2) Vue3官方定义不能整体替换 reactive 定义的对象。可以使 Object.assign() 方法可以在不改变对象引用的情况下更新属性。而因此,无论是修改属性还是用Object.assign()替换,oldValuenewValue都是指向的同一个对象,那二者也就是相等。

代码如下

<template><div class="person"><h1>情况三:监视【reactive】定义的【对象类型】数据</h1><h2>姓名:{{ person.name }}</h2><h2>年龄:{{ person.age }}</h2><button @click="changeName">修改名字</button><button @click="changeAge">修改年龄</button><button @click="changePerson">修改整个人</button><hr><h2>测试:{{obj.a.b.c}}</h2><button @click="test">修改obj.a.b.c</button></div></template><script lang="ts" setup name="Person">import {reactive,watch} from 'vue'// 数据let person = reactive({name:'张三',age:18})let obj = reactive({a:{b:{c:666}}})// 方法function changeName(){person.name += '~'}function changeAge(){person.age += 1}function changePerson(){Object.assign(person,{name:'李四',age:80})}function test(){obj.a.b.c = 888}watch(person,(newValue,oldValue)=>{console.log('person变化了',newValue,oldValue)})watch(obj,(newValue,oldValue)=>{console.log('Obj变化了',newValue,oldValue)})</script>

控制台打印 

可以看到无论是修改属性还是用Object.assign()替换,oldValuenewValue都是指向的同一个对象,那二者也就是相等。

3. 监视ref 和 reactive定义的对象类型中的某个属性

一个对象类型中的属性可以基本类型,也可以是对象类型(引用类型)。所以,这节我们需要分成两部分。

3.1 属性值为基本类型

当监视响应式对象中的某个属性,且该属性是基本类型的,要写成函数式——也就是一开始所说的Vue3中点的watch只能监视的四种类型中的 函数返回一个值(getter函数)

假如我只想监听属性 name的变化,其他都不监听。

代码如下

<template><div class="person"><h1>情况三:监视【reactive】定义的【对象类型】数据</h1><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="changeCar">修改车</button><button @click="changePerson">修改整个人</button><hr></div></template><script lang="ts" setup name="Person">import {reactive,watch} from 'vue'// 数据let person = reactive({name:'张三',age:18,car:{c1:'奔驰',c2:'宝马'}})// 方法function changeName(){person.name += '~'}function changeAge(){person.age += 1}function changePerson(){Object.assign(person,{name:'李四',age:80})}function changeCar(){person.car = {c1:'保时捷',c2:'兰博基尼'}}watch(()=>person.name,(newValue,oldValue)=>{console.log('person变化了',newValue,oldValue)})</script>

点击改变修改名字按钮,控制台打印如下,可以看到只监听了name的变化

3.2 属性值为引用类型

当监听的属性式引用类型的时候,可直接编,也可写成函数,但建议写成函数

注意:若是对象监视的是地址值,需要关注对象内部,需要手动开启深度监视。

监听car属性代码(直接编写)

<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="changeFirstCar">修改第一台车</button><button @click="changeSecondCar">修改第二台车</button><button @click="changeCar">修改车</button><hr></div></template><script lang="ts" setup name="Person">import {reactive,watch} from 'vue'// 数据let person = reactive({name:'张三',age:18,car:{c1:'奔驰',c2:'宝马'}})// 方法function changeName(){person.name += '~'}function changeAge(){person.age += 1}function changeFirstCar(){person.car.c1 = '保时捷'}function changeSecondCar(){person.car.c2 = '兰博基尼'}function changeCar(){person.car = {c1:'保时捷',c2:'兰博基尼'}}watch(person.car,(newValue,oldValue)=>{console.log('person变化了',newValue,oldValue)},{deep:true})</script>

这样写的话,点击修改第一台、第二太车,都能监听到 person.car 的变化,但点击修改整个车,是监听不到的,因为,监听的是 person对象中的car属性,而 chanrgCar 方法中, person.car = {c1:'保时捷',c2:'兰博基尼'},这段代码创建了一个新的car,不是之前的person对象中的car了,就监视不到了。

如图,点击 “修改车”按钮,控制台没输出,说明没监视到。而点击第一台车、第二太车按钮,是可以监视的。

 监听car属性代码(函数式)

而写成函数式的话也就是官方所谓的getter函数,vue内部会创建一个依赖收集的追踪,是可以监视到变化的。

 watch(()=>person.car,(newValue,oldValue)=>{console.log('person变化了',newValue,oldValue)},{deep:true})

这样写的话,不仅car的属性变化可以监测,整体变化是可以监视到person.car的变化的。

因为分析源码可知,当你传入的是一个函数时,vue内部每次数据发生变化,watch都会主动跟踪捕获,然后触发对用的callback。

结论:监视的要是对象里的属性,那么最好写函数式,

注意点:若是对象监视的是地址值,需要关注对象内部,需要手动开启深度监视。

所以这里建议,只要你想监视对象中的属性,直接写成函数(返回一个值、也叫getter()函数)的形式

4. 监视上述多个数据

想要监视多少数据,可以写成数组形式。

代码如下

 watch([()=>person.name,person.car],(newValue,oldValue)=>{console.log('person.car变化了',newValue,oldValue)},{deep:true})

注意:这样写,监听的 person.car 就不是通过一个返回值的函数的形式了。点击修改第一台、第二台车可以监听到,但点击修改整个车,就监听不到了。
 

5. 总结

回顾一下,vue3官方规定,watch只能监视如下数据,一是ref定义的数据,二是reactive定义的数据,三是getter函数——一个函数,返回一个值类型,四是以上类型的值组成的数据。在上面的内内容中,只有标题3对不上,但是内容中是有体现第三种数据(getter函数)的。建议的是,当你想要监听对象种的某个属性时(不管是基本类型,还是对象类型),直接用函数的形式监听,也就是一个函数,返回一个值类型。下图所示。

 

更多vue3相关内容可以点击下方链接查看 ↓ ↓ ↓

Vue3入门到实战_借来一夜星光的博客-CSDN博客

 


http://www.ppmy.cn/server/159206.html

相关文章

MySQL的索引

一、索引概述&#xff1a; 索引&#xff08;index&#xff09;是帮助MySQL高效获取数据的数据结构&#xff08;有序&#xff09; 优缺点&#xff1a; 优点&#xff1a;提高数据检索&#xff0c;降低数据库的IO成本&#xff0c;通过索引列对数据库进行排序&#xff0c;降低数据排…

分类统计字符个数(PTA)C语言

本题要求实现一个函数&#xff0c;统计给定字符串中英文字母、空格或回车、数字字符和其他字符的个数。 函数接口定义&#xff1a; void StringCount( char s[] ); 其中 char s[] 是用户传入的字符串。函数StringCount须在一行内按照 letter 英文字母个数, blank 空格或回…

隧道IP广播与紧急电话系统:提升隧道安全的关键技术

隧道IP广播与紧急电话系统&#xff1a;提升隧道安全的关键技术 随着现代城市交通的迅猛发展&#xff0c;隧道作为重要的交通基础设施&#xff0c;其安全性与应急处理能力显得尤为重要。隧道IP广播与紧急电话系统作为保障隧道安全的关键技术&#xff0c;正发挥着越来越重要的作…

代码随想录算法训练营第三十天-贪心算法-763. 划分字母区间

标记字符最远位置&#xff0c;这是人能想到的&#xff1f;定义一个26个字母的数组&#xff0c;下标表示字母的位置&#xff0c;数组值表示当前字母在字符串中遍历过程中所处的位置算法题目无厘头太多&#xff0c;但解法也是太精彩&#xff0c;可是根本记不住&#xff0c;要每日…

【English-Book】Go in Action目录页翻译中文

第8页 内容 前言 xi 序言 xiii 致谢 xiv 关于本书 xvi 关于封面插图 xix 1 介绍 Go 1 1.1 用 Go 解决现代编程挑战 2 开发速度 3 • 并发 3 • Go 的类型系统 5 内存管理 7 1.2 你好&#xff0c;Go 7 介绍 Go 玩具 8 1.3 总结 8 2 Go 快速入门 9 2.1 程序架构 10 2.2 主包 …

HTTP中form-data、x-www-form-urlencoded、raw、binary的区别

前言 在日常接口对接工作中经常遇到如上HTTP请求类型&#xff0c;虽然最常用的是POST但是即便这种方式也会在第三方应用中看到不同的请求格式&#xff1b;现总结下以方便区分。 常见的请求类型 格式说明form-data就是http请求中的multipart/form-data,它会将表单的数据处理为…

微软开源AI Agent AutoGen 详解

AutoGen是微软发布的一个用于构建AI Agent系统的开源框架,旨在简化事件驱动、分布式、可扩展和弹性Agent应用程序的创建过程。 开源地址: GitHub - microsoft/autogen: A programming framework for agentic AI 🤖 PyPi: autogen-agentchat Discord: https://aka.ms/auto…

人工智能之深度学习-[1]-了解深度学习

深度学习 深度学习&#xff08;Deep Learning&#xff09;是机器学习&#xff08;Machine Learning&#xff09;的一种方法&#xff0c;它通过模拟人脑的神经网络结构来进行学习和推理。深度学习使用多层神经网络来分析和建模数据&#xff0c;尤其擅长处理大量数据和复杂模式的…