返回顶部
首页 > 资讯 > 前端开发 > JavaScript >Vue3侦听器的实现原理详情
  • 916
分享到

Vue3侦听器的实现原理详情

2024-04-02 19:04:59 916人浏览 八月长安
摘要

目录侦听响应式对象侦听属性值侦听获取新值和旧值实现效果前言: 本篇内容基于vue3计算属性是如何实现的实现。 侦听响应式对象 前面我们聊到计算属性,它可以自动计算并缓存响应式数据的值

前言:

本篇内容基于vue3计算属性是如何实现的实现。

侦听响应式对象

前面我们聊到计算属性,它可以自动计算并缓存响应式数据的值。而如果我们仅需要在响应式数据变化时,执行一些预设的操作,就可以使用watch侦听器。我们还是先来实现一个最简单的例子,然后来一点一点扩充它。

const data = {foo: 1}
const obj = Reactive(data)
watch(obj, () => {
  console.log('obj已改变')
})

在这个例子中,我们使用了watch侦听器,当obj的属性被改变时,控制台应该会打印出obj已改变。基于前面我们对计算属性的实现,这里我们已经有了一个大概的思路。把watch视为响应式对象的副作用函数,当响应式对象改变时,触发执行该副作用函数。

想要触发副作用函数,必须先收集它,还记得副作用函数是如何收集的吗?对,当响应式数据被get时,收集副作用函数。所以首先,我们需要让watch被响应式对象收集到。     

function watch(getter, cb) {
  effect(
    () => getter.foo
  )
}

接着,我们还需要让我们预设的方法被执行。当响应式数据被set时,触发副作用函数。这里我们想触发的是cb这个传入的回调函数,这里我们就又能用到实现计算属性时的调度器了,当调度器存在时,set触发的trigger会先执行调度器中的函数。

function watch(getter, cb) {
  effect(
    () => getter.foo,
    {
      scheduler() {
        cb()
      }
    }
  )
}

一个简单的侦听器已经完成了!这里我们为了简单,把功能写死了,仅支持对obj.foo的侦听。接下来,我们就要想想,如何实现对响应式对象的任意属性进行侦听?

按照前面的思路,想要实现对响应式对象的任意属性的侦听,就需要我们get到该对象的每一个属性,这就需要我们对响应式对象进行一次递归遍历。

function traverse(value, seen = new Set()) { // (1)
  if(typeof value !== 'object' || value === null || seen.has(value)) return
  seen.add(value)
  for(const key in value) {
    traverse(value[key], seen)
  }
  return value
}

为了避免递归遍历对象时,循环引用造成的死循环,我们在(1)处创建了Set,当重复出现相同的对象时,直接返回。

侦听属性值

Vue3中,我们不能直接侦听响应式对象的属性值。如果需要侦听响应式对象的属性值,就需要一个getter函数,让侦听器能被响应式对象收集到。

const data = {
  foo: 1
}
const obj = reactive(data)
watch(
  () => obj.foo, 
  () => {
  console.log('obj.foo已改变')
})

指定了属性就意味着,当前的侦听器仅会被指定的属性触发,就无需递归遍历整个响应式对象了。

function watch(getter, cb) {
  if(typeof getter !== 'function') getter = traverse(getter) // (2)
  effect(
    () => getter(),
    {
      scheduler() {
        cb()
      }
    }
  )
}

在(2)处,我们增加了一个判断,如果传入的已经是getter函数,我们直接使用,如果不是getter函数,则认为是一个响应式对象,就需要进行递归遍历。

侦听获取新值和旧值

在Vue中我们还需要能够在回调函数cb()中拿到响应式数据更新前后的新值与旧值。

const data = {
  foo: 1
}
const obj = reactive(data)
watch(
  () => obj.foo, 
  (newValue, oldValue) => {
  console.log(newValue, oldValue)
})

接下来的问题是,如何获取newValueoldValuenewValue好解决,执行完回调函数cb()得到的就是newValue,但这里如何获取oldValue的值呢?要从watch中拿到旧值,那就不能让副作用函数被立即执行。这里想到了什么?对,在实现计算属性的时候,我们用到过的lazy,它可以禁止副作用函数自动执行。

function watch(getter, cb) {
  if(typeof getter !== 'function') getter = traverse(getter)
  let oldValue
  const effectFn = effect(
    () => getter(),
    {
      lazy: true, // (3)
      scheduler() {
          cb(oldValue)
      }
    }
  )
  oldValue = effectFn() // (4)
}

在(3)处我们设置了lazy开关,设置了lazy后,副作用函数的执行权就交到了我们自己手上。在(4)处,我们手动执行了副作用函数。这里可以需要我们向前回顾一下,前面我们传入的getter是一个函数() => obj.foo,而effect函数的第一个参数就是真正被执行的副作用函数,所以我们手动执行的,其实就是函数() => obj.foo,这样我们就拿到了旧值。

如何获取新值呢?在响应式数据的值更新后,副作用函数effect会被触发执行,当调度器属性存在时,执行调度器。在调度器中,我们可以再次执行副作用函数,通过() => obj.foo拿到改变后的新值。

function watch(getter, cb) {
  if(typeof getter !== 'function') getter = traverse(getter)
  let oldValue, newValue
  const effectFn = effect(
    () => getter(),
    {
      lazy: true,
      scheduler() {
        newValue = effectFn()
        cb(newValue, oldValue)
        oldValue = newValue // (5)
      }
    }
  )
  oldValue = effectFn()
}

在(5)处,执行完回调函数cb(),我们进行了一下善后工作,更新了oldValue的值,为下一次回调做准备。

有时,我们还希望侦听器可以在创建时就立即执行回调函数。

const data = {
  foo: 1
}
const obj = reactive(data)
watch(
  () => obj.foo, 
  (newValue, oldValue) => {
      console.log('newValue:', newValue,', oldValue:', oldValue)
  },
  { immediate: true }
)

immediate的值为true时,需要立即执行。明确了需求,我们来完善watch侦听器。

function watch(getter, cb, options = {}) {
  if(typeof getter !== 'function') getter = traverse(getter)
  let oldValue, newValue
  function job() { // (6)
    newValue = effectFn()
    cb(newValue, oldValue)
    oldValue = newValue
  }

  const effectFn = effect(
    () => getter(),
    {
      lazy: true,
      scheduler: job,
    }
  )

  if(options.immediate) {  // (7)
    job()
  } else {
    oldValue = effectFn()
  } 
}

在(6)处,我们抽离了回调函数的执行逻辑,当options.immediate存在时,直接触发执行。

实现效果

到此这篇关于Vue3侦听器是如何实现的的文章就介绍到这了,更多相关Vue3侦听器内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Vue3侦听器的实现原理详情

本文链接: https://lsjlt.com/news/166361.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Vue3侦听器的实现原理详情
    目录侦听响应式对象侦听属性值侦听获取新值和旧值实现效果前言: 本篇内容基于Vue3计算属性是如何实现的实现。 侦听响应式对象 前面我们聊到计算属性,它可以自动计算并缓存响应式数据的值...
    99+
    2024-04-02
  • Vue3侦听器的实现原理是什么
    侦听响应式对象前面我们聊到计算属性,它可以自动计算并缓存响应式数据的值。而如果我们仅需要在响应式数据变化时,执行一些预设的操作,就可以使用watch侦听器。我们还是先来实现一个最简单的例子,然后来一点一点扩充它。const data = {...
    99+
    2023-05-16
    Vue3
  • Vue3源码分析侦听器watch的实现原理
    目录watch 的本质watch 的函数签名侦听多个源侦听单一源watch 的实现watch 函数source 参数cb 参数options 参数doWatch 函数doWatch ...
    99+
    2022-11-13
    Vue3侦听器watch Vue3侦听器watch原理
  • 深入了解Vue3中侦听器watcher的实现原理
    目录watch API 的用法watch API实现原理标准化source构造回调函数创建scheduler创建effect返回销毁函数异步任务队列的设计异步任务队列的创建异步任务队...
    99+
    2024-04-02
  • 详解Vue3中的watch侦听器和watchEffect高级侦听器
    目录1watch侦听器2watchEffect高级侦听器清除副作用:就是在触发监听之前会调用一个函数可以处理你的逻辑例如防抖停止跟踪 watchEffect 返回一个函数 调用之后将...
    99+
    2022-11-13
    Vue3 watch侦听器 vue3 watchEffect侦听器
  • 计算属性和侦听器详情
    目录1、计算属性1.1 基础例子1.2 计算属性缓存 vs 方法1.3 计算属性 vs 侦听属性1.4 计算属性的 setter2、侦听器1、计算属性 模板内的表达式非常便利,但是设...
    99+
    2024-04-02
  • 详解Vue3 中的计算属性及侦听器
    目录计算属性缓存getter 和 setter侦听器配置选项其它写法计算属性 我们知道,在模板中可以直接通过插值语法显示一些data中的数据,但是在某些情况,我们可能需要对数据进行一...
    99+
    2022-11-13
    Vue3 计算属性 Vue3 侦听器
  • 详解Vue3中侦听器watch的使用教程
    目录watch 侦听器使用。侦听器监听 reactive监听多个参数执行各自逻辑监听多个参数执行相同逻辑上一节我们简单的介绍了一下 vue3 项目中的计算属性,这一节我们继续 vue...
    99+
    2024-04-02
  • Vue2和Vue3如何使用watch侦听器详解
    watch:侦听数据变化 (某个值的change事件) vue2.x data(){ return{ num:10 } }, watc...
    99+
    2024-04-02
  • vue3.0中的watch侦听器实例详解
    目录前言 侦听器和计算属性的区别vue3如何使用watch呢? 基本使用监听多个响应式数据侦听reactive定义的响应式数据 监听reactive定义的响应式数据的某一个属性配置选...
    99+
    2024-04-02
  • 一文搞懂Vue3中watchEffect侦听器的使用
    目录watchEffect 侦听器watchEffect 侦听器使用watchEffect 监听基本数据watchEffect 监听复杂数据watchEffect 啥时候执行关闭 w...
    99+
    2024-04-02
  • Vue3 TypeScript 实现useRequest详情
    目录前言:效果展示Axiosinterfaceaxios的简单封装useRequest如何使用添加泛型支持queryKey的问题完整代码结语前言: 自从 Vue3 ...
    99+
    2024-04-02
  • Vue3中的计算属性及侦听器怎么使用
    计算属性我们知道,在模板中可以直接通过插值语法显示一些data中的数据,但是在某些情况,我们可能需要对数据进行一些转化后再显示,或者需要将多个数据结合起来进行显示在模板中使用表达式,可以非常方便的实现,但是设计它们的初衷是用于简单的运算,在...
    99+
    2023-05-14
    Vue3
  • Vue3中的计算属性及侦听器如何使用
    这篇文章主要介绍“Vue3中的计算属性及侦听器如何使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Vue3中的计算属性及侦听器如何使用”文章能帮助大家解决问题。计算属性我们知道,在模板中可以直接通...
    99+
    2023-07-06
  • 详解vue3 响应式的实现原理
    目录核心设计思想Vue.js 2.x 响应式Vue.js 3.x 响应式依赖收集:get 函数派发通知:set 函数总结源码参考核心设计思想 除了组件化,Vue.js 另一个核心设计...
    99+
    2024-04-02
  • Vue3插槽Slot实现原理详解
    目录Vue官方对插槽的定义Slot到底是什么如何使用插槽回顾组件渲染的原理插槽的初始化原理解析插槽中的内容作用域插槽原理具名插槽原理默认内容插槽的原理Vue官方对插槽的定义 Vue ...
    99+
    2024-04-02
  • Template ref在Vue3中的实现原理详解
    目录背景模板的编译setup 函数返回值的处理组件的渲染Template Ref 的注册总结背景 最近我的 Vue3 音乐课程后台问答区频繁出现一个关于 Template ref 在...
    99+
    2024-04-02
  • Vue中如何实现对Array的数据侦听
    这篇文章给大家分享的是有关Vue中如何实现对Array的数据侦听的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。核心思想通过创建一个拦截器来覆盖数组本身的原型对象Array.pro...
    99+
    2024-04-02
  • Vue2和Vue3的nextTick实现原理
    目录一次弄懂 Vue2 和 Vue3 的 nextTick 实现原理Vue2 中的 nextTick异步任务队列宏任务和微任务总结Vue3 中的 nextTickPromise 在浏...
    99+
    2023-05-18
    Vue2和Vue3的nextTick实现原理 Vue2 nextTick实现原理 Vue3 nextTick 实现原理
  • Vue3使用Proxy实现数据监听的原因分析
    vue 数据双向绑定原理,而这个方法有缺点,并且不能实现数组和对象的部分监听情况;具体也可以看我之前写的一篇博客: 关于 Vue 不能 watch 数组 和 对象变化的解决方案,最新...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作