Vue 3 监听属性 (Watchers)

在 Vue 3 中,侦听器(Watchers) 用于观察一个或多个响应式数据的变化,并在数据变化时执行一些异步或开销较大的操作。它是 Vue 提供的一种机制,可以让你在数据变化时做出反应,通常用于处理副作用或执行异步操作。

与计算属性(computed)不同,计算属性 是依赖于响应式数据的计算值,只有在依赖的数据发生变化时才会重新计算。而 侦听器 允许你在数据变化时触发更复杂的逻辑,通常用于执行副作用操作,如发送 HTTP 请求、处理表单数据或操作外部库等。

1. 使用 watch 监听数据

你可以使用 watch API 来监听响应式数据的变化。Vue 3 中的 watch 可以用于监听单个数据源,也可以监听多个数据源。

1.1. 监听单个属性

<template>
  <div>
    <p>Price: {{ price }}</p>
    <button @click="price += 10">Increase Price</button>
  </div>
</template>

<script>
import { ref, watch } from 'vue';

export default {
  setup() {
    const price = ref(100);

    // 监听 price 变化
    watch(price, (newValue, oldValue) => {
      console.log(`Price changed from ${oldValue} to ${newValue}`);
    });

    return {
      price
    };
  }
};
</script>

在这个例子中,我们使用 watch 监听 price 变量的变化。每当 price 发生变化时,都会触发回调函数,并打印出新的和旧的 price 值。

1.2. 监听多个属性

你也可以监听多个数据源(响应式属性)。你只需要将它们放在一个数组中:

<template>
  <div>
    <p>Price: {{ price }}</p>
    <p>Quantity: {{ quantity }}</p>
    <button @click="price += 10">Increase Price</button>
    <button @click="quantity += 1">Increase Quantity</button>
  </div>
</template>

<script>
import { ref, watch } from 'vue';

export default {
  setup() {
    const price = ref(100);
    const quantity = ref(1);

    // 监听 price 和 quantity
    watch([price, quantity], ([newPrice, newQuantity], [oldPrice, oldQuantity]) => {
      console.log(`Price changed from ${oldPrice} to ${newPrice}`);
      console.log(`Quantity changed from ${oldQuantity} to ${newQuantity}`);
    });

    return {
      price,
      quantity
    };
  }
};
</script>

在这个例子中,当 pricequantity 发生变化时,侦听器会同时触发,输出变化的内容。

2. watch 的参数

  • 第一个参数:需要监听的响应式数据,可以是单个数据源,也可以是一个数组,表示多个数据源。
  • 第二个参数:当监听的响应式数据发生变化时,会调用的回调函数。这个回调函数有两个参数:newValueoldValue,分别代表数据变化后的值和变化前的值。
  • 第三个参数(可选):一个对象,允许你配置侦听器的行为。

3. watch 的配置项

你可以在 watch 中传递配置项来控制侦听器的行为。常见的配置项包括:

3.1. immediate

immediate 选项会使侦听器在创建时立即执行一次回调,而不是等待数据变化之后再执行。

<template>
  <div>
    <p>Price: {{ price }}</p>
    <button @click="price += 10">Increase Price</button>
  </div>
</template>

<script>
import { ref, watch } from 'vue';

export default {
  setup() {
    const price = ref(100);

    // 在数据变化前,立即执行一次
    watch(price, (newValue, oldValue) => {
      console.log(`Price changed from ${oldValue} to ${newValue}`);
    }, {
      immediate: true
    });

    return {
      price
    };
  }
};
</script>

immediate: true 表示当组件初始化时,侦听器会立即触发一次回调。

3.2. deep

deep 选项可以让侦听器递归地监听对象或数组内部的嵌套属性。如果数据是一个对象或数组,且你希望监听其内部属性的变化,可以使用 deep

<template>
  <div>
    <p>{{ user }}</p>
    <button @click="user.name = 'John'">Change Name</button>
  </div>
</template>

<script>
import { ref, watch } from 'vue';

export default {
  setup() {
    const user = ref({
      name: 'Alice',
      age: 30
    });

    // 监听 user 对象的深层变化
    watch(user, (newValue, oldValue) => {
      console.log('User changed:', newValue);
    }, {
      deep: true
    });

    return {
      user
    };
  }
};
</script>

在这个例子中,deep: true 表示监听 user 对象的内部属性(如 nameage)的变化,而不仅仅是监听 user 本身的变化。

3.3. flush

flush 选项控制回调函数的调用时机。它可以接受以下值:

  • 'sync'(默认值):在数据变化后,立即同步执行回调。
  • 'post':在下次 DOM 更新周期后执行回调。
  • 'pre':在 DOM 更新之前执行回调。
<template>
  <div>
    <p>{{ price }}</p>
    <button @click="price += 10">Increase Price</button>
  </div>
</template>

<script>
import { ref, watch } from 'vue';

export default {
  setup() {
    const price = ref(100);

    // 在 DOM 更新后执行
    watch(price, (newValue, oldValue) => {
      console.log(`Price changed from ${oldValue} to ${newValue}`);
    }, {
      flush: 'post'
    });

    return {
      price
    };
  }
};
</script>

在此示例中,flush: 'post' 使得回调在 DOM 更新完成后才执行。

4. 使用 watchEffect

除了 watch,Vue 3 还提供了一个更简洁的 watchEffect API,适用于在副作用函数中直接响应依赖。

<template>
  <div>
    <p>Price: {{ price }}</p>
    <button @click="price += 10">Increase Price</button>
  </div>
</template>

<script>
import { ref, watchEffect } from 'vue';

export default {
  setup() {
    const price = ref(100);

    // 自动追踪所有被访问的响应式数据
    watchEffect(() => {
      console.log(`Price is: ${price.value}`);
    });

    return {
      price
    };
  }
};
</script>

watchEffect 会自动追踪其内部使用的响应式数据,每次相关数据变化时都会重新执行回调函数。它更适合用于无需显式指定依赖的简单场景。

总结

  • watch 允许你监听一个或多个响应式数据的变化,并在数据变化时执行回调。
  • 你可以使用 immediate 选项立即执行回调,使用 deep 选项监听对象或数组的深层变化。
  • watchEffect 是另一种更简洁的方式,它会自动追踪函数中使用的响应式数据。
  • 侦听器 适合用于执行副作用操作,如数据变化时发送 HTTP 请求、执行异步操作等。

通过使用 watchwatchEffect,你可以更加灵活地处理响应式数据的变化,进行复杂的副作用处理。