Vue3源码解析watch函数实例

Vue3源码解析watch函数实例

在Vue3.x中,watch函数作为一个重要的API存在,它能够对一个值进行监测,当这个值发生变化时,就可以执行相关的回调函数。本文将分享一个完整的攻略,来解析Vue3源码中watch函数的实现。

1. watch函数的基本用法

在Vue3.x中,watch函数的基本用法如下:

// 监听一个值
watch(
  // 被监听的值的getter函数,以响应式的方式进行监听
  () => count,

  // 当值发生变化时,执行的回调函数
  (newVal, oldVal) => {
    console.log(`count由${oldVal}变为${newVal}`)
  }
)

基本上,watch函数就是把我们之前在Vue2.x中使用的$watch API包装一下,让其更加灵活,并且可以自由组合使用。

2. watch API的实现

先来看看Vue3源码中是如何实现watch API的。

packages/reactivity/src目录下,有一个叫做baseHandlers.ts的文件,其中定义了一个createGetterInvoker函数,它的作用是返回一个getter函数,这个getter函数可以直接触发依赖收集。这里我们只关注它是如何实现的:

export function createGetterInvoker(fn) {
  const invoker = (...args) => {
    return fn(...args)
  }
  ;(invoker as any).__inject__ = true // 用于标记当前函数是一个getter函数
  return invoker
}

通过以上代码可以看到,createGetterInvoker函数的作用是返回一个函数,这个函数会被标记为一个getter函数,以便在后续的代码中识别。

watch函数中我们传入了两个参数:第一个参数是要监听的对象,第二个参数是回调函数,具体实现如下:

export function watch(getter: () => any, cb: Function, options?: WatchOptions) {
  const fn = () => {
    cb(getter(), value)
  }

  const { lazy, deep, flush, onTrack, onTrigger } = options || {}
  const onInvalidate = () => {
    runner.effect.stop()
  }
  const runner = effect(
    fn,
    lazy
      ? { lazy: true, scheduler: () => {
          if (!runner.isActive) {
            runner.activate()
            fn()
          }
        } }
      : {
          scheduler: () => {
            if (!runner.isFlushPending) {
              runner.isFlushPending = true
              nextTick(runner.flush)
            }
          }
        }
  )

  if (deep) {
    traverse(getter())
  }

  let value = undefined
  if (!lazy) {
    value = getter()
    // 触发一次回调,以便获取初始的状态
    cb(value, undefined)
  }

  // 保存effect对象,以便在用户手动解绑时使用
  const effect = runner.effect
  effect.onInvalidate = onInvalidate

  ...
}

在上面的代码中,实际上是通过effect函数来进行依赖收集的。effect函数会返回一个对象,称之为effect对象,它有很多属性和方法,其中最重要的两个属性是depsdepsCount,它们用于记录这个effect对象所依赖的响应式对象以及其数量。

watch函数中,我们通过effect()函数创建了一个effect对象,然后在后续的代码中,将我们传入的回调函数作为这个effect对象fn属性来执行。

同时,我们还把getter()函数传入了traverse函数中,表示要执行一次“深遍历”操作,以便把响应式对象中的所有属性都进行依赖收集。

需要注意的是,我们在代码的开头处用到了patchFlagshapeFlag这两个变量,它们其实是跟Vue3中的虚拟DOM相关的,这里我们不用管它们是如何实现的,只需要知道它们的存在即可。

3. watch函数的用例分析

我们可以通过下面的示例来进一步了解watch函数的用例和实现细节。

// 一个简单的对象
const obj = reactive({ count: 0 })

// 操作对象的count属性
const operateObj = (num) => {
  obj.count += num
}

// 监听对象的count属性
watch(
  () => obj.count,
  (newVal, oldVal) => {
    console.log(`count由${oldVal}变为${newVal}`)
  }
)

// 改变对象的count属性
operateObj(1)
operateObj(2)

在上述代码中,我们通过reactive将一个普通的对象变成了响应式对象,然后对其count属性进行了监听。

然后我们又通过operateObj函数对count属性进行了两次修改。由于我们已经对count属性进行了监听,所以就会执行相关的回调函数,控制台会输出下面的内容:

count由0变为1
count由1变为3

这说明了watch函数的实现逻辑是正确的,并且能够很好地实现对响应式对象的监测。

总结

我们通过分析Vue3源码来了解了watch函数的实现逻辑,以及它在实际应用中的使用方法。在Vue3.x中,watch函数的重要性不言而喻,我们可以通过它来监听一个值,然后在值发生变化时执行相关的业务逻辑,从而提高Vue应用的响应性和可维护性。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Vue3源码解析watch函数实例 - Python技术站

(0)
上一篇 2023年5月27日
下一篇 2023年5月27日

相关文章

  • vue中遇到的坑之变化检测问题(数组相关)

    1. 问题背景 在Vue中,当数组相关数据更新时,会对应的更新DOM元素,但是在更新数组时,我们需要注意到一些坑点。 2. 变化检测方式 Vue采用的是基于 JavaScript 对象的变化检测机制,在更新一个对象时,Vue 会遍历它的每一个属性,并且使用 Object.defineProperty 把这个属性转为 getter 和 setter。 3. 数…

    Vue 2023年5月27日
    00
  • Vue.js render方法使用详解

    下面是”Vue.js render方法使用详解”的完整攻略: 一、render方法是什么 render方法是Vue.js中非常重要的一个方法,在Vue.js内部也是经常被使用的。它是用来创建Vue.js中的虚拟DOM树,并最终根据这棵虚拟DOM树生成真正的DOM树。使用render方法可以获得更加精细的DOM操作控制权,从而实现更高级的交互和性能优化。 使用…

    Vue 2023年5月27日
    00
  • 详解vue 组件之间使用eventbus传值

    下面是详解vue组件之间使用eventbus传值的完整攻略: 什么是event bus event bus 是Vue.js内置的一个在组件之间通信的机制,它可以让组件之间的通信变得更加简单方便。event bus是一个可以充当中央事件处理器的实例,可以用它来触发事件、监听事件或广播事件。 在组件中使用event bus 在Vue中使用event bus的步骤…

    Vue 2023年5月29日
    00
  • vue.js异步上传文件前后端实现代码

    下面我会详细地讲解“Vue.js异步上传文件前后端实现代码”的完整攻略。 准备工作 在正式开始编写代码之前,我们需要进行一些准备工作: 确认后端服务器是否支持文件上传,并且上传的文件大小是否有限制。 安装Vue.js插件vue-file-upload,它提供了非常方便的上传文件功能。 前端实现 添加上传组件 首先,我们需要在页面中添加上传组件。可以使用vue…

    Vue 2023年5月28日
    00
  • vue + Electron 制作桌面应用的示例代码

    下面是关于“vue + Electron 制作桌面应用的示例代码”的完整攻略,主要分为以下几个步骤: 1. 创建项目 首先,确保已安装最新版本的 nodejs 和 npm。然后,在命令行工具中输入以下命令创建一个基础的 Vue.js 项目。 vue create my-desktop-app 接下来,进入项目目录并安装 Electron 和 electron…

    Vue 2023年5月27日
    00
  • Vue Promise的axios请求封装详解

    标题:Vue Promise的Axios请求封装详解 简介:Vue.js 是一款轻量级、渐进式的 JavaScript 框架,提供了数据驱动和组件化的思想,可用于构建任何复杂的单页面应用。而 Axios 是一个基于 Promise 的 HTTP 客户端,用于浏览器和 Node.js。在 Vue.js 开发中,我们常常需要用到 Axios 去请求后台数据。为了…

    Vue 2023年5月28日
    00
  • ant-design-vue 快速避坑指南(推荐)

    Ant Design Vue 快速避坑指南 Ant Design Vue 是一款基于 Vue.js 的 UI 组件库,它提供了许多丰富的组件,如按钮、表单、弹窗等等。使用 Ant Design Vue 可以大大缩短前端开发时间,但是使用过程中也会遇到一些坑点,本文将介绍 Ant Design Vue 的使用指南及避坑秘籍。 安装 要使用 Ant Design…

    Vue 2023年5月28日
    00
  • Vue3响应式对象是如何实现的(1)

    当我们使用Vue3来开发应用程序时,我们可能会频繁地使用响应式对象。那么,Vue3响应式对象是如何实现的呢? 在Vue3中,响应式对象是通过使用Proxy对象来实现的。Proxy是ES6的一个新特性,可以用来拦截JavaScript对象的操作。通过使用Proxy对象,我们可以实现Vue3的响应式对象功能。 下面,让我们通过两个示例来详细讲解Vue3响应式对象…

    Vue 2023年5月27日
    00
合作推广
合作推广
分享本页
返回顶部