vue源码解析文档(vue3源码解析)

本篇文章给大家谈谈vue源码解析文档,以及vue3源码解析对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。

本文目录一览:

【面试题解析】从 Vue 源码分析 key 的作用

最近看了面试题中有一个这样的题, v-for 为什么要绑定 key?

Vue 中 key 很多人都弄不清楚有什么作用,甚至还有些人认为不绑定 key 就会报错。

其实没绑定 key 的话,Vue 还是可以正常运行的,报警告是因为没通过 Eslint 的检查。

接下来将通过源码一步步分析这个 key 的作用。

Virtual DOM 最主要保留了 DOM 元素的层级关系和一些基本属性,本质上就是一个 JS 对象。相对于真实的 DOM,Virtual DOM 更简单,操作起来速度更快。

如果需要改变 DOM,则会通过新旧 Virtual DOM 对比,找出需要修改的节点进行真实的 DOM 操作,从而减小性能消耗。

传统的 Diff 算法需要遍历一个树的每个节点,与另一棵树的每个节点对比,时间复杂度为 O(n²)。

Vue 采用的 Diff 算法则通过逐级对比,大大降低了复杂性,时间复杂度为 O(n)。

VNode 更新首先会经过 patch 函数, patch 函数源码如下:

vnode 表示更新后的节点,oldVnode 表示更新前的节点,通过对比新旧节点进行操作。

1、vnode 未定义,oldVnode 存在则触发 destroy 的钩子函数

2、oldVnode 未定义,则根据 vnode 创建新的元素

3、oldVnode 不为真实元素并且 oldVnode 与 vnode 为同一节点,则会调用 patchVnode 触发更新

4、oldVnode 为真实元素或者 oldVnode 与 vnode 不是同一节点,另做处理

接下来会进入 patchVnode 函数,源码如下:

1、vnode 的 text 不存在,则会比对 oldVnode 与 vnode 的 children 节点进行更新操作

2、vnode 的 text 存在,则会修改 DOM 节点的 text

接下来在 updateChildren 函数内就可以看到 key 的用处。

key 的作用主要是给 VNode 添加唯一标识,通过这个 key,可以更快找到新旧 VNode 的变化,从而进一步操作。

key 的作用主要表现在以下这段源码中。

updateChildren 过程为:

1、分别用两个指针(startIndex, endIndex)表示 oldCh 和 newCh 的头尾节点

2、对指针所对应的节点做一个两两比较,判断是否属于同一节点

3、如果4种比较都没有匹配,那么判断是否有 key,有 key 就会用 key 去做一个比较;无 key 则会通过遍历的形式进行比较

4、比较的过程中,指针往中间靠,当有一个 startIndex endIndex,则表示有一个已经遍历完了,比较结束

从 VNode 的渲染过程可以得知,Vue 的 Diff 算法先进行的是同级比较,然后再比较子节点。

子节点比较会通过 startIndex、endIndex 两个指针进行两两比较,再通过 key 比对子节点。如果没设置 key,则会通过遍历的方式匹配节点,增加性能消耗。

所以不绑定 key 并不会有问题,绑定 key 之后在性能上有一定的提升。

综上,key 主要是应用在 Diff 算法中,作用是为了更快速定位出相同的新旧节点,尽量减少 DOM 的创建和销毁的操作。

希望以上内容能够对各位小伙伴有所帮助,祝大家面试顺利。

Vue 的文档中对 key 的说明如下:

关于就地修改,关键在于 sameVnode 的实现,源码如下:

可以看出,当 key 未绑定时,主要通过元素的标签等进行判断,在 updateChildren 内会将 oldStartVnode 与 newStartVnode 判断为同一节点。

如果 VNode 中只包含了文本节点,在 patchVnode 中可以直接替换文本节点,而不需要移动节点的位置,确实在不绑定 key 的情况下效率要高一丢丢。

某些情况下不绑定 key 的效率更高,那为什么大部分Eslint的规则还是要求绑定 key 呢?

因为在实际项目中,大多数情况下 v-for 的节点内并不只有文本节点,那么 VNode 的字节点就要进行销毁和创建的操作。

相比替换文本带来的一丢丢提升,这部分会消耗更多的性能,得不偿失。

了解了就地修改,那么我们在一些简单节点上可以选择不绑定 key,从而提高性能。

如果你喜欢我的文章,希望可以关注一下我的公众号【前端develop】

vue源码解析文档(vue3源码解析),vue源码解析文档,信息,文章,源码,第1张

vue3源码分析-实现props,emit,事件处理等

本期来实现, setup里面使用props,父子组件通信props和emit等 ,所有的源码请查看

在render函数中, 可以通过this,来访问setup返回的内容,还可以访问this.$el等

由于是测试dom,jest需要提前注入下面的内容,让document里面有app节点,下面测试用例类似在html中定义一个app节点哦

本功能的测试用例正式开始

上面的测试用例

解决这两个需求:

针对上面的分析,需要在setupStatefulComponent中来创建proxy并且绑定到instance当中,并且setup的执行结果如果是对象,也已经存在instance中了,可以通过instance.setupState来进行获取

通过上面的操作,从render中this.xxx获取setup返回对象的内容就ok了,接下来处理el

需要在mountElement中,创建节点的时候,在vnode中绑定下,el,并且在setupStatefulComponent 中的代理对象中判断当前的key

看似没有问题吧,但是实际上是有问题的,请仔细思考一下, mountElement是不是比setupStatefulComponent 后执行,setupStatefulComponent执行的时候,vnode.el不存在,后续mountelement的时候,vnode就会有值,那么上面的测试用例肯定是报错的,$el为null

解决这个问题的关键,mountElement的加载顺序是 render - patch - mountElement,并且render函数返回的subtree是一个vnode,改vnode中上面是mount的时候,已经赋值好了el,所以在patch后执行下操作

在vue中,可以使用onEvent来写事件,那么这个功能是怎么实现的呢,咋们一起来看看

在本功能的测试用例中,可以分析以下内容:

解决问题:

这个功能比较简单,在处理prop中做个判断, 属性是否满足 /^on[A-Z]/i这个格式,如果是这个格式,则进行事件注册,但是vue3会做事件缓存,这个是怎么做到?

缓存也好实现,在传入当前的el中增加一个属性 el._vei || (el._vei = {}) 存在这里,则直接使用,不能存在则创建并且存入缓存

事件处理就ok啦

父子组件通信,在vue中是非常常见的,这里主要实现props与emit

根据上面的测试用例,分析props的以下内容:

解决问题:

问题1: 想要在子组件的setup函数中第一个参数, 使用props,那么在setup函数调用的时候,把当前组件的props传入到setup函数中即可 问题2: render中this想要问题,则在上面的那个代理中,在 加入一个判断,key是否在当前instance的props中 问题3: 修改报错,那就是只能读,可以使用以前实现的 api shallowReadonly来包裹一下 既可

做完之后,可以发现咋们的测试用例是运行没有毛病的

上面实现了props,那么emit也是少不了的,那么接下来就来实现下emit

根据上面的测试用例,可以分析出:

解决办法: 问题1: emit 是setup的第二个参数, 那么可以在setup函数调用的时候,传入第二个参数 问题2: 关于emit的第一个参数, 可以做条件判断,把xxx-xxx的形式转成xxxXxx的形式,然后加入on,最后在props中取找,存在则调用,不存在则不调用 问题3:emit的第二个参数, 则使用剩余参数即可

到此就圆满成功啦!

vue3.0(双向绑定)源码分析

vue3.0双向绑定相关的模块有reactive/effect/computed/ref,这篇文章主要聊聊我对它们的理解,以及我在编码中遇到的问题,希望能给大家带来帮助,首先,一张图来分析它们之间的依赖关系。

把数据转化成响应式的数据,获取/修改数据时,能数据进行劫持操作。vue3.0用的ES6的proxy,在此之前用的是Object.defineProperty。这里有两个问题需要注意:1/proxy不会对子对象进行劫持,需要递归。2/新增数据时,set会执行两次,是因为length属性也进行劫持。

利用高阶函数的思想,把effect弄成一个单独可用的函数体,在函数体内,执行回调函数并在外部进行一些逻辑处理。在effect文件中,还暴露了track/trigger。当effect中,存在依赖的数据,会调用reactive文件的get方法,get方法调用track,track函数会把storeEffect中的effect用一种格式存储起来。set方法会调用trigger,trigger会调用get存储的effect。

依赖effect当数据改变时,触发当前的get回调函数,当获取返回值时,返回当前get回调函数的返回值,当设置时,触发set回调函数传递最新值。这里有点需要注意,这里的有个缓存机制,获取相同的值时,get回调函数值触发一次,通过dirty变量实现。

绑定一个非对象类型的数据,直接通过返回对象的get/set方法实现。

项目案例

vue3源码解读--data响应式的处理

目录

    vue2源码

    vue3源码

示例

源码

    上一节,我们已经看到了组件被挂载到页面的流程。但是忽略了对options的处理。vue2中是在组件init过程中就对配置项进行了合并处理,vue3中是在组件创建即setupComponent中执行applyOptions做的这个事情

    经过对组件实例的解析操作,最终拿到的dataOptions即我们实例中的data函数。可以看到,在vue3已经不允许根组件定义为对象了

    显然reactive即响应式实现的关键,顺着调用关系找到createReactiveObject函数。常听人提起的Proxy赫然立于眼前

    proxy和Object.defineProperty差不多,都可以拦截对象的访问和修改操作,那么接下来的重点就是看下它是如何做依赖收集和派发更新的即可

    当前targetType=1,使用baseHandlers做处理器,即createGetter函数。当组件render过程中将会触发msg的访问执行到此

    可以看到,如果msg是一个对象,则会递归reactive。为什么要递归处理呢?proxy不是已经把整个对象都代理到了吗?

    写一个例子看一下

        如果正常访问,我没有问题的,每次都可以正确的触发get

        如果是拿到返回值再进行访问的话,res.c就是无效的

        把第二个值也转为Proxy后就可以了

    回到正题,进入track函数

    在trackEffects中完成依赖收集

    同样的,当set newValue时将执行到createSetter。这将执行trigger进行更新派发

总结

    拿到options的data--视情况(如对象递归执行)进行reactive化--在访问时收集依赖(ReactiveEffect)--设置值时派发更新

    proxy.x相当于让activeEffect去订阅data的change,proxy.x = y则相当于data发布更新,通知activeEffect执行componentUpdateFn             --观察者模式

vue2.0源码解析(上)

vue项目地址:

当前版本号:2.6.11

1、基本目录结构:

1、找到initState()函数,这是初始化响应式的入口。

关于vue源码解析文档和vue3源码解析的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。

1、本网站名称:源码村资源网
2、本站永久网址:https://www.yuanmacun.com
3、本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长进行删除处理。
4、本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
5、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
6、本站资源大多存储在云盘,如发现链接失效,请联系我们我们会第一时间更新。
源码村资源网 » vue源码解析文档(vue3源码解析)

1 评论

您需要 登录账户 后才能发表评论

发表评论

欢迎 访客 发表评论