Vue源码解析之_update函数(六)

在$mount函数中,主要是调用了mountComponent函数,而该函数最后主要是调用了updateComponent函数,

上一次我们分析了render函数的功能(主要是利用createElement函数生成vnode),那么_update函数主要做了什么

Vue源码解析之_update函数(六)_第1张图片

首先,可以看到在'src/core/instance/lifecycle.js'中在Vue原型上定义了私有方法_update,在整个函数中,最重要的部分是执执行__patch__函数。在初始换渲染的阶段,向__patch__函数中传入了四个参数值。

Vue源码解析之_update函数(六)_第2张图片


然后,看看__patch__函数的功能(主要是将vnode转换成dom,渲染在视图中)。patch定义在'src/platforms/wed/runtime/patch.js'中。

可以看到,最终的patch是一个createPatchFunction函数返回的函数(函数柯里化),同时传入了两个参数。nodeOps中是一些关于dom node(dom节点)的操作。modules中包含的是基础模块和平台模块,因为vue可以运行在不同的平台(web或者weex),因此这样做的好处是不用每次都去考虑不同平台如何处理。

Vue源码解析之_update函数(六)_第3张图片


createPatchFunction定义在'src/core/patch.js'中,在该js中,最后返回了一个patch函数。在该函数中,第一个参数是dom元素,第二个参数是vnode。

因为vnode和oldVnode都是定义了的,所以前面两个if不成立,程序进入从第694行的else语句。因为oldVnode是dom节点,所以isRealElement为true。程序进入703行的else语句中,在第708行的if判断中,因为第二个条件不成立(并不是在ssr环境中),所以该if判断不成立。进入712行if判断,因为hydrating为false,因此不执行该if判断。

程序执行第728行,oldVnode = emptyNodeAt(oldNode)。这里为什么已经是dom元素了,还要转换为vnode?我认为应该是这个dom元素是原来我们设置的options中el对应的dom节点,但是我们现在要创新新的节点去替换原来的dom节点。所以先转换为vnode。之后在同一进行操作。

Vue源码解析之_update函数(六)_第4张图片


可以看到,emptyNodeAt()函数的功能是创建一个新的vnode。因此oldVnode = emptyNodeAt(oldNode)创新了新的vnode替换,而原来的oldNode(dom节点)可以在该vnode节点的elm元素中访问到



回到patch函数中,取到当前的el对应的dom节点和其父节点后,开始利用createElm函数创建新的dom节点。

Vue源码解析之_update函数(六)_第5张图片


在createElm()函数中,主要完成的功能是将构建dom子节点插入到父节点中,并且一直循环到该节点没有子节点为止。这个过程createElm()函数和createChildren函数一起完成。

Vue源码解析之_update函数(六)_第6张图片


可以看到,在createChildren()函数中,如果该vnode的子节点是矩阵的话,就会调用createElm()函数。因此两个函数是相互调用生成dom节点,然后插入到父节点的过程。如果该子节点是最后一个节点,则直接在dom节点后面插入该文本节点。(比如

message
中的message)

Vue源码解析之_update函数(六)_第7张图片


最后,回到patch函数中,因为新建了一个div来渲染视图,因此应该把原来的就定义的用来挂载的dom节点(一般是个div)删掉。所以,可以看到,在vue的渲染过程中,会创建新的dom节点替换掉以前的节点,因此我们在初始化的时候不能讲节点选择挂载在html和body上。

Vue源码解析之_update函数(六)_第8张图片


总结

实例的私有方法_update主要是调用了patch函数,patch函数的主要功能将vnode转换为dom节点然后渲染在视图中。因此,为了生成dom节点,还需要判断vnode是否有子节点,一直递归到没有子节点时。开始创建子节点并插入在父节点中。最后再将原来定义的根节点移除,因为已经重新建立了新的节点替换原来的根节点。

总结源码分析的第一部分至第六部分,其实就是以下过程:

首先在new Vue之后,对生命周期、事件中心、data、props等进行了初始化。

然后调用$mount函数对$el节点进行渲染。渲染的过程中,Vue只认render函数,那么就会先将template转换为render函数(mountComponent函数的功能)。

然后调用render函数生成vnode。怎么生成?主要是利用createELement函数,先将vnode的children处理为一维数组,然后通过判断tag来生成vnode。

生成vnode之后,就是通过patch函数转换为dom节点,渲染在视图上。那么,怎么将vnode转换为dom节点?在vnode中,有个elm用来保存对应的dom节点,因此不用再额外生成dom(除了文本节点以外)。只是需要不深度遍历children,将children中的dom节点添加到父节点中。完成dom树的构建。

Vue源码解析之_update函数(六)_第9张图片

你可能感兴趣的:(vue源码分析)