Vue2 和 Vue3 中 watch 用法和原理详解

简介: 本文详解 Vue2 与 Vue3 中 `watch` 的用法、原理及差异。涵盖基本语法、深度监听、程序式监听、组合式 API、性能优化与常见问题,助你掌握响应式监听核心机制,提升开发效率与代码质量。(238字)

@TOC

1. Vue2 中的 watch

1. 基本用法

在 Vue2 中,watch 是一个对象,其键是要观察的表达式,值是对应的回调函数或包含选项的对象。

// 对象写法
export default {
   
  data() {
   
    return {
   
      count: 0,
      user: {
   
        name: 'John',
        age: 25
      }
    }
  },
  watch: {
   
    // 监听基本数据类型
    count(newVal, oldVal) {
   
      console.log(`count changed from ${
     oldVal} to ${
     newVal}`)
    },

    // 深度监听对象
    user: {
   
      handler(newVal, oldVal) {
   
        console.log('user changed:', newVal)
      },
      deep: true, // 深度监听
      immediate: true // 立即执行
    },

    // 监听对象特定属性
    'user.name': function(newVal, oldVal) {
   
      console.log(`name changed from ${
     oldVal} to ${
     newVal}`)
    }
  }
}

2. 程序式监听

Vue2 也提供了 $watch API,可以在实例的任何地方监听数据变化。

export default {
   
  mounted() {
   
    // 使用 $watch API
    const unwatch = this.$watch(
      'count',
      (newVal, oldVal) => {
   
        console.log(`count changed: ${
     oldVal} -> ${
     newVal}`)
      },
      {
   
        immediate: true,
        deep: false
      }
    )

    // 取消监听
    // unwatch()
  }
}

2. Vue3 中的 watch

1. 组合式 API 用法

Vue3 的 watch 更加灵活,支持监听 ref、reactive 对象、getter 函数等多种数据源。

import {
    ref, reactive, watch, watchEffect } from 'vue'

export default {
   
  setup() {
   
    const count = ref(0)
    const user = reactive({
   
      name: 'John',
      age: 25
    })

    // 监听 ref
    watch(count, (newVal, oldVal) => {
   
      console.log(`count changed from ${
     oldVal} to ${
     newVal}`)
    })

    // 监听 reactive 对象
    watch(
      () => user.name, // getter 函数
      (newVal, oldVal) => {
   
        console.log(`name changed from ${
     oldVal} to ${
     newVal}`)
      }
    )

    // 深度监听对象
    watch(
      () => user,
      (newVal, oldVal) => {
   
        console.log('user changed:', newVal)
      },
      {
    deep: true }
    )

    // 监听多个源
    watch(
      [() => count.value, () => user.name],
      ([newCount, newName], [oldCount, oldName]) => {
   
        console.log(`count: ${
     oldCount}->${
     newCount}, name: ${
     oldName}->${
     newName}`)
      }
    )

    // watchEffect - 自动追踪依赖
    watchEffect(() => {
   
      console.log(`count is ${
     count.value}, name is ${
     user.name}`)
    })

    return {
   
      count,
      user
    }
  }
}

2. 选项式 API 用法

Vue3 也支持在选项式 API 中使用 watch,与 Vue2 的用法类似。

import {
    watch } from 'vue'

export default {
   
  data() {
   
    return {
   
      count: 0,
      user: {
   
        name: 'John',
        age: 25
      }
    }
  },
  watch: {
   
    count(newVal, oldVal) {
   
      console.log(`count changed from ${
     oldVal} to ${
     newVal}`)
    }
  },
  created() {
   
    // 使用 watch 函数
    watch(
      () => this.user.name,
      (newVal, oldVal) => {
   
        console.log(`name changed from ${
     oldVal} to ${
     newVal}`)
      }
    )
  }
}

3.核心原理分析

1. Vue2 的 Watch 原理

Vue2 的 watch 基于响应式系统的依赖收集和派发更新机制。

  • 在组件实例初始化阶段,遍历 watch 对象的每一个属性,为每一个监听表达式创建一个 watcher 实例。
  • watcher 的创建过程:解析表达式,生成 getter 函数;执行 getter 函数,触发依赖收集;保存旧值,等待数据变化。
  • 当被监听的数据发生变化时,触发 setter,通知对应的 watcher 更新;watcher 执行 getter 获取新值,比较新值和旧值,如果不同则执行回调函数。

2. Vue3 的 Watch 原理

Vue3 的 watch 基于 effect 机制实现。

  • 将回调函数包装成一个 effect,当被监听的数据发生变化时,effect 会重新执行。
  • 通过 track 函数进行依赖收集,trigger 函数触发更新。
  • 使用调度器 scheduler 控制 effect 的执行时机,实现异步更新和 flush 选项。

4. 主要差异对比

1. 差异总结

  • Vue2 的 watch 语法较为简单直观,适合选项式 API;Vue3 的 watch 更加灵活,适合组合式 API。
  • Vue3 的 watch 基于 effect 机制实现,提供了更好的性能和更丰富的配置选项。
  • 两者都支持深度监听、立即执行、异步回调等特性,但在语法和使用方式上有所不同。

2. 特性对比

特性 Vue2 Vue3
API 形式 选项式 组合式 + 选项式
监听 reactive 不支持 原生支持
深度监听 需要显式配置 reactive 对象默认深度监听
多源监听 不支持 支持监听多个数据源
清理副作用 不支持 支持 cleanup 函数
性能 相对较低 基于 Proxy,性能更好

5. 使用建议

1. 性能优化

避免不必要的深度监听,只监听需要的属性。

// Vue3 - 避免不必要的深度监听
const largeObject = reactive({
    /* 大量数据 */ })

// 不好的做法
watch(largeObject, () => {
   
  // 任何属性变化都会触发
})

// 好的做法 - 只监听需要的属性
watch(
  () => largeObject.importantProp,
  () => {
   
    // 只有 importantProp 变化时触发
  }
)

2. 清理副作用

Vue3 支持在 watch 中清理副作用,避免内存泄漏。

// Vue3 - 清理副作用
watch(
  data,
  async (newVal, oldVal, onCleanup) => {
   
    let cancelled = false
    onCleanup(() => {
   
      cancelled = true
    })

    const result = await fetchData(newVal)
    if (!cancelled) {
   
      // 处理结果
    }
  }
)

3. 防抖处理

使用防抖函数避免频繁触发 watch 回调。

import {
    debounce } from 'lodash-es'

// Vue3 防抖监听
watch(
  searchQuery,
  debounce((newVal) => {
   
    searchAPI(newVal)
  }, 300)
)

6.常见问题解答

1. Vue2 和 Vue3 的 watch 混用?

在 Vue3 的选项式 API 中,可以继续使用 Vue2 风格的 watch 选项,但不建议混用。

2. 什么时候用 watch,什么时候用 computed?

watch 用于执行副作用(如 API 调用、DOM 操作),computed 用于派生数据。

3. watchEffect 和 watch 的区别?

watchEffect 自动追踪依赖,立即执行;watch 需要明确指定监听源,默认懒执行。

通过深入理解 Vue2 和 Vue3 中 watch 的用法和原理,可以更好地根据项目需求选择合适的监听方式,并编写出更高效、可维护的代码。

相关文章
|
3月前
|
缓存 前端开发 JavaScript
Vue3 写法示例与规范指南
Vue3项目规范指南:统一目录结构、命名规则与Composition API用法,涵盖组件通信、性能优化及ESLint+Prettier工具链配置,提升代码可维护性与团队协作效率。(239字)
442 1
|
前端开发 JavaScript 安全
【前端相关】elementui使用el-upload组件实现自定义上传
【前端相关】elementui使用el-upload组件实现自定义上传
3480 0
|
3月前
|
XML Android开发 数据格式
Android setContentView源码与原理分析
`setContentView` 是 Activity 显示界面的核心方法,其本质是将布局嵌入由 `PhoneWindow` 管理的 `DecorView` 中。系统首先创建包含状态栏、标题栏等的窗口模板(如 `screen_simple.xml`),再通过 `LayoutInflater` 将开发者指定的布局加载到 ID 为 `android.R.id.content` 的 `mContentParent` 容器内,最终在 `Activity` 恢复时由 `WindowManager` 将 `DecorView` 添加至窗口,触发测量与绘制流程,完成界面显示。
265 73
|
3月前
|
JavaScript 安全 前端开发
Vue2 和 Vue3 中 Vue Router 用法与原理详解
本文深入解析 Vue Router 在 Vue2(v3)与 Vue3(v4)中的核心用法与原理,涵盖安装配置、声明式与编程式导航、路由守卫、懒加载、动态路由及性能优化。对比版本差异,揭示其基于响应式系统实现的路由匹配与视图更新机制,助力开发者构建高效、可维护的单页应用。
350 2
|
3月前
|
JavaScript 前端开发 安全
TypeScript 与 ArkTS 全面对比:鸿蒙生态下的语言演进
本文深入对比TypeScript与华为鸿蒙原生语言ArkTS,从类型系统、UI开发、性能优化到生态定位,全面解析二者差异。ArkTS基于TS演进,面向操作系统层级重构,具备强类型安全、声明式UI、AOT编译与分布式能力,助力“一次开发,多端部署”。结合10亿鸿蒙设备爆发趋势,为开发者提供技术选型指南与平滑迁移路径,是进军全场景智慧生态的关键钥匙。(238字)
377 1
|
3月前
|
存储 JavaScript 前端开发
Vue 事件总线(EventBus)详解
事件总线是一种基于发布-订阅模式的轻量级通信机制,用于解决Vue中非父子组件间的通信问题。通过创建全局事件中心,实现跨组件解耦,适用于登录通知、购物车更新等场景,但需注意内存泄漏与调试难题,建议配合命名空间与自动清理机制使用。
361 5
|
4月前
|
JavaScript 前端开发 安全
Vue 3 + TypeScript 现代前端开发最佳实践(2025版指南)
每日激励:“如果没有天赋,那就一直重复”。我是蒋星熠Jaxonic,一名执着于代码宇宙的星际旅人。用Vue 3与TypeScript构建高效、可维护的前端系统,分享Composition API、状态管理、性能优化等实战经验,助力技术进阶。
Vue 3 + TypeScript 现代前端开发最佳实践(2025版指南)
|
3月前
|
自然语言处理 JavaScript 前端开发
vue 插槽详解
本文系统讲解 Vue.js 插槽机制,涵盖默认插槽、具名插槽、作用域插槽及动态插槽等高级用法,结合代码示例与实际应用场景(如布局组件、表格、模态框),帮助开发者掌握组件内容分发的核心技术,提升组件复用性与灵活性。
332 8
|
6月前
|
前端开发
Promise.all()方法的作用是什么?
Promise.all()方法的作用是什么?
509 121
|
存储 JavaScript API
Vuex 和 Pinia 的区别
【10月更文挑战第18天】Vuex 和 Pinia 都有各自的优势和适用场景。Vuex 适合较为大型和复杂的项目,强调严格的架构和流程;而 Pinia 则更适合中小型项目以及对灵活性和简洁性有更高要求的开发者。你可以根据项目的具体需求和个人喜好来选择使用哪一个状态管理库。
1617 59