Vue实例创建之初始化VNode->HTML

前言

前几篇文章介绍了html转换成vnode的过程以及vnode创建的过程,分析上面的过程都是基于最简单的实例来分析的,而且仅仅是分析处理HTML以及文本部分,对于Vue中指令、过滤器等都没有涉及到,不过差强人意,达到我学习Vue源码的初衷。

本文介绍vnode创建之后的逻辑处理,如何比较替换真实DOM,就是Vue中的diff算法。

具体分析

还是已最基本的简单实例为示例,贯穿整篇文章,即:

<div id="app">
	{{ text }}
</div>

VNode创建这篇文章可知:

Vue.prototype._render主要作用是调用构建好的render函数,得到vnode
之后将vnode作为参数传入_update,之后调用_update

而_update实例方法则是这篇文章的核心。

_update实例方法

实际上_update中主要的点如下:

var prevNode = vm._vnode;
vm._vnode = vnode;
// 是否已存在vnode对象,不存在就表示是初始化,存在就表示是替换
if (!prevNode) {
	vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false);
} else {
	vm.$el = vm.__patch__(prevNode, vnode);
}

从上面主要代码可知,主要区分是否是初始化调用,根据是否是初始化则__patch__的参数会有所不同。

__patch__实例方法

在这里插入图片描述

__patch__方法的主要逻辑处理如上图,从上图逻辑中可知:

如果已存在vnode,那么实际上会调用patchVnode函数来比较之间的区别
如果不存在vnode,实际上会使用挂载点的DOM对象和vnode来进行处理

首先emptyNode函数的调用。

emptyNode函数

该函数就是创建一个空vnode,即:

new VNode(nodeOps.tagName(elm).toLowerCase(), {}, [], undefined, elm);

elm就是当前挂载点的浏览器DOM节点
空vnode对象实际就设置标签名称和elm两个属性

生成vnode之后,接下来的需要关注的处理逻辑:

var oldElm = oldVnode.elm;
// 获取挂载点的父节点,本文示例中就是body节点
var parentElm = nodeOps.parentNode(oldElm);
createElm(vnode, [], parentElm, nodeOps.nextSibling(oldElm));
createElm函数

在这里插入图片描述
上图的主要逻辑可知其主要的处理逻辑:

  • 调用createElement创建节点
  • 调用createChildren处理子节点
  • 调用createTextNode处理文本节点
  • 调用insert将节点添加到指定位置

insert函数实际上内部是调用insertBefore或appendChild来实现节点插入。

setScope函数

主要的功能就是调用setStyleScope函数来给节点添加scopeId。

node.setAttribute(scopeId, '');
removeVnodes函数

顾名思义,该函数是用于实体移除DOM的,结合示例分析梳理主要的处理逻辑如下:
在这里插入图片描述

从上图中可知对于标签节点需要特殊处理,实际上也是处理Vue相关的指令以及remove、destory生命周期相关的处理。

这里主要关注的是removeNode函数,具体的处理:

var parent = nodeOps.parentNode(el);
if (isDef(parent)) nodeOps.removeChild(parent. el);

判断挂载点父节点是否存在,存在就调用removeChild函数来移除指定节点。

createChildren函数

实际上该函数还是调用createElm函数来构建替换节点,主要的处理代码如下:

    if (Array.isArray(children)) {
    // 节点
     for (var i = 0; i < children.length; ++i) {
        createElm(children[i], insertedVnodeQueue, vnode.elm, null, true, children, i);
      }
    } else if (isPrimitive(vnode.text)) {
    // 文本
      nodeOps.appendChild(vnode.elm, nodeOps.createTextNode(String(vnode.text)));
    }

总结

本文只分析了初始化时VNode转化为HTML的主要处理逻辑,其中细节点很多,但主要的处理梳理如下:

_update -> patch -> createElm + removeNode

createElm内部主要处理逻辑:

createElement -> createChildren -> createTextNode -> insert

而createChildren的处理实际上还是调用createElm函数,实际上就是递归处理。

而比较vnode之间的差别主要是patchVnode函数,这部分短期没有计划去看。

本文算是具体分析的最后一篇了,写了大概几篇Vue源码相关的文章,就结果而言差强人意,至少达到了我自身的目标,下篇文章会总结整个流程并实现简易的MVVM框架(实际上结合分析Vue的处理思想,自己动手实现一遍而已)。

猜你喜欢

转载自blog.csdn.net/s1879046/article/details/82979954