本文只在为大家梳理完整的vue3
代码执行流程,从创建createApp
到渲染为真实dom
节点。在读后续文章时,请大家参考以下流程图食用,好了废话不多说,开整!!!(本文主要为梳理思路,不展示太多源码,想了解细节可以看我的其他文章,谢谢!!!
)
点击放大图片->
[c430f20c3e2c4d278cc1cedbfdb95c5f~tplv-k3u1fbpfcp-watermark.image (1221×722) (byteimg.com)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jN0tTAdt-1656666680613)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c430f20c3e2c4d278cc1cedbfdb95c5f~tplv-k3u1fbpfcp-watermark.image?)]
提示:一定要按照流程图哦!!!
我们创建vue3
时,最常见的一个api
就是createApp
,但是在执行createRender
时,createApp
还没有被创建,那该方法是干什么的呢,传入的参数有是什么呢?我们接着往下看。
options
:源码中也叫做 nodeOps
,其实就是vue3
自己重新封装的一些dom
操作,例如insert、remove、createElement等
,在pc端,其实就是利用domcument
下的一些原生方法实现优点:
那就有人要问了,为什么要重新封装,首先有这么几点好处:
vue
的渲染工作与dom
操作完全解耦,这样更适合多端操作,只需要重入对应的nodeOps
即可,自己重新封装对应的dom
操作方法,比如移动端等从流程图来看,调用该方法之后,返回三个Api
,其中我们只关心两个重要的也是常用的createApp、render
我们继续往下看。
这个方法大家应该都不陌生,该方法传入一个根组件rootComponent
,但是并没有做任何处理,在该方法中主要任务创建了一个全局对象app
。我们来看下app中常见的几个api
:
App
vue
实现扩展,如vueRouter、vuex、pinia等
注意:以上方法都应该在mount挂载之前执行
从流程图中我们可以看到,挂载中主要执行了两个操作
createVNode
createVNode
方法中,将组件包装成vnode
对象并且返回render(vnode, rootContainer)
render
就是在前边执行createRender
时返回的方法,我们在此处继续执行它,并且传入两个参数,第一个是我们包装后的rootComponent
,第二个是挂载传入真实domrootContainer
好了,mount
执行完毕,我们进入到render
中继续向下执行
在此方法中,做了一个最重要的工作就是将已经渲染的vnode
,也可以称之为旧的vnode
保存到container._vnode
上,然后调用
patch(container._vnode|| null, vnode)
这样,就形成了新旧vnode
,也就有了diff
的说法,让我们进入到patch
方法中。
patch
中文意思打补丁,也就描述了他的用法,对比新旧vnode
,也就是我们常说的diff
算法,将新的vnode
渲染到真实dom中。
该方法中主要分为了两大分支,当然还有其它,我们就先忽略,跟着主线走下去
processComponent
当传入的n2为组件时进入这个分支
processElement
当传入的n2为元素类型时走该分支
我们先进入processComponent
来对传入的rootComponent
进行处理
该方法中又出现了两个分支
我们接着往下看
该组件中执行了三个主要的方法,我们一个个来看
instance
,因此vue3
中就有了一个方法getCurrentInstance
来访问每个组件的实例。setup
,所以,我们调用的所有方法,也就是在这被执行,比如reactive,ref,生命hook,watch,computed等
,之后将setup
调用的结果保存到instance
中的setupState
属性中。该方法中创建了一个componentUpdateFn
组件更新函数,也就是在这,实现了真正的响应式处理,在setupComponent
中,执行了setup
,在这我们对数据进行了响应式处理,利用reactive/refs
对数据实现了处理,在get
中收集依赖,set
中更新依赖。
在创建好componentUpdateFn
方法之后,我们创建了一个新的对象
new ReactiveEffect(componentUpdateFn)
,之后我们执行返回对象的run
方法,其中执行了传入的componentUpdateFn
函数,在componentUpdateFn
中,我们首先对组件的render
或者template
进行处理,也就对我们用到了响应式数据进行了get
,由此,将ReactiveEffect
收集到对应数据的依赖中,在每次数据修改时,执行componentUpdateFn
,之后,在挂载函数中继续执行patch
,传入处理后的render
或者temeplate
,至此回到patch
中,进行递归。
此时,传入的是根标签包装后的vnode
,所以,此次走的分支为processElement
,让我们跟着流程图继续往下看。
nodeOpts
,也就是dom操作方法,将vnode
渲染为真实的dom,此时,终于将组件渲染到页面上,同时将转换的真实dom存放在vnode.el
上。diff
算法的核心,当组件更新之后,通过diff
算法,将新的vnode
渲染到页面上。至此,vue3从创建到渲染的所有流程执行结束,在数据更新之后,我们通过执行依赖,也就是componentUpdateFn
函数,重复之前的步骤,重新执行组件的render函数
获取根标签,传递给patch
,然后更新页面,一直重复该过程。也就实现了页面的改变。直到网页关闭。