Vue 中的 watch 监听

501 阅读3分钟
  • 在 Vue 中,watch 是一个非常强大的功能,用于响应式地监视 Vue 实例上的数据,并在数据变化时执行一些操作。以下是关于 watch 的详细讲解:

基本概念

  • 定义watch 是 Vue 实例的一个选项,它允许你定义一个观察者对象,用来观察 Vue 实例上的数据。当被观察的数据发生变化时,就会触发相应的处理函数。
  • 作用:主要用于在数据变化时执行异步或开销较大的操作。例如,当用户输入搜索关键词时,你可以使用 watch 来监视关键词的变化,当变化达到一定条件时(如输入停止后延迟一段时间),再发起搜索请求,而不是在每次输入时都立即请求,从而优化性能。

基本用法

  • 对象形式

    • 单个数据监视

      JavaScript复制

      new Vue({
        data() {
          return {
            firstName: 'John',
            lastName: 'Doe'
          };
        },
        watch: {
          firstName(newVal, oldVal) {
            console.log(`firstName从${oldVal}变为${newVal}`);
          }
        }
      });
      

      在这个例子中,当 firstName 的值发生变化时,会触发 firstName 对应的处理函数,newVal 是变化后的值,oldVal 是变化前的值。

    • 多个数据监视

      JavaScript复制

      new Vue({
        data() {
          return {
            firstName: 'John',
            lastName: 'Doe'
          };
        },
        watch: {
          firstName(newVal, oldVal) {
            console.log(`firstName从${oldVal}变为${newVal}`);
          },
          lastName(newVal, oldVal) {
            console.log(`lastName从${oldVal}变为${newVal}`);
          }
        }
      });
      

      可以同时监视多个数据,每个数据对应一个处理函数。

  • 函数形式

    • 监视单个数据

      JavaScript复制

      new Vue({
        data() {
          return {
            firstName: 'John'
          };
        },
        watch: {
          firstName: function(newVal, oldVal) {
            console.log(`firstName从${oldVal}变为${newVal}`);
          }
        }
      });
      

      使用函数形式也可以实现对单个数据的监视。

    • 监视多个数据

      JavaScript复制

      new Vue({
        data() {
          return {
            firstName: 'John',
            lastName: 'Doe'
          };
        },
        watch: {
          firstName: function(newVal, oldVal) {
            console.log(`firstName从${oldVal}变为${newVal}`);
          },
          lastName: function(newVal, oldVal) {
            console.log(`lastName从${oldVal}变为${newVal}`);
          }
        }
      });
      

      同样可以监视多个数据。

高级用法

  • 深度监视

    • 场景:当你需要监视一个对象内部的属性变化时,普通的 watch 是无法感知对象内部属性的变化的。例如,监视一个对象的某个属性,但该属性是一个对象,你希望当这个对象内部的属性变化时也能触发监视器。

    • 实现:通过设置 deep: true 选项来实现深度监视。

      JavaScript复制

      new Vue({
        data() {
          return {
            user: {
              name: 'John',
              age: 20
            }
          };
        },
        watch: {
          user: {
            handler(newVal, oldVal) {
              console.log('user对象内部属性发生变化');
            },
            deep: true
          }
        }
      });
      

      在这个例子中,当 user 对象内部的 nameage 属性发生变化时,都会触发监视器。

  • 立即执行

    • 场景:有时候你希望在组件初始化时,就立即执行监视器中的处理函数,而不仅仅是当数据变化时执行。

    • 实现:通过设置 immediate: true 选项来实现。

      JavaScript复制

      new Vue({
        data() {
          return {
            firstName: 'John'
          };
        },
        watch: {
          firstName: {
            handler(newVal, oldVal) {
              console.log(`firstName从${oldVal}变为${newVal}`);
            },
            immediate: true
          }
        }
      });
      

      在这个例子中,组件初始化时,firstName 的监视器处理函数就会立即执行一次,此时 newValoldVal 都是初始值 John

  • 组合使用

    • 深度监视且立即执行

      JavaScript复制

      new Vue({
        data() {
          return {
            user: {
              name: 'John',
              age: 20
            }
          };
        },
        watch: {
          user: {
            handler(newVal, oldVal) {
              console.log('user对象内部属性发生变化');
            },
            deep: true,
            immediate: true
          }
        }
      });
      

      同时设置了 deepimmediate 选项,既可以深度监视对象内部属性的变化,又可以在组件初始化时立即执行处理函数。

注意事项

  • 性能优化:虽然 watch 很强大,但过度使用可能会导致性能问题,尤其是深度监视。因为深度监视会递归地监视对象内部的所有属性,当对象很大或者属性很多时,会消耗大量性能。所以在使用深度监视时,要谨慎考虑是否真的需要深度监视,或者是否可以通过其他方式来优化。
  • 避免无限循环:在 watch 的处理函数中,要避免修改被监视的数据,否则可能会导致无限循环。例如,在监视 firstName 的处理函数中又去修改 firstName 的值,就会不断触发监视器,形成无限循环。
  • 解绑监视器:在组件销毁时,Vue 会自动解绑所有的 watch 监视器。但在一些特殊情况下,如手动创建的监视器,可能需要手动解绑,以避免内存泄漏。