Vue.js 是一个流行的 JavaScript 框架,而其中的 侦听器(watch) 功能是其中的一项重要特性。它可以用来侦听 Vue 实例中数据的变化,并在变化发生时执行相应的操作。本篇博客将深入探讨 Vue 侦听器的相关内容,包括其优缺点、用法以及 Tips 等。

🍁watch 的优缺点

🍂Watch 优点

  • 📒可以在数据发生变化时执行自定义的回调函数,从而可以用于控制流程跳转和生成数据计算逻辑等场景;
  • 📒相对于 computed 计算属性而言,watch 更加灵活,因为可以在回调函数中进行任意代码操作,而 computed 属性的计算则更为“规范化”,主要是用于生成属性,而不需要进行过多的业务逻辑;
  • 📒Watch 功能与 Vue 中的计算属性、监听属性、组件生命周期等之间构成了合理的拓扑结构,可以应对复杂的应用场景,做到周到全面的数据侦听。

🍂Watch 缺点

  • 📒Watch 需要使用一个回调函数作为参数。如果回调函数中的代码太多,会导致代码混乱,可维护性降低;
  • 📒Watch 回调函数中的代码执行会相对于 computed 计算属性更为频繁,因为 computed 在依赖于它的属性发生变化前不会重新计算,而 watch 在数据发生变化时就会执行回调函数。如果 watch 回调函数中的代码执行太耗时,可能会导致页面卡顿等问题。
    因此,在使用 Watch 功能时,需要对性能和可维护性进行平衡和考虑。

🍁watch 的用法

在 Vue 中使用 watch 可以分为两种方式:对象式 watch 和 函数式 watch。

🍂对象式 watch

对象式 watch 的基本形式为:

//Vue实例中的data
data(){
    return {   
        user:{
            name:'',
            age:''
        }
    }
}

// 在 Vue实例中使用 watch

watch:{
    'user.name'(newVal,oldVal){
        console.log(newVal,oldVal)
    }
}

上述代码中,watch 中的属性值为字符串,用来表示需要侦听的属性。属性值可以是一个带点的路径,以便进行深度侦听。用户只需要在watch中加入一个字符串即可。

对于对象式 Watch,Vue 提供了如下选项:

  • 📒handler:回调函数。

  • 📒immediate:即使在 data 上没有初始值时,Watch 也会立即执行回调。它可以是 true 或 false。

  • 📒deep:如果对象中的所有属性的值发生变化,则 Watch 会触发回调函数。它可以是 true 或 false。

🍂函数式 watch

函数式 watch 的基本形式为:

//Vue实例中的data

data() {
    return {   
        watches: {
            'user.name': {
                handler: 'userNameChangeHandler',
                immediate: true
            },
            'user.age': {
                handler(val, oldVal) {
                    console.log(`年龄变化了,新值: ${val},旧值: ${oldVal}`)
                }
            }
        },
    }
},

// 在 Vue实例中使用 watch

methods: {
    userNameChangeHandler(newVal, oldVal) {
        console.log(`用户名变化了,新值: ${newVal},旧值: ${oldVal}`)
    }
},
watch: {
    watches: {
        deep: true,  //深度监视
        handler: function (val, oldVal) {
            for (let key in val) {
                let watchOption = val[key];
                this.$watch(key, watchOption.handler, { deep: watchOption.deep || false, immediate: watchOption.immediate || false })
            }
        }
    }
}

上述代码中,使用了函数式 Watch 的方式。这种方式的好处是可以在组件中集中管理和处理多个侦听器,提高代码的可维护性和可读性。在上述代码中,我们将需要侦听的属性和对应的回调函数放在一个名为 “watches” 的对象中,使用 $watch 方法进行遍历并侦听属性的变化,从而执行相应的回调函数。

在函数式 Watch 中,我们可以为每个属性定义一个独立的回调函数,也可以直接在 handler 中编写回调逻辑,它提供了更大的灵活性和复用性。

需要注意的是,在函数式 Watch 中,我们使用了一个特殊的 watch 对象来进行侦听操作,并在 watch 对象里的属性中定义了需要侦听的属性和对应的回调函数。然后在组件的 watch 选项中使用 $watch 方法进行遍历监听。

通过对象式 Watch 和函数式 Watch,我们可以根据具体的需求选择合适的方式来使用侦听器。对象式 Watch 适用于简单的侦听需求,而函数式 Watch 则适用于复杂的场景,能够更好的组织和管理侦听器。

🍁代码示例

🍂监听基本数据类型

以下是一个简单的 Vue 组件示例,展示了如何使用对象式 Watch 和函数式 Watch 来监控数据的变化并执行相应的回调函数:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>vue 侦听器</title>
    </head>
    <body>

        <div id="app">
            <template>
                <div>
                  <p>{{ text }}</p>
                  <button @click="changeText">Change Text</button>
                  <p>{{ count }}</p>
                  <button @click="incrementCount">Increment Count</button>
                </div>
              </template>
        </div>

        <script src="./vue.js"></script>
        <script>
            new Vue({
                el: '#app',
                data() {
	                    return {
	                    text: 'Hello World',
	                    count: 0
                    };
                },
                watch: {
                    text(newText, oldText) {
                    	console.log('Text has changed:', oldText, '=>', newText);
                    },
                    count(newCount, oldCount) {
                    	console.log('Count has changed:', oldCount, '=>', newCount);
                    }
                },
                methods: {
                    changeText() {
                    	this.text = 'New Text';
                    },
                    incrementCount() {
	                   	this.count++;
                    }
                }
            });
        </script>
    </body>
</html>

上述代码中的 Vue 组件,包含了一个文字显示和一个按钮。点击按钮可以改变文字的内容。

在 watch 对象中,我们定义了两个对象式 Watch。一个是对 text 属性进行侦听,另一个是对 count 属性进行侦听。当这两个属性发生变化时,对应的回调函数会被执行。

在 created 钩子函数中,我们使用函数式 Watch 来监控 count 属性的变化。通过 this.$watch 方法,我们将 this.count 包裹在一个函数中作为侦听的目标属性,然后定义了一个函数作为回调函数。当 count 发生变化时,回调函数将会被触发执行。

在组件的 changeText 方法中,我们通过修改 text 的值来模拟 text 属性的变化。同时,也会触发相应的 Watch 回调函数。

通过这个示例,你可以了解到如何使用对象式 Watch 和函数式 Watch 来监控属性的变化,并在发生变化时执行相应的操作。

🍂监听复杂数据类型(Object,array)

在 Vue 中,监听数组对象的变化可能是比较复杂的,因为不仅需要监听数组的变化,还要监听数组中每个对象的变化。

为了解决这个问题,Vue 提供了两种解决方法:使用 $watch 监听数组对象或使用 deep 选项监听数组对象。

<template>
  <div>
    <h2>Users</h2>
    <ul>
      <li v-for="user in users" :key="user.id">
        {{ user.name }}
        <button @click="deleteUser(user)">Delete</button>
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      users: [
        { id: 1, name: 'Alice' },
        { id: 2, name: 'Bob' },
        { id: 3, name: 'Charlie' }
      ]
    };
  },
  mounted() {
    this.$watch(
      'users',
      (newVal, oldVal) => {
        console.log('users has changed:');
        console.log('newVal:', newVal);
        console.log('oldVal:', oldVal);
      },
      { deep: true } // 进行深度监听
    );
  },
  methods: {
    deleteUser(user) {
      // 从数组中删除指定的用户对象
      const index = this.users.findIndex(u => u.id === user.id);
      this.users.splice(index, 1);
    }
  }
};
</script>

在上述代码中,我们定义了一个包含三个对象的 users 数组。在 mounted 钩子函数中使用 $watch 方法监听 users 数组的变化,并设置 deep: true 表示进行深度监听。

同时,我们定义了一个 deleteUser 方法,用于从数组中删除指定的用户对象。该方法会触发 users 数组的变化,从而执行 $watch 中的回调函数。

🍁综合应用 Tips

在使用侦听器时,以下是一些综合应用的 Tips,有助于更好地使用和优化侦听器:

  • 📒可以使用 immediate 选项来在组件创建时立即执行一次回调函数。

  • 📒可以使用 deep 选项来深度侦听对象或数组的变化。

  • 📒可以使用 watch 数组来同时侦听多个属性的变化,可以简化代码。

  • 📒可以使用 $watch 方法进行动态添加和移除侦听器。

  • 📒在回调函数中可以使用异步操作,比如发送网络请求、操作 DOM 等。

综上所述,侦听器(watch)是 Vue.js 中一个非常有用的特性,可以在数据发生变化时执行相应的回调函数。通过对象式 Watch 和函数式 Watch 的方式,我们可以根据不同的需求选择合适的方式来使用侦听器,并通过一些 Tips 来提高代码的可读性和性能。


🏫博客主页:魔王-T

🥝大鹏一日同风起 扶摇直上九万里

❤️感谢大家点赞👍收藏⭐评论✍️


Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐