导航:首页 > 源码编译 > vue的源码看不懂

vue的源码看不懂

发布时间:2024-08-07 18:49:09

‘壹’ vue生命周期详解

vue源码中最终执行生命周期函数都是调用 callHook 方法, callHook 函数的逻辑很简单,根据传入的生命周期类型 hook ,去拿到 vm.$options[hook] 对应的回调函数数组,然后遍历执行,执行的时候把 vm 作为函数执行的上下文。

1. new Vue(options) :创建一个vm实例;

2. mergeOptions(resolveConstructorOptions(vm.constructor), options, vm) :合并Vue构造函数里options和传入的options或合并父子的options。比如:在mergeOptions函数中会调用mergeHook方法合并生命周期的钩子函数,mergeHook方法原理是只有父时返回父,只有子时返回数组类型的子。父、子都存在时,将子添加在父的后面返回组合而成的数组。这也是父子均有钩子函数的时候,先执行父的后执行子的的原因;

3. initLifecycle(vm)、initEvents(vm)、initRender(vm) :在创建的vm实例上初始化生命周期、事件、渲染相关的属性;

4. callHook(vm, 'beforeCreate') :调用beforeCreate生命周期钩子函数;

5. initInjections(vm)、initState(vm)、initProvide(vm) :初始化数据:inject、state、provide。initState 的作用是初始化 props、data、methods、watch、computed 等属性;

6. callHook(vm, 'created') :调用created生命周期钩子函数;

7. vm.$mount(vm.$options.el) : $mount 方法在多个文件中都有定义,如"src/platform/web/entry-runtime-with-compiler.js"、"src/platform/web/runtime/index.js"、"src/platform/weex/runtime/index.js"。因为 $mount 方法的实现是和平台、构建方式相关的。以"entry-runtime-with-compiler.js"为例,关键步骤是查看 vm.$options 中是否有render方法,如果没有则会根据el和template属性确定最终的template字符串,再调用 compileToFunctions 方法将template字符串转为render方法,最后,调用原先原型上的$mount方法,即开始执行"lifecycle.js"中 mountComponent 方法;

8. callHook(vm, 'beforeMount') :调用beforeMount生命周期钩子函数;

9. vm._render() => vm._update() => vm.__patch__() :先执行vm._render方法,即调用createElement生成虚拟DOM,即VNode ,每个VNode有children ,children 每个元素也是⼀个 VNode,这样就形成了⼀个 VNode Tree;再调用vm._update方法进行首次渲染,vm._update方法核心是调用vm. patch 方法,这个方法跟vm.$mount一样跟平台相关;vm. patch 方法则是根据生成的VNode Tree递归createElm方法创建真实Dom Tree挂载到Dom上;

10. callHook(vm, 'mount') :调用mount生命周期钩子函数:VNode patch 到 Dom 之后会执行 'invokeInsertHook'函数,把 insertedVnodeQueue 中保存的mount钩子函数执行一遍,insertedVnodeQueue队列中的钩子函数是在根据VNode Tree递归createElm方法创建真实Dom Tree过程生成的钩子函数顺序队列,因此mounted钩子函数的执行顺序是先子后父;

11. data changes :数据更新,nextTick中执行 flushSchelerQueue 方法,该方法会执行watcher队列中的watcher;

12. callHook(vm, 'beforeUpdate') :执行watcher时会执行watcher的before方法,即调用beforeUpdate生命周期钩子函数;

13. Virtual DOM re-render and patch :重新render生成新的Virtual DOM,并且patch到DOM上;

14. callHook(vm, 'updated') :调用updated生命周期钩子函数;

15. vm.$destroy() :启动卸销毁过程;

16. callHook(vm, 'beforeDestroy') :调用beforeDestroy生命周期钩子函数;

17. Teardown watchers, childcomponents and event listeners :执行一系列销毁动作,在 $destroy 的执行过程中,它又会执行 vm.__patch__(vm._vnode, null) 触发它子组件的销毁钩子函数,这样一层层的递归调用,所以 destroyed 钩子函数执行顺序是先子后父,和 mounted 过程一样。

18. callHook(vm, 'destroyed ') :调用destroyed 生命周期钩子函数。

‘贰’ 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的第二个参数, 则使用剩余参数即可

到此就圆满成功啦!

‘叁’ 面试中的网红Vue源码解析之虚拟DOM,你知多少呢深入解读diff算法

众所周知,在前端的面试中,面试官非常爱考dom和diff算法。比如,可能会出现在以下场景

滴滴滴,面试官发来一个面试邀请。接受邀请📞

我们都知道, key 的作用在前端的面试是一道很普遍的题目,但是呢,很多时候我们都只浮于知识的表面,而没有去深挖其原理所在,这个时候我们的竞争力就在这被拉下了。所以呢,深入学习原理对于提升自身的核心竞争力是一个必不可少的过程。

在接下来的这篇文章中,我们将讲解面试中很爱考的虚拟DOM以及其背后的diff算法。 请认真阅读本文~文末有学习资源免费共享!!!

虚拟DOM是用JavaScript对象描述DOM的层次结构。DOM中的一切属性都在虚拟DOM中有对应的属性。本质上是JS 和 DOM 之间的一个映射缓存。

要点:虚拟 DOM 是 JS 对象;虚拟 DOM 是对真实 DOM 的描述。

diff发生在虚拟DOM上。diff算法是在新虚拟DOM和老虚拟DOM进行diff(精细化比对),实现最小量更新,最后反映到真正的DOM上。

我们前面知道diff算法发生在虚拟DOM上,而虚拟DOM是如何实现的呢?实际上虚拟DOM是有一个个虚拟节点组成。

h函数用来产生虚拟节点(vnode)。虚拟节点有如下的属性:
1)sel: 标签类型,例如 p、div;
2)data: 标签上的数据,例如 style、class、data-*;
3)children :子节点;
4) text: 文本内容;
5)elm:虚拟节点绑定的真实 DOM 节点;

通过h函数的嵌套,从而得到虚拟DOM树。

我们编写了一个低配版的h函数,必须传入3个参数,重载较弱。

形态1:h('div', {}, '文字')
形态2:h('div', {}, [])
形态3:h('div', {}, h())

首先定义vnode节点,实际上就是把传入的参数合成对象返回。

[图片上传失败...(image-7a9966-1624019394657)]
然后编写h函数,根据第三个参数的不同进行不同的响应。

当我们进行比较的过程中,我们采用的4种命中查找策略:
1)新前与旧前:命中则指针同时往后移动。
2)新后与旧后:命中则指针同时往前移动。
3)新后与旧前:命中则涉及节点移动,那么新后指向的节点,移到 旧后之后
4)新前与旧后:命中则涉及节点移动,那么新前指向的节点,移到 旧前之前

命中上述4种一种就不在命中判断了,如果没有命中,就需要循环来寻找,移动到旧前之前。直到while(新前<=新后&&旧前<=就后)不成立则完成。

如果是新节点先循环完毕,如果老节点中还有剩余节点(旧前和旧后指针中间的节点),说明他们是要被删除的节点。

如果是旧节点先循环完毕,说明新节点中有要插入的节点。

1.什么是Virtual DOM 和Snabbdom
2.手写底层源码h函数
3.感受Vue核心算法之diff算法
4.snabbdom之核心h函数的工作原理

1、零基础入门或者有一定基础的同学、大中院校学生
2、在职从事相关工作1-2年以及打算转行前端的朋友
3、对前端开发有兴趣人群

阅读全文

与vue的源码看不懂相关的资料

热点内容
python遍历两个数组 浏览:393
手游搭建云服务器 浏览:401
视易锋云服务器启动黑屏 浏览:139
python怎么获取网页a标签内容 浏览:982
app更新后老的安装包去哪里了 浏览:199
集合运算法则差集 浏览:310
x2pdf 浏览:271
python源码cs 浏览:101
数控机床自动编程软件 浏览:738
方舟的服务器号是什么 浏览:111
没有服务器怎么发现其他节点 浏览:337
文明传奇怎么开服务器 浏览:56
javalistint 浏览:675
程序员到公司当领导 浏览:225
用算法控制玩家的行为 浏览:484
androidsdk17下载 浏览:793
怎么给单独表格添加密码 浏览:13
下载压缩密码 浏览:260
android系统上编程 浏览:470
单片机模拟i2c从机 浏览:238