day186-具体的diff分析过程(vuejs)-笔记

要点

  1. updateChildren()代码

代码相对较多,较繁琐,这里了解代码和key起的作用就可。

代码 + 内部注释

patch过程中父节点相同,父节点文本内容相同,子节点不同updateChildren()的比较。

基本思路就是两个树进行新旧节点的比较。

updateChildren (parentElm, oldCh, newCh) {
let oldStartIdx = 0, newStartIdx = 0
let oldStartVnode = oldCh[0]

let oldEndIdx = oldCh.length - 1
let oldEndVnode = oldCh[oldEndIdx]

let newStartVnode = newCh[0]

let newEndIdx = newCh.length - 1
let newEndVnode = newCh[newEndIdx]

let oldKeyToIdx
let idxInOld
let elmToMove
let before
// 判断遍历是否结束
while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
// 1,不设置key
if (oldStartVnode === null) {
// 2,都是两头指针相互向中间靠
oldStartVnode = oldCh[++oldStartIdx]
} else if (oldEndVnode === null) {
oldEndVnode = oldCh[--oldEndIdx]
} else if (newStartVnode === null) {
newStartVnode = newCh[++newStartIdx]
} else if (newEndVnode === null) {
newEndVnode = newCh[--newEndIdx]
// 3,递归调用,需要看清楚具体比较的东西是什么
} else if (sameVnode(oldStartVnode, newStartVnode)) {
patchVnode(oldStartVnode, newEndVnode)

// 如果碰到一样的节点,就深度遍历比较,走递归
oldStartVnode = oldCh[++oldStartIdx]
newStartVnode = newCh[++newStartIdx]
} else if (sameVnode(oldEndVnode, newEndVnode)) {
patchVnode(oldEndVnode, newEndVnode)

oldEndVnode = oldCh[--oldEndIdx]
newEndVnode = newCh[--newEndIdx]
} else if (sameVnode(oldStartVnode, newEndVnode)) {
// ????
patchVnode(oldEndVnode, newEndVnode)

// 需要对dom进行移动
api.insertBefore(parentElm, oldStartVnode.el, api.nextSibling(oldEndVnode.el))

oldStartVnode = oldCh[++oldStartIdx]
newEndVnode = newCh[--newEndIdx]
} else if (sameVnode(oldEndVnode, newStartVnode)) {
patchVnode(oldEndVnode, newStartVnode)

// 需要对dom进行移动
api.insertBefore(parentElm, oldEndVnode.el, oldStartVnode.el)

oldEndVnode = oldCh[--oldEndIdx]
newStartVnode = newCh[++newStartIdx]
} else {
// 设置key,除头尾两端比较外,加了一个oldKeyToIdx对象表,从中查找匹配的节点
if (oldKeyToIdx === undefined) {
// 有key时生成index表
oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx)
}
idxInOld = oldKeyToIdx[newStartVnode.key]
if (!idxInOld) {
api.insertBefore(parentElm, createEle(newStartVnode).el, oldStartVnode.el)
newStartVnode = newCh[++newStartIdx]
} else {
elmToMove = oldCh[idxInOld]
if (elmToMove.sel !== newStartVnode.sel) {
api.insertBefore(parentElm, createEle(newStartVnode).el, oldStartVnode.el)
} else {
patchVnode(elmToMove, newStartVnode)

oldCh[idxInOld] = null
api.insertBefore(parentElm, elmToMove.el, oldStartVnode.el)
}
newStartVnode = newCh[++newStartIdx]
}
}
}
if (oldStartIdx > oldEndIdx) {
before = newCh[newEndIdx + 1] === null ? null : newCh[newEndIdx + 1].el
addVnodes(parentElm, before, newCh, newStartIdx, newEndIdx)
} else if (newStartIdx > newEndIdx) {
removeVnodess(parentElm, oldCh, oldStartIdx, oldEndIdx)
}
}

参考

原文点此

文章作者: lmislm
文章链接: http://lmislm.com/2019/07/18/2019-07-18/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 LMISLMのBlog