0


vue diff算法与虚拟dom知识整理(15) 终结篇,收尾新前到旧前全部不匹配情况

我们现在就只需要处理最后一种情况了

我们在 updateChildren.js
在while中
在这里插入图片描述
的if最后加个 else
在这里插入图片描述
当他们都没哟匹配到的情况

我们现在在updateChildren.js最上面 定义一个空对象 叫 keyMap
参考代码如下

let keyMap =null;

在这里插入图片描述

然后 在我们刚写的else中编写代码如下

//判断  如果没有keyMap  表示之前没有处理过if(!keyMap){//将keyMap 转成一个对象
    keyMap ={};//循环遍历  条件为旧前加到大于旧后  简单说遍历所有 旧节点的子节点for(let i = oldStartIdx; i <= oldEndIdx; i++){//先存入对应子节点的keyconst key = oldch[i].key;//判断如果是undefined就不要进来了if(key !=undefined){
            keyMap[key]= i;}}}
console.log(keyMap);
newStartIdx++;

在这里插入图片描述
简单说 我们判断 如果所有条件都不匹配 就先看看 keyMap中有没有内容 如果没有 就将他设置为一个真的对象 然后 循环所有的旧节点的子节点集合 拿取每一个子节点key 如果key不是undefined 就将key和下标记录给keyMap
最后打印一下结果在控制台 顺手将新前newStartIdx节点加一 因为 如果你不处理 他会死循环的

我们马上来试一下效果
将src下的index.js代码修改如下

import h from"./snabbdom/h";import patch from"./snabbdom/patch";const container = document.getElementById("container");const vnode =h("section",{},[h("p",{key:"a"},"a"),h("p",{key:"b"},"b"),h("p",{key:"c"},"c"),h("p",{key:"d"},"d")]);patch( container, vnode)const btn = document.getElementById("btn");const vnode1 =h("section",{},[h("p",{key:"QQQ"},"QQQ")]);

btn.onclick=function(){patch( vnode, vnode1)}

这样 肯定是不管他什么新前旧前的都匹配不上了 因为我们就一个 QQQ 是旧节点压根没有的

然后我们运行项目
在这里插入图片描述
然后点击 更改dom
在这里插入图片描述
可以看到 内容全没了 控制台也成功输出了旧节点的key和下标

这里 没了是因为 我们上文写的 while下面那个旧节点删除的逻辑将他们都处理掉了
在这里插入图片描述
但现在显然我们要想办法把这个qqq弄上去

我们在这个console.log(keyMap); 后面在加一段代码

//从keyMap中去寻找和新前节点的key相同的节点下标  然后赋值给idxInoldconst idxInold = keyMap[newStartVnode.key];
console.log(idxInold);

在这里插入图片描述
因为 新前肯定是我们正在处理的这个节点 我们去匹配一下 keyMap 中的内容
如果有和新前key一样的 就取过来 如果没有 我们取到的就是个undefined
我们运行项目 然后点击 更改dom 查看控制台
在这里插入图片描述
很显然 他输出了undefined
因为旧节点的子节点中 并没有key为QQQ的子节点
我们可以改一些src下的index.js
将 vnode1 改为

const vnode1 =h("section",{},[h("p",{key:"c"},"QQQ")]);

然后我们运行项目 点击更改dom
在这里插入图片描述
可以看到 这次我们就取到了

那么 这个就非常简答了 如果 最后
idxInold不是undefined 表示 旧节点中有这个节点 需要更改一下
如果是undefined 表示 新前就是个全新的节点 需要插入进去

但在这之前 我们要改一下代码
updateChildren.js中的while循环开头加入这样的逻辑代码

//判断如果旧前节点是空的  控制指针后移if(oldStartVnode ==null|| oldch[oldStartIdx]==undefined){
    oldStartVnode = oldch[++oldStartIdx];//判断旧后如果是空的  将旧后向前移一个}elseif(oldEndVnode ==null|| oldch[oldEndIdx]==undefined){
    oldEndVnode = oldch[--oldEndIdx];//判断  新前节点如果是空的  则向后移动一个节点}elseif(newStartVnode ==null|| newCh[newStartIdx]==undefined){
    newStartVnode = newCh[++newStartIdx];//然后判断  新后节点是空的 向前移动一个节点}elseif(newEndVnode ==null|| newCh[newEndIdx]==undefined){
    newEndVnode = newCh[--newEndIdx];}

注意 就和之前的if连在一起 如下图
在这里插入图片描述
如果新前 新后 旧前 旧后取不到值 就做一下处理 向前 或向后处理一个节点 保证这个节点是存在的

然后我们在我们刚写的这个

const idxInold = keyMap[newStartVnode.key];

下面 编写代码如下

//判断 如果idxInold是undefined  表示新前是一个全新的节点if(idxInold ==undefined){}else{// 否则表示   旧节点中也有这个节点 需要精细化和移动处理//先将要处理的老节点存出来const elmToMove = oldch[idxInold];//通过patchVNode对新老节点做精细化比较处理patchVNode(newStartVnode,elmToMove);//然后在旧节点的集合中将这一项设置为undefined  避免在下面被删除旧节点干掉
    oldch[idxInold]=undefined;//将处理好的节点  移动到 旧前节点的前面
    parentElm.insertBefore(elmToMove.elm, oldStartVnode.elm);}//将新前节点后移
newStartVnode = newCh[++newStartIdx];

这里 我们判断 拿到的idxInold 是不是undefined 就是判断 当前新前节点在旧节点的子节点中是否存在
我们这里 直接先写else 就是 存在 他不为undefined

那么 我们先用elmToMove 记录下旧的这个节点的内容
然后 用patchVNode对他们做精细化比较赋值处理

然后将原本旧节点的这个 赋值为undefined 然后 通过insertBefore 将节点移动到当前旧前

然后 我们下面这个旧节点删除的处理要优化下
在这里插入图片描述
简单说 判断一下 确认 oldch[i] 是存在的再继续往下走

然后 我们此时运行项目
在这里插入图片描述
点击 更改dom
在这里插入图片描述
可以看到 我们 key为c 值为 QQQ的节点就上来了

梳理一下逻辑 首先 第一次
新前新后都是 c
旧前是 a 旧后是 d

此时 四个值都有 所以最前面的几个条件达不到 然后 新前旧前 新后旧后 旧前新后这些都不一样
所以直接走进了最后的else
然后 新前在旧子节点中匹配出了c节点 然后 通过patchVNode做了精细化比较 在将原来旧节点的这个c节点赋值为了undefined
然后 通过insertBefore 将新前(处理了精细化比较的c节点) 移动到目前旧前节点 a 前面
然后 将新前节点 向后推1
因为 新前节点 加一之后就等于1了 而新后节点是接的新节点的子节点长度-1 新节点只有一个子节点
那么 新后就是0 所以 新前大于了新后 循环结束 走人后面两个判断
走进旧节点上传 就将多余部分干掉了
所以 我才叫大家加上那个判断 因为你赋值为undefined之后 他处理完 这个节点在删除循环中是会报错的 要判断 确定有才做删除操作

然后 我们将 src下的index.js代码改成这样

import h from"./snabbdom/h";import patch from"./snabbdom/patch";const container = document.getElementById("container");const vnode =h("section",{},[h("p",{key:"a"},"a"),h("p",{key:"b"},"b"),h("p",{key:"c"},"c"),h("p",{key:"d"},"d")]);patch( container, vnode)const btn = document.getElementById("btn");const vnode1 =h("section",{},[h("p",{key:"QQQ"},"QQQ")]);

btn.onclick=function(){patch( vnode, vnode1)}

然后 我们再运行项目
在这里插入图片描述
然后 我们点更改dom
这样就废了
在这里插入图片描述
啥都没了 因为我们并没有写这个新增节点的处理

我们在 if (idxInold == undefined) {
下面加入

//通过 createElement  将newStartVnode新前节点变成孤儿节点  然后插入在 oldStartVnode旧前节点前面
parentElm.insertBefore(createElement(newStartVnode), oldStartVnode.elm)

然后 我们运行项目

在这里插入图片描述
然后点击更改dom
在这里插入图片描述
我们的更新就成功了


本文转载自: https://blog.csdn.net/weixin_45966674/article/details/131033452
版权归原作者 -耿瑞- 所有, 如有侵权,请联系我们删除。

“vue diff算法与虚拟dom知识整理(15) 终结篇,收尾新前到旧前全部不匹配情况”的评论:

还没有评论