首页 > 编程笔记 > JavaScript笔记
阅读:571
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 秒后显示警告提示,当然在点击按钮后,监听的回调还会再次执行。
ICP备案:
公安联网备案: