Vue基础入门08,详解 Vue watch 侦听器:基础用法、深度监听与立即执行场景

2025博客之星年度评选已开启 10w+人浏览 1.8k人参与

在 Vue 的响应式系统中,watch侦听器是处理数据变化的核心工具之一。它能够监听 Vue 实例(或组件)中数据的变动,并在数据发生变化时执行自定义的逻辑操作。无论是简单的数值变化监听,还是复杂的对象、数组深度监听,亦或是需要初始化时立即执行的场景,watch都能通过灵活的配置满足需求。本文将从基础用法到高级场景,全面解析watch侦听器的使用方式。

一、watch 侦听器的基础用法

watch的基础作用是监听单个数据的变化,当被监听的数据发生改变时,触发对应的处理函数。它的使用方式主要分为字符串形式(Vue2 选项式 API)、函数形式(Vue2 选项式 API)和组合式 API(Vue3) 两种场景,我们先从最基础的选项式 API 开始讲解。

1. 监听基本类型数据(Vue2 选项式 API)

对于StringNumberBoolean等基本类型数据,watch的基础用法非常直观。我们只需要在 Vue 实例的watch选项中,以数据名为键,以处理函数为值即可。

new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue',
    count: 0
  },
  watch: {
    // 监听message的变化
    message(newVal, oldVal) {
      console.log('message从', oldVal, '变为', newVal);
    },
    // 也可以写成对象形式,handler为处理函数(基础场景下和上面的写法等价)
    count: {
      handler(newVal, oldVal) {
        console.log('count从', oldVal, '变为', newVal);
      }
    }
  },
  methods: {
    changeMessage() {
      this.message = 'Hello Watch';
    },
    increment() {
      this.count++;
    }
  }
});

在上述代码中,当messagecount的值发生变化时,对应的监听函数会被触发,函数的两个参数分别是新值(newVal)旧值(oldVal)

2. 组合式 API 中的基础监听(Vue3)

在 Vue3 的<script setup>语法中,我们使用watch函数来实现监听功能,它接收三个参数:监听源处理函数配置项

<template>
  <div>
    <p>{{ message }}</p>
    <button @click="changeMessage">修改消息</button>
  </div>
</template>

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

// 定义响应式数据
const message = ref('Hello Vue3');

// 监听ref数据
watch(message, (newVal, oldVal) => {
  console.log('message从', oldVal, '变为', newVal);
});

const changeMessage = () => {
  message.value = 'Hello Watch3';
};
</script>

对于reactive定义的对象属性,还可以通过函数返回值的形式指定监听源:

import { reactive, watch } from 'vue';

const user = reactive({
  name: '张三',
  age: 18
});

// 监听user.name的变化
watch(() => user.name, (newVal, oldVal) => {
  console.log('用户名从', oldVal, '变为', newVal);
});

3. 监听多个数据

如果需要同时监听多个数据的变化,可以将监听源设置为一个数组,处理函数的参数也会变成对应的数据新值和旧值数组:

// Vue3组合式API
const count = ref(0);
const name = ref('张三');

watch([count, () => user.age], ([newCount, newAge], [oldCount, oldAge]) => {
  console.log('count或age发生变化', newCount, newAge);
});

// Vue2选项式API
watch: {
  'count'(newVal, oldVal) { /* ... */ },
  'user.age'(newVal, oldVal) { /* ... */ },
  // 也可以通过数组监听多个数据(需要借助$watch)
}

二、深度监听:处理对象 / 数组的嵌套变化

默认情况下,watch浅监听的:它只会监听数据的引用变化,而不会监听对象内部属性或数组元素的变化。例如,对于一个对象user: { name: '张三', age: 18 },如果我们直接修改user.name,默认的watch不会触发。这时就需要用到深度监听deep: true)。

1. Vue2 选项式 API 中的深度监听

new Vue({
  el: '#app',
  data: {
    user: {
      name: '张三',
      info: {
        age: 18,
        address: '北京'
      }
    },
    list: [1, 2, 3]
  },
  watch: {
    // 监听对象的深度变化
    user: {
      handler(newVal, oldVal) {
        console.log('user对象发生变化', newVal);
      },
      deep: true // 开启深度监听
    },
    // 监听数组的变化(数组的push/pop等方法会触发默认监听,但嵌套数组需要深度监听)
    list: {
      handler(newVal, oldVal) {
        console.log('list发生变化', newVal);
      },
      deep: true // 数组嵌套时需要开启
    }
  },
  methods: {
    changeUserName() {
      this.user.name = '李四'; // 开启深度监听后,此操作会触发watch
    },
    changeUserAddress() {
      this.user.info.address = '上海'; // 嵌套属性变化也会触发
    },
    pushToList() {
      this.list.push(4); // 数组普通操作默认触发,嵌套数组需要深度监听
    }
  }
});

需要注意的是,数组的原生方法(如pushpopsplice等)会改变数组的引用,因此默认的watch就能监听;但如果是数组的嵌套元素变化(如list[0].name = 'xxx'),则需要开启deep: true

2. Vue3 组合式 API 中的深度监听

<template>
  <div>
    <button @click="changeUserAge">修改年龄</button>
  </div>
</template>

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

const user = reactive({
  name: '张三',
  info: {
    age: 18
  }
});

// 监听整个user对象的深度变化
watch(user, (newVal) => {
  console.log('user发生变化', newVal);
}, { deep: true }); // 配置项中开启deep

// 也可以只监听嵌套属性(无需深度监听,更高效)
watch(() => user.info.age, (newVal) => {
  console.log('年龄变化', newVal);
});

const changeUserAge = () => {
  user.info.age = 20;
};
</script>

性能优化建议:深度监听会遍历对象的所有嵌套属性,当对象结构复杂时,可能会有性能损耗。因此,如果我们只需要监听对象的某个嵌套属性,直接通过() => user.info.age的形式监听该属性,比监听整个对象并开启深度监听更高效。

三、立即执行:初始化时触发监听函数

默认情况下,watch的处理函数只会在数据发生变化时触发,初始化时不会执行。但在某些场景下,我们需要在页面加载时就执行一次监听函数(例如,根据初始数据请求接口、初始化状态等),这时就需要用到immediate: true配置。

1. 基本使用场景

// Vue2选项式API
new Vue({
  el: '#app',
  data: {
    userId: 1
  },
  watch: {
    userId: {
      handler(newVal) {
        // 根据userId请求用户数据
        this.fetchUserInfo(newVal);
      },
      immediate: true // 初始化时立即执行
    }
  },
  methods: {
    async fetchUserInfo(id) {
      const res = await fetch(`/api/user/${id}`);
      const data = await res.json();
      console.log('用户信息', data);
    }
  }
});

在上述代码中,userId的监听函数会在 Vue 实例初始化时立即执行一次,之后当userId变化时,也会再次执行。这完美解决了 “初始数据加载” 的需求。

2. Vue3 组合式 API 中的立即执行

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

const userId = ref(1);

watch(userId, async (newVal) => {
  const res = await fetch(`/api/user/${newVal}`);
  const data = await res.json();
  console.log('用户信息', data);
}, { immediate: true }); // 配置项中开启immediate

// 手动修改userId
const changeUserId = () => {
  userId.value = 2;
};
</script>

3. 立即执行 + 深度监听的组合使用

在实际开发中,我们经常需要同时开启immediatedeep,例如监听一个复杂的查询参数对象,初始化时执行查询,参数变化时重新查询:

// Vue3组合式API
const queryParams = reactive({
  keyword: '',
  page: 1,
  size: 10
});

watch(queryParams, async (newVal) => {
  // 根据查询参数请求数据
  const res = await fetch(`/api/list?${new URLSearchParams(newVal)}`);
  const data = await res.json();
  console.log('列表数据', data);
}, { 
  immediate: true, // 初始化执行
  deep: true // 监听参数对象的嵌套变化
});

// 修改查询参数
const changeKeyword = () => {
  queryParams.keyword = 'vue';
};

四、总结与注意事项

  1. 基础用法watch用于监听数据变化,接收新值和旧值参数,Vue2 中通过选项式 API 配置,Vue3 中通过watch函数实现,支持监听单个或多个数据。
  2. 深度监听:通过deep: true开启,用于监听对象内部属性、数组嵌套元素的变化,注意避免对复杂对象滥用深度监听,优先监听具体属性以提升性能。
  3. 立即执行:通过immediate: true开启,用于初始化时执行监听函数,常见于数据初始化、接口请求等场景。
  4. 注意事项
    • Vue3 中,watch监听reactive对象时,旧值参数会和新值相同(因为引用未变),如果需要获取旧值,可监听对象的属性而非整个对象。
    • 不再需要的watch(如组件销毁时),Vue3 的watch函数会返回一个停止监听的函数,可手动调用以释放资源。
    • 对于简单的逻辑,可优先使用computed计算属性,watch更适合处理异步操作或复杂的副作用逻辑。

watch侦听器作为 Vue 响应式系统的重要组成部分,掌握其基础用法和高级配置,能让我们更优雅地处理数据变化带来的业务逻辑,提升代码的可维护性和性能。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

canjun_wen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值