首页 > 编程笔记 > JavaScript笔记 阅读:107

Vue3 watch()的用法(非常详细,附带实例)

Vue3 提供的组合式 API 函数 watch(),从功能上看,与选项式 API 的 watch 配置和 $watch 方法相同,但在语法使用上还是有些许差别的。

watch() 函数可以监听一个或多个响应式数据,当响应式数据发生变化时,监听的回调就会自动执行。

watch() 函数接收 3 个参数,具体如下:
1) 第 1 个参数是被监听的一个或多个响应式数据,该参数有 3 种形式,具体如下:
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 秒后显示警告提示,当然在点击按钮后,监听的回调还会再次执行。

相关文章