Vue2 中 `watch` 监听详解与 Vue3 的对比:深入理解监听器的使用与优化

在 Vue 开发中,watch 是一个非常强大的工具,用于监听数据变化并执行相应的操作。它适用于那些需要在数据发生变化时执行异步或复杂操作的场景。本文将详细介绍 Vue2 中 watch 的使用方式、配置项以及其与 Vue3 的差异 ,同时还会对比 watchcomputed 的区别与适用场景。


🧩 一、Vue2 中 watch 的基本用法

1. 简单监听

javascript 复制代码
export default {
  data() {
    return {
      message: 'Hello Vue'
    };
  },
  watch: {
    message(newVal, oldVal) {
      console.log('message changed:', newVal, oldVal);
    }
  }
};

message 值发生变化时,回调函数会被触发,输出新旧值。


2. 使用对象形式(添加配置项)

Vue2 支持以对象形式定义 watch,从而可以使用更多高级功能:

javascript 复制代码
watch: {
  message: {
    handler(newVal, oldVal) {
      console.log('message changed:', newVal, oldVal);
    },
    immediate: true,   // 页面初始化时也触发一次
    deep: false        // 是否深度监听
  }
}
  • handler: 回调函数,接收新值和旧值。
  • immediate: 若为 true,页面加载时立即执行一次回调。
  • deep: 若为 true,会深度监听对象内部属性的变化(适用于对象或数组)。

3. 监听对象中的某个属性(字符串路径)

javascript 复制代码
data() {
  return {
    user: {
      name: 'Tom',
      age: 20
    }
  };
},
watch: {
  'user.name': {
    handler(newVal, oldVal) {
      console.log('user.name changed:', newVal);
    },
    immediate: true
  }
}

这种方式适合监听嵌套对象的某个具体属性。


4. 深度监听对象

如果你希望监听整个对象的变化(包括对象内部任意属性),可以设置 deep: true

javascript 复制代码
watch: {
  user: {
    handler(newVal) {
      console.log('user object changed', newVal);
    },
    deep: true
  }
}

⚠️ 注意:深度监听可能会带来性能开销,特别是对象较大或频繁更新时。


🔄 二、Vue3 中 watch 的写法与对比

Vue3 中的响应式系统进行了重构(基于 Proxy),因此 watch 的语法也有一定变化。主要体现在:

  • 在 Vue3 中,watch 不再是选项式 API 中的一个单独配置项,而是通过 Composition API 来使用。
  • 更加灵活,支持监听多个源、组合逻辑等。

1. Vue3 Composition API 中的 watch

基本用法:

javascript 复制代码
import { ref, watch } from 'vue';

export default {
  setup() {
    const count = ref(0);

    watch(count, (newVal, oldVal) => {
      console.log('count changed:', newVal, oldVal);
    });

    return { count };
  }
};

监听响应式对象的某个属性:

javascript 复制代码
const user = reactive({ name: 'Tom' });

watch(
  () => user.name,
  (newVal) => {
    console.log('user.name changed:', newVal);
  }
);

同时监听多个值:

javascript 复制代码
watch([() => firstName.value, () => lastName.value], ([newFirst, newLast]) => {
  console.log('Name changed:', newFirst, newLast);
});

设置 immediatedeep

javascript 复制代码
watch(
  () => user,
  (newVal) => {
    console.log('user changed:', newVal);
  },
  { deep: true, immediate: true }
);

✅ Vue2 与 Vue3 watch 对比总结

特性 Vue2 Vue3
写法 选项式 API Composition API
监听对象属性 字符串路径 'obj.key' 使用 () => obj.key
多值监听 不支持原生,需封装 原生支持数组形式
配置项 immediatedeep 同样支持,作为第三个参数传入
性能 可控但略显笨重 更加灵活、模块化

🔁 三、watchcomputed 的区别与使用建议

1. computed ------ 依赖缓存,返回值

  • 用途:用于根据已有响应式数据计算出新的值。
  • 特点
    • 基于它的响应式依赖进行缓存。
    • 如果依赖的数据没有变化,多次访问会直接返回缓存结果。
  • 示例
javascript 复制代码
computed: {
  fullName() {
    return this.firstName + ' ' + this.lastName;
  }
}

2. watch ------ 异步/副作用处理

  • 用途:执行异步操作或复杂的副作用逻辑(如请求接口、修改 DOM 等)。
  • 特点
    • 没有返回值。
    • 适合处理状态变化后的一系列行为。
  • 示例
javascript 复制代码
watch: {
  searchQuery(newVal) {
    if (newVal) {
      this.fetchResults();
    }
  }
}

✅ 对比总结

特性 computed watch
是否有返回值
是否缓存
是否异步友好 否(不推荐)
是否适合副作用
是否自动追踪依赖
典型用途 数据转换、格式化 异步请求、事件触发、状态同步

📌 四、最佳实践与注意事项

✅ 推荐使用原则:

  • 如果你需要从已有数据派生出新数据,并且这个新数据会被模板使用,优先使用 computed
  • 如果你希望在数据变化时执行一些副作用(比如网络请求、定时器、DOM 操作等),请使用 watch
  • 在 Vue3 中,推荐使用 Composition API 提供的 watchcomputed,结构更清晰、逻辑可复用性强。

❗ 常见问题与解决办法:

1. watch 中无法获取最新值?

  • 确保你监听的是响应式数据(ref / reactive)。
  • 对象类型记得使用 deep: true 或者监听特定属性。

2. watch 初始化时不触发?

  • 添加 immediate: true 即可。

3. watch 执行频率过高?

  • 使用 debounce 节流处理,尤其是在监听输入框内容变化时。

🧠 五、进阶技巧

1. 使用 nextTick() 延迟执行

javascript 复制代码
this.$nextTick(() => {
  this.fetchData();
});

watch 中执行 DOM 操作前,确保 DOM 已更新。

2. 封装可复用的 Watcher 函数

在 Vue3 中可以将 watch 封装成自定义 Hook,提高代码复用性:

javascript 复制代码
function useWatchSearch(fetchResults) {
  const searchQuery = ref('');

  watch(searchQuery, (newVal) => {
    if (newVal) fetchResults();
  });

  return { searchQuery };
}

📚 六、结语

无论是 Vue2 还是 Vue3,watch 都是一个不可或缺的响应式工具。它让我们能够优雅地处理数据变化带来的副作用。而 computed 则更适合用于数据的衍生计算。

掌握它们之间的区别与适用场景,可以帮助我们写出更高效、更易维护的 Vue 应用。


📖 参考文档


如果你喜欢这篇文章,欢迎关注我的博客,后续将持续分享 Vue、React、前端工程化等干货内容!

相关推荐
崎岖Qiu13 分钟前
【JVM篇11】:分代回收与GC回收范围的分类详解
java·jvm·后端·面试
再学一点就睡3 小时前
手写 Promise 静态方法:从原理到实现
前端·javascript·面试
再学一点就睡3 小时前
前端必会:Promise 全解析,从原理到实战
前端·javascript·面试
前端工作日常4 小时前
我理解的eslint配置
前端·eslint
前端工作日常4 小时前
项目价值判断的核心标准
前端·程序员
90后的晨仔5 小时前
理解 Vue 的列表渲染:从传统 DOM 到响应式世界的演进
前端·vue.js
OEC小胖胖5 小时前
性能优化(一):时间分片(Time Slicing):让你的应用在高负载下“永不卡顿”的秘密
前端·javascript·性能优化·web
烛阴5 小时前
ABS - Rhomb
前端·webgl
植物系青年5 小时前
10+核心功能点!低代码平台实现不完全指南 🧭(下)
前端·低代码
植物系青年5 小时前
10+核心功能点!低代码平台实现不完全指南 🧭(上)
前端·低代码