浅谈Vue中监听属性—watch监听器的使用方法

发布时间:2024年01月17日

目录

💡 监听属性的概念

💡 watch有什么作用

💡 watch的基本语法

💡 监听属性的优缺点

💡?使用watch的场景


💡 监听属性的概念

在计算机科学中,watch是一种调试技术,用于监视程序运行时特定变量的值。当程序在调试器控制下执行时,调试器会显示变量的当前值,并在程序执行过程中自动更新该值。

在Vue中,watch 是一种用于监测数据变化并做出回应的技术。watch 可以监听任何一个数据属性,并在该属性发生变化时执行指定的函数。


💡 watch有什么作用

watch 可以监听数据的变化,并在数据变化时执行所指定的回调函数。它可以做以下几件事情:

? 监听数据变化:watch 可以监听 Vue 实例上的任何数据变化,包括简单数据类型、对象、数组和计算属性等。

? 接收新旧值:当数据发生变化时,watch 回调函数会接受到两个参数,分别是新值和旧值,这可以方便我们比较数据变化,进一步做出相应的处理。

? 执行响应函数:watch 的主要作用就是执行我们所指定的响应函数,以便我们对数据变化作出及时的响应,如重新计算、渲染视图或发送网络请求等。

? 深度监听:watch 还可以通过配置 deep 选项来深度监听嵌套对象的变化,这样当嵌套对象中的属性发生变化时也能捕获到。

? 立即执行:watch 还可以通过配置 immediate 选项来在初始化组件时立即执行回调函数,而不必等待数据变化。

? ?取消监听:当一个 watch 监听器不再需要时,可以使用 unwatch 方法来取消监听。

综上所述,watch 可以监听数据变化并执行相应操作,这使得我们可以很方便地对数据变化做出处理和重新计算。在实际开发中,watch 经常被用来检测表单输入变化、监听状态变化以及优雅地处理异步操作等。


💡 watch的基本语法

// 对象式写法
watch: {
? // 监听的属性名
? 属性名: {
? ? handler: function (newVal, oldVal) {
? ? ? // 对属性变化作出响应
? ? }
? }
}

// 函数式写法
watch: {
? // 监听的属性名,参数为新旧值
? '属性名'(newVal, oldVal) {
? ? // 对属性变化作出响应
? }
}

其中,handler 是一个函数,其第一个参数是属性的新值第二个参数是属性的旧值

属性名 是需要监听的属性名称。当属性发生变化时,watch 可以触发指定的响应函数来处理这个变化,比如,重新计算或发送请求等。

watch 可以监听对象、数组、计算属性等数据类型的变化,也可以通过 deep 选项来深度监听嵌套对象的变化,还可以使用 immediate 选项来立即执行回调函数。

通过示例来进一步了解监听属性

示例一:

new Vue({ ?
? data: { ?
? ? message: 'Hello Vue!' ?
? }, ?
? watch: { ?
? ? // 当 `message` 属性发生变化时,执行 `handleMessageChange` 函数 ?
? ? message(newVal, oldVal) { ?
? ? ? console.log('message changed from', oldVal, 'to', newVal); ?
? ? } ?
? }, ?
? methods: { ?
? ? handleMessageChange(newVal, oldVal) { ?
? ? ? console.log('message changed from', oldVal, 'to', newVal); ?
? ? } ?
? } ?
});

在上面的示例中,我们通过watch选项观察了message属性的变化。当message的值发生改变时,回调函数将会被触发,并输出新的值和旧的值。

除了直接在回调函数中执行逻辑外,还可以使用命名函数作为回调函数,或者使用箭头函数。此外,还可以在回调函数中返回一个值,以便在数据变化后执行其他操作。

除了观察数据的变化,watch选项还可以用于观察计算属性或方法。在这种情况下,回调函数将会在计算属性或方法的结果发生变化时被触发。

示例二:

<template>
? <div>
? ? <p>当前计数:{{ count }}</p>
? ? <button @click="increment">+1</button>
? </div>
</template>

<script>
export default {
? data() {
? ? return {
? ? ? count: 0,
? ? };
? },
? watch: {
? ? count(newValue, oldValue) { // 监听 count 变化
? ? ? console.log(`count 变化,新值为 ${newValue},旧值为 ${oldValue}`);
? ? },
? },
? methods: {
? ? increment() {
? ? ? this.count++; // 改变 count 的值
? ? },
? },
};
</script>

上面的示例中,我们定义了一个 count 数据属性,并使用 watch 监听它的变化。在按钮点击事件中,我们改变了 count 的值,watch 监听到了数据的变化并执行了回调函数,输出了新旧值信息。

还可以通过配置 deep 和 immediate 选项来深度监听和在组件初始化时立即执行回调函数。

<script>
export default {
? data() {
? ? return {
? ? ? person: {
? ? ? ? name: 'Tom',
? ? ? ? age: 18,
? ? ? },
? ? };
? },
? watch: {
? ? 'person.name'(newValue, oldValue) { // 深度监听 person.name 的变化
? ? ? console.log(`person.name 变化,新值为 ${newValue},旧值为 ${oldValue}`);
? ? },
? },
? created() {
? ? this.$watch('person', (newValue, oldValue) => { // 深度监听 person 对象及其子属性的变化
? ? ? console.log('person 变化', newValue, oldValue);
? ? }, { deep: true });

? ? this.$watch('person.name', (newValue, oldValue) => { // 初始化时立即执行回调函数
? ? ? console.log(`person.name 变化,新值为 ${newValue},旧值为 ${oldValue}`);
? ? }, { immediate: true });
? },
};
</script>

或是?

<script>
export default {
? data() {
? ? return {
? ? ? person: {
? ? ? ? name: 'Tom',
? ? ? ? age: 18,
? ? ? },
? ? };
? },
? watch: {
? ? 'person.name':{
        handler(newValue, oldValue) { // 深度监听 person.name 的变化
? ? ?   console.log(`person.name 变化,新值为 ${newValue},旧值为 ${oldValue}`);
? ?     },

        // 当要监听对象/对象某个属性或数组、数组元素的时候需要添加deep:true属性
        deep: true; // 深度监听 person 对象及其子属性的变化

        // 如果想在第一次绑定的时候执行此监听函数 则需要设置immediate属性
        immediate: true; // 初始化时立即执行回调函数
  },
};
</script>

在这里,我们使用 watch 深度监听了 person.name 的变化,并在创建组件时使用 $watch 方法深度监听 person 对象的变化,同时设置了 immediate 选项,在初始化时立即执行回调函数。

参考watch事件监听三种用法-CSDN博客 |?watch监听事件的多种用法-ViewDesign

番外:vue - 组件中watch:{}监听与 this.$watch()的区别


💡 监听属性的优缺点

优点:

响应式:watch 可以实现数据的响应式监测,即在数据变化时自动执行回调函数,方便及时地对变化做出处理。

灵活性:watch 可以监听任意数据属性,并执行自定义的回调函数,使得我们可以根据具体需求做出相应的操作。

深度监听:watch 可以通过配置 deep 选项来深度监听嵌套对象的变化,不仅监听父级对象的变化,还能捕获到子级对象属性的变化。

初始化执行:watch 可以通过配置 immediate 选项在组件初始化时立即执行回调函数,而不必等待数据变化。

取消监听:当一个 watch 不再需要时,可以通过 unwatch 方法来取消监听,避免不必要的资源消耗。

缺点:

异步问题:watch 回调函数是异步执行的,在一些特定场景下,可能无法立即获取到最新的数据。如果需要立即获取到最新数据,可能需要配合 $nextTick 或使用计算属性来解决。

频繁触发:如果被监听的数据频繁变化,可能会导致 watch 回调函数被频繁触发,影响性能。此时,可以通过配置 immediate 选项和优化逻辑来减少不必要的回调触发。

复杂性:当使用多个 watch 监听多个数据时,可能会导致代码复杂度增加,维护起来稍显困难。在这种情况下,可以考虑使用计算属性来代替 watch。

那我们该怎么样去处理这些缺点呢?

? 处理异步问题:可以使用 $nextTick 方法来确保在更新视图之后再执行回调函数,以获取最新的数据。

watch: {
? count: {
? ? handler(newValue, oldValue) {
? ? ? this.$nextTick(() => {
? ? ? ? console.log(`count 变化,新值为 ${newValue},旧值为 ${oldValue}`);
? ? ? ? // 在这里进行相应的操作
? ? ? });
? ? },
? ? immediate: true,
? },
}

? 优化频繁触发:如果被监听的数据频繁变化,可以考虑通过设置 immediate 选项或优化逻辑来减少不必要的回调触发。例如,可以使用 debounce 或 throttle 函数来限制回调函数的执行频率,以避免过多的触发。

? 简化复杂性:当使用多个 watch 监听多个数据时,可以考虑使用计算属性来代替 watch。计算属性具有自动的依赖跟踪和缓存机制,能够简化代码并提高性能。

computed: {
? countInfo() {
? ? return `当前计数:${this.count}`;
? },
},
watch: {
? countInfo(newValue, oldValue) {
? ? console.log(`countInfo 变化,新值为 ${newValue},旧值为 ${oldValue}`);
? },
},

这样,通过计算属性 countInfo 来监听 count 的变化,代码会更加清晰和易于维护。

综上所述,watch 提供了一种方便而强大的数据监测技术,但需要注意处理异步问题和频繁触发的情况,以及根据实际场景选择最佳的数据监听方式。


💡?使用watch的场景

数据监听:当数据发生变化时,可以使用 watch 来监听数据的变化,并在变化时执行相应的操作。例如,监听表单字段的变化,当表单字段发生变化时,可以根据新的值进行实时的验证、计算或发送请求等操作。

异步操作:当需要监听异步操作的结果或状态时,可以使用 watch 来监视异步操作的变化。例如,监视网络请求的结果,当请求返回时,可以根据返回的数据更新组件的状态或进行后续操作。

路由变化:当路由发生变化时,例如切换页面或参数变化,可以使用 watch 监听 $route 对象的变化,并根据新的路由信息进行相应的页面更新或数据加载操作。|?Vue中监听路由参数变化的几种方式

深度监听对象或数组:当需要深度监听对象或数组内部属性的变化时,可以使用 watch 来进行深度监听。例如,监听一个复杂的数据结构,当其中某个属性发生变化时,可以触发相应的操作。

状态管理:当使用状态管理工具(如 Vuex)时,可以使用 watch 来监听状态的变化,并根据状态的变化进行相应的处理。例如,监听某个状态的变化,在状态变化时更新视图或触发其他操作。

总而言之,watch 适用于需要监听数据变化并执行相应操作的场景,特别是在需要处理异步操作、深度监听对象或数组、响应路由变化等情况下。

使用watch还需要注意的几个点:

1. 主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操作,可以看作是 computed 和 methods 的结合体;

2. 可以监听的数据来源:data,props,computed内的数据;

3. watch支持异步;

4. 不支持缓存,监听的数据改变,直接会触发相应的操作;

5. 监听函数有两个参数,第一个参数是最新的值,第二个参数是输入之前的值,顺序一定是新值,旧值。


? 参考资料

vue2中watch(侦听器)讲解以及解决深度监听新值和旧值相同的两种方案(手写深拷贝和JSON.parse())

watch事件监听三种用法 |?vue中watch如何对对象进行深度监听 |?watch监听事件的多种用法

文章来源:https://blog.csdn.net/sunyctf/article/details/135304567
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。