更新子节点
因为VNode是一个树结构,他有很多子 Children,那么就需要依次向下遍历,
这个遍历的方法就是 patchChildren 。
这里比较重要
const patchChildren = (n1,n2,container,anchor,parentComponent,parentSuspense,isSVG,optimized = false) => {const c1 = n1 && n1.childrenconst prevShapeFlag = n1 ? n1.shapeFlag : 0 // 旧节点const c2 = n2.childrenconst { patchFlag, shapeFlag } = n2 // 新节点// fast pathif (patchFlag > 0) {if (patchFlag & 128 /* KEYED_FRAGMENT */) {patchKeyedChildren(c1,c2,container,anchor,parentComponent,parentSuspense,isSVG,optimized)return} else if (patchFlag & 256 /* UNKEYED_FRAGMENT */) {patchUnkeyedChildren(c1,c2,container,anchor,parentComponent,parentSuspense,isSVG,optimized)return}}// children有3种可能:文本、数组或没有children。if (shapeFlag & 8 /* TEXT_CHILDREN */) {// text children fast pathif (prevShapeFlag & 16 /* ARRAY_CHILDREN */) {// 新节点是文本,旧节点是数组,直接删除。unmountChildren(c1, parentComponent, parentSuspense)}// 新节点是文本,和旧节点不相同,直接替换。if (c2 !== c1) {hostSetElementText(container, c2)}} else {if (prevShapeFlag & 16 /* ARRAY_CHILDREN */) {if (shapeFlag & 16 /* ARRAY_CHILDREN */) {// 新节点和旧节点都是数组,diff比较patchKeyedChildren(c1,c2,container,anchor,parentComponent,parentSuspense,isSVG,optimized)} else {// 新节点不是数组,旧节点是数组,直接删除unmountChildren(c1, parentComponent, parentSuspense, true)}} else {if (prevShapeFlag & 8 /* TEXT_CHILDREN */) {// 替换空文本hostSetElementText(container, '')}// mount new if array 挂载一个新的数组子节点if (shapeFlag & 16 /* ARRAY_CHILDREN */) {mountChildren(c2,container,anchor,parentComponent,parentSuspense,isSVG,optimized)}}}}
代码中的patchKeyedChildren是根据存在的 key 进行 Diff。
代码中的patchUnKeyedChildren是根据不存在的 key 进行 Diff。
总结:
新节点是文本
- 1 - 旧节点是数组,删除所有字节点
- 2 - 旧节点不是是文本,替换文本
- 3 - 旧节点是空,添加文本
新节点是数组
- 1 - 旧节点是数组,diff比较子节点
- 2 - 旧节点不是数组,删除所有子节点
- 3 - 旧节点是空,挂载新的子节点
新节点是空
