开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 2 天,点击查看活动详情
节点列表末尾尝试复用
上次说到了老节点和新节点开头尽量复用,接下来就是后面尽量复用了,尝试比对新节点最后一个和老节点最后一个type和key是否相同,如果是直接调用patch方法更新dom,这个节点的更新也就完毕了,后面就不用处理了,然后将新老节点结束索引往前移动一位,再尝试前面的操作,直到遇到不可以复用的老节点后,结束这个尝试,最坏的结果是一个都不可以复用,但这无关紧要。
while (i <= e1 && i <= e2) {
const n1 = c1[e1];
const n2 = c2[e2];
if (isSameVNodeType(n1, n2)) {
patch(n1.key);
} else {
break;
}
e1--;
e2--;
}
阶段性成果
通过尝试复用列表开始和尝试复用列表结束,已经将开始可以复用节点处理完,结束可以复用的dom处理完了 假设有如下新的和旧的节点列表
肉眼可见的,前面两个key为a,b的节点,和后面两个key为f,g的节点都是可以复用的,只需要patch一下就完成了dom更新,而到现在为止。我们的代码,已经可以做到这一点了。
后面还未处理的就剩下如下这些不是开头可以复用结尾可以复用,不太规律的节点了
当前这只是通过人来判断的,后面要用逻辑处理
老节点能用的都用了,新节点还没处理完
i是新老节点列表当前未处理的开始位置索引,e1是老节点当前未处理的结束位置的索引,当开始位置大于结束位置,则说明,需要处理的节点已经没有了。此时逻辑就非常简单,直接mountElement所有剩下未处理的新节点。
if (i > e1) {
while (i <= e2) {
const n2 = c2[i];
mountElement(n2.key);
i++;
}
}
假设新旧节点结构如下
let list1 = [{
key: "a",
},
{
key: "b",
},
{
key: "f",
},
{
key: "g",
},
];
let list2 = [{
key: "a",
},
{
key: "b",
},
{
key: "e",
},
{
key: "c",
},
{
key: "d",
},
{
key: "h",
},
{
key: "f",
},
{
key: "g",
},
];
前面尝试复用结束后i变成2,后面尝试复用结束后e1变成1。此时就符合老节点已经处理完,只剩下新节点,e2此时为5,新节点未处理的节点分别为e,c,d,h,也就是下标2,3,4,5。
新节点处理完了,老节点没处理完
上面的情况反过来,新节点处理完了。老节点没处理完,这些老节点就全部卸载就行了。
else if (i > e2) {
while (i <= e1) {
const n1 = c1[i];
unmount(n1.key);
i++;
}
}
最后一种剩下了新的和老的,是diff算法最核心的算法了,也是最终要面对的问题,今天脑子不够用了,要等明天来搞了