vue的diff算法知识点总结
源码:https://github.com/vuejs/vue/blob/dev/src/core/vdom/patch.js 虚拟domdiff算法首先要明确一个概念就是diff的对象是虚拟dom,更新真实dom则是diff算法的结果 Vnode基类这个部分的代码 主要是为了更好地知道在diff算法中具体diff的属性的含义,当然也可以更好地了解vnode实例 整体过程 核心函数是patch函数
这里是一个外层的比较函数,直接去比较了两个节点的key,tag(标签),data的比较(注意这里的data指的是VNodeData),input的话直接比较type。 这会确认两个节点是否有进一步比较的价值,不然直接替换 替换的过程主要是一个createElm函数 另外则是销毁oldVNode 插入过程简化来说就是判断node的type分别调用 createComponent(会判断是否有children然后递归调用) createComment createTextNode 创建后使用insert函数 之后需要用hydrate函数将虚拟dom和真是dom进行映射 核心函数const elm = vnode.elm = oldVnode.elm
if (isTrue(oldVnode.isAsyncPlaceholder)) { if (isTrue(vnode.isStatic) && let i const oldCh = oldVnode.children
updateChildren这部分重点还是关注整个算法 首先四个指针,oldStart,oldEnd,newStart,newEnd,两个数组,oldVnode,Vnode。 while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
if (isUndef(oldStartVnode)) { oldStartVnode = oldCh[++oldStartIdx] // Vnode has been moved left } else if (isUndef(oldEndVnode)) { oldEndVnode = oldCh[--oldEndIdx] } else if (sameVnode(oldStartVnode,newStartVnode)) { patchVnode(oldStartVnode,newStartVnode,insertedVnodeQueue) oldStartVnode = oldCh[++oldStartIdx] newStartVnode = newCh[++newStartIdx] } else if (sameVnode(oldEndVnode,newEndVnode)) { patchVnode(oldEndVnode,newEndVnode,insertedVnodeQueue) oldEndVnode = oldCh[--oldEndIdx] newEndVnode = newCh[--newEndIdx] } else if (sameVnode(oldStartVnode,newEndVnode)) { // Vnode moved right patchVnode(oldStartVnode,insertedVnodeQueue) canMove && nodeOps.insertBefore(parentElm,oldStartVnode.elm,nodeOps.nextSibling(oldEndVnode.elm)) oldStartVnode = oldCh[++oldStartIdx] newEndVnode = newCh[--newEndIdx] } else if (sameVnode(oldEndVnode,newStartVnode)) { // Vnode moved left patchVnode(oldEndVnode,oldEndVnode.elm,oldStartVnode.elm) oldEndVnode = oldCh[--oldEndIdx] newStartVnode = newCh[++newStartIdx] } else { if (isUndef(oldKeyToIdx)) oldKeyToIdx = createKeyToOldIdx(oldCh,oldStartIdx,oldEndIdx) idxInOld = isDef(newStartVnode.key) ? oldKeyToIdx[newStartVnode.key] : findIdxInOld(newStartVnode,oldEndIdx) if (isUndef(idxInOld)) { // New element createElm(newStartVnode,parentElm,false,newStartIdx) } else { vnodeToMove = oldCh[idxInOld] if (sameVnode(vnodeToMove,newStartVnode)) { patchVnode(vnodeToMove,insertedVnodeQueue) oldCh[idxInOld] = undefined canMove && nodeOps.insertBefore(parentElm,vnodeToMove.elm,oldStartVnode.elm) } else { // same key but different element. treat as new element createElm(newStartVnode,newStartIdx) } } newStartVnode = newCh[++newStartIdx] } } if (oldStartIdx > oldEndIdx) { refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm addVnodes(parentElm,refElm,newStartIdx,newEndIdx,insertedVnodeQueue) } else if (newStartIdx > newEndIdx) { removeVnodes(parentElm,oldEndIdx) } } 一个循环比较的几种情况和处理(以下的++ --均指index的++ --)比较则是比较的node节点,简略写法 不严谨 比较用的是sameVnode函数也不是真的全等 整体循环不结束的条件oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx
循环结束后并没有完成 还有一段判断才算完 oldEndIdx) {
refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm
addVnodes(parentElm,oldEndIdx)
}
简单的说就是循环结束后,看四个指针中间的内容,old数组中和new数组中,多退少补而已 总结整体认识还很粗糙,不过以目前的水平和对vue的了解也就只能到这了 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |