patch的流程
组件页面渲染时,将render返回的新vnode(新节点)和组件实例保存的vnode(旧节点)作为参数,调用patch方法,更新DOM。
判断两个节点是否相同
处理过程中,需要判断节点是否相同。相同节点需要满足以下条件:
key相同
标签类型相同
注释节点标识相同,都是注释节点,或者都不是注释节点
data的值状态相同,或者都有值,或者都没值
function sameVnode (a, b) {// 判断两个VNode节点是否是同一个节点
return (
a.key === b.key && // key相同
(
a.tag === b.tag && // tag相同
a.isComment === b.isComment && // 注释节点标识相同
isDef(a.data) === isDef(b.data) && // data值状态相同
sameInputType(a, b) // input的type相同
)
)
}patch方法
patch判断流程如下:
a) 如果新节点为空,此时旧节点存在(组件销毁时),调用旧节点destroy生命周期函数
b) 如果旧节点为空,根据新节点创建DOM
c) 其他(如果新旧节点都存在)
a) 旧节点不是DOM(组件节点),且新旧节点相同
执行patchVnode
b) 旧节点是DOM元素或者两个节点不相同
创建新节点DOM,销毁旧节点以及DOM。
function patch (oldVnode, vnode, hydrating, removeOnly) {
if (isUndef(vnode)) {
if (isDef(oldVnode)) { invokeDestroyHook(oldVnode); }
return
}
...
if (isUndef(oldVnode)) {
isInitialPatch = true;// 组件初始加载
createElm(vnode, insertedVnodeQueue);
} else {
var isRealElement = isDef(oldVnode.nodeType);
if (!isRealElement && sameVnode(oldVnode, vnode)) {
patchVnode(oldVnode, vnode, insertedVnodeQueue, null, null, removeOnly);
} else {
...
var oldElm = oldVnode.elm;
var parentElm = nodeOps.parentNode(oldElm);// 获取父元素
// create new node
createElm(
vnode,
insertedVnodeQueue,
oldElm._leaveCb ? null : parentElm,
nodeOps.nextSibling(oldElm)// 获取紧跟的弟弟元素
);
if (isDef(parentElm)) {
removeVnodes(parentElm, [oldVnode], 0, 0);// 销毁旧节点以及DOM元素
} else if (isDef(oldVnode.tag)) {
invokeDestroyHook(oldVnode);
}
}
}
invokeInsertHook(vnode, insertedVnodeQueue, isInitialPatch);
return vnode.elm
}
}patchVnode方法
当两个节点相同时,执行patchVnode方法。在处理各种情况之前,会将旧节点elm属性值赋值给新节点的elm属性,保持elm保持一致。
具体流程如下:










