首页 > 编程笔记 > JavaScript笔记
阅读:107
Vue3 watch()的用法(非常详细,附带实例)
Vue3 提供的组合式 API 函数 watch(),从功能上看,与选项式 API 的 watch 配置和 $watch 方法相同,但在语法使用上还是有些许差别的。
watch() 函数可以监听一个或多个响应式数据,当响应式数据发生变化时,监听的回调就会自动执行。
watch() 函数接收 3 个参数,具体如下:
1) 第 1 个参数是被监听的一个或多个响应式数据,该参数有 3 种形式,具体如下:
2) 第 2 个参数是监听回调函数,该回调函数可接收两个参数,具体如下:
3) 第 3 个参数是可选的配置对象,包含是否立即执行的 immediate 和是否深度监听的 deep。
请阅读下方代码:
运行后的页面效果如下图所示:

图 1 运行后的页面效果
此时使用 watch() 函数来监听 ref 对象,默认进行的是浅监听,如果需要进行深度监听,则需要配置 deep 为 true,代码如下:
如果对 ref 对象数据进行浅更新,那么两个监听的回调都会执行:
如果对 ref 对象数据进行深度更新,那么前面浅监听的回调不会再执行了:
使用 watch() 函数监听 reactive 对象,默认进行的是深度监听。在按钮的点击回调中,无论是对 person 对象的浅更新,还是深度更新,监听的回调都会执行,代码如下:
如果我们想要监听的是 reactive 对象代理的一个基础类型属性,比如现在想要监听 name 属性,如果直接给 watch() 函数传入 person.name,则程序会直接报错。这是因为它是一个基础类型的值,而不是一个响应式的值,代码如下:
Vue3 针对这种情况,提供了函数式的写法,可以传入一个函数,函数内部返回要监听的这个值:
如果我们想要监听多个不同的数据,要怎么处理呢?其实 watch() 函数可以接收一个包含多个要监听数据的数组。同时,watch() 函数接收的第 1 个参数就是由多个被监听数据的最新值组成的数组,第 2 个参数是旧值的数组。
上面的代码监听的是 ref 对象 countObj 和 reactive 对象 person 中的 name 属性,其监听的回调接收的 newVals 就是最新 countObj 的 value 和最新 person 的 name 组成的数组,而 oldVals 就是旧 countObj 的 value 和旧 person 的 name 组成的数组。
如果在更新函数中对 ref 对象进行浅更新,监听的回调就会执行,代码如下:
如果在更新函数中通过 reactive 对象 person 更新 name 属性,监听的回调就会执行,代码如下:
如果想让监听的回调在初始化时执行一次,就可以配置 immediate 为 true。需要强调的是,还可以在监听的回调中执行异步操作,而这在计算属性的 get 函数中是不可以实现的,代码如下:
watch() 函数可以监听一个或多个响应式数据,当响应式数据发生变化时,监听的回调就会自动执行。
watch() 函数接收 3 个参数,具体如下:
1) 第 1 个参数是被监听的一个或多个响应式数据,该参数有 3 种形式,具体如下:
- 一个 reactive 对象或 ref 对象;
- 返回 reactive 对象中基础类型属性的函数;
- 包含任意多个 reactive 对象、ref 对象或函数的数组。
2) 第 2 个参数是监听回调函数,该回调函数可接收两个参数,具体如下:
- 一个新值或包含多个新值的数组;
- 一个旧值或包含多个旧值的数组。
3) 第 3 个参数是可选的配置对象,包含是否立即执行的 immediate 和是否深度监听的 deep。
请阅读下方代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>watch 函数</title> <script src="https://cdn.bootcdn.net/ajax/libs/vue/3.2.40/vue.global.js"></script> </head> <body> <div id="app"> <p>count: {{ countObj.count }}</p> <p>person: {{ person.name }}-{{ person.addr.city }}</p> <button @click="update">更新</button> </div> <script> const { createApp, ref, reactive, watch } = Vue; createApp({ setup() { const countObj = ref({ count: 0, }); const person = reactive({ name: '张三', addr: { city: '北京', }, }); const update = () => { // 准备更新 ref 或 reactive 数据 }; return { countObj, person, update, }; }, }).mount('#app'); </script> </body> </html>在上面的代码中,我们分别定义了一个 ref 对象 countObj 和一个 reactive 对象 person,同时定义了一个准备更新数据的 update() 函数,并通过 return 返回数据。在模板中读取了 ref 对象和 reactive 对象的数据并进行动态显示,将 update() 函数绑定给按钮的点击监听。
运行后的页面效果如下图所示:

图 1 运行后的页面效果
此时使用 watch() 函数来监听 ref 对象,默认进行的是浅监听,如果需要进行深度监听,则需要配置 deep 为 true,代码如下:
// 浅监听 ref 对象 watch(countObj, (newVal, oldVal) => { console.log('countObj 浅监听', newVal, oldVal); }); // 深度监听 ref 对象 watch( countObj, (newVal, oldVal) => { console.log('countObj 深度监听', newVal, oldVal); }, { deep: true } );
如果对 ref 对象数据进行浅更新,那么两个监听的回调都会执行:
const update = () => { // 对 ref 对象数据进行浅更新 countObj.value = {count: 2}; };
如果对 ref 对象数据进行深度更新,那么前面浅监听的回调不会再执行了:
const update = () => { // 对 ref 对象数据进行深度更新 countObj.value.count = 3; };
使用 watch() 函数监听 reactive 对象,默认进行的是深度监听。在按钮的点击回调中,无论是对 person 对象的浅更新,还是深度更新,监听的回调都会执行,代码如下:
// 监听 reactive 对象,默认进行的是深度监听 watch(person, (newVal, oldVal) => { console.log('person change', newVal, oldVal); }); const update = () => { // 浅更新 person.name += '---'; // 深度更新 person.addr.city += '=='; };
如果我们想要监听的是 reactive 对象代理的一个基础类型属性,比如现在想要监听 name 属性,如果直接给 watch() 函数传入 person.name,则程序会直接报错。这是因为它是一个基础类型的值,而不是一个响应式的值,代码如下:
// 错误写法 watch(person.name, (newVal, oldVal) => { console.log('person.name change', newVal, oldVal); });
Vue3 针对这种情况,提供了函数式的写法,可以传入一个函数,函数内部返回要监听的这个值:
watch(() => person.name, (newVal, oldVal) => { console.log('person.name change', newVal, oldVal); }); const update = () => { // 浅更新 person.name += '---'; };当用户点击“更新”按钮更新 name 属性值时,监听的回调就会自动执行。
如果我们想要监听多个不同的数据,要怎么处理呢?其实 watch() 函数可以接收一个包含多个要监听数据的数组。同时,watch() 函数接收的第 1 个参数就是由多个被监听数据的最新值组成的数组,第 2 个参数是旧值的数组。
// 监听 ref 对象和 reactive 对象中的 name 属性 watch([countObj, () => person.name], (newVals, oldVals) => { console.log('countObj或person.name变化了', newVals, oldVals); });
上面的代码监听的是 ref 对象 countObj 和 reactive 对象 person 中的 name 属性,其监听的回调接收的 newVals 就是最新 countObj 的 value 和最新 person 的 name 组成的数组,而 oldVals 就是旧 countObj 的 value 和旧 person 的 name 组成的数组。
如果在更新函数中对 ref 对象进行浅更新,监听的回调就会执行,代码如下:
const update = () => { countObj.value = {count: 2}; };
如果在更新函数中通过 reactive 对象 person 更新 name 属性,监听的回调就会执行,代码如下:
const update = () => { person.name += '---'; };
如果想让监听的回调在初始化时执行一次,就可以配置 immediate 为 true。需要强调的是,还可以在监听的回调中执行异步操作,而这在计算属性的 get 函数中是不可以实现的,代码如下:
watch(countObj, (newVal, oldVal) => { console.log('立即执行的监听', newVal, oldVal); // 可以执行异步操作 setTimeout(() => { alert('2秒后的提示'); }, 2000); }, {immediate: true}); const update = () => { countObj.value = {count: 2}; };在初始化时监听的回调就会执行一次,且在 2 秒后显示警告提示,当然在点击按钮后,监听的回调还会再次执行。