Vue2 diff(patchVnode)--虚拟节点比较过程

444 阅读2分钟

(一)什么是虚拟节点

 在vue中,采用虚拟节点进行dom的模拟,以减少真实dom的创建更新达到优化的目的

(二)diff是怎么比较的

vue 比较节点的入口是patch 函数(old,vnode,hyd,removeonly), 在patch的过程中会判断节点是否需要更新在patchVnode中决定,patchVnode中对各种节点的情况做出不同的处理,其中的主要对比逻辑在updateChildre中 即:

patch(old,vnode){
	if(patchable){
		patchVnode(oldVnode,newVnode);
	}
}
patchVnode(oldVnode,newVnode){
	// 省略各种不需要更新子节点的情况
	updateChildren(oldVnode.children,newVnode.children)
	// 这里vNode中children节点是一个数组,updateChildren中采用双指针的方法进行数组的遍历。
}

patchVode过程:

patchVode 入参:新旧节点,插入到新节点的队列

如果新旧节点相等=>返回

新旧节点为静态节点/once节点。返回,不进行patch

新节点不为text=>新旧节点都有子节点=>updateChildren

                            新节点有子节点,addnodes(增加新节点中的子节点);(此之前会检查key,有重复则报错提醒)

                            旧节点有子节点: removeNodes(删除旧节点中的子节点);

新节点为text=>新旧节点text不同则做更新旧节点

updateChildren过程:

两个新旧节点的数组:伪代码

if(oldStart == newStart){
    oldStart++;
    newStart++;
}
if(oldEnd == newOld){
  oldEnd--;
  newOld--;
}
if(oldStart == newEnd){
   patchVonde(oldStart,newEnd);
   insert newEnd before oldStart
}
if(oldEnd == newStart){
   patchVonde(oldEnd,newStart);
   insert newStart before oldEnd
}
// key 的作用 有key的时候会复用oldNode =>但是会增加一次patch 的过程
// 没有key => 直接新建节点-》dom操作
if(newStart的key在旧节点的key中可以找到){
	// 要插入的节点=旧节点中相同key的节点
	if(要插入的节点和newStart是相同节点){
		patchVnode(要插入的节点、newStart);
		在oldStart前插入(要插入的节点)
	}
}else{
	创建一个新的节点并插入到oldStart前
}

image.png


stateDiagram-v2

[*]-->新节点不存在

[*]-->新节点存在

新节点不存在 --> 旧节点存在

旧节点存在 --> 销毁旧节点(destroy)

新节点存在 --> 旧节点不存在

旧节点不存在 --> 新增节点

新节点存在 --> 旧节点存在且新旧都为vnode

旧节点存在且新旧都为vnode --> patchVnode

新节点存在 --> 旧节点为真实dom

旧节点为真实dom --> 同事