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

这篇具有很好参考价值的文章主要介绍了vue diff算法与虚拟dom知识整理(15) 终结篇,收尾新前到旧前全部不匹配情况。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

我们在 updateChildren.js
在while中
vue diff算法与虚拟dom知识整理(15) 终结篇,收尾新前到旧前全部不匹配情况
的if最后加个 else
vue diff算法与虚拟dom知识整理(15) 终结篇,收尾新前到旧前全部不匹配情况
当他们都没哟匹配到的情况

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

let keyMap = null;

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

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

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

vue diff算法与虚拟dom知识整理(15) 终结篇,收尾新前到旧前全部不匹配情况
简单说 我们判断 如果所有条件都不匹配 就先看看 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 是旧节点压根没有的

然后我们运行项目
vue diff算法与虚拟dom知识整理(15) 终结篇,收尾新前到旧前全部不匹配情况
然后点击 更改dom
vue diff算法与虚拟dom知识整理(15) 终结篇,收尾新前到旧前全部不匹配情况
可以看到 内容全没了 控制台也成功输出了旧节点的key和下标

这里 没了是因为 我们上文写的 while下面那个旧节点删除的逻辑将他们都处理掉了
vue diff算法与虚拟dom知识整理(15) 终结篇,收尾新前到旧前全部不匹配情况
但现在显然我们要想办法把这个qqq弄上去

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

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

vue diff算法与虚拟dom知识整理(15) 终结篇,收尾新前到旧前全部不匹配情况
因为 新前肯定是我们正在处理的这个节点 我们去匹配一下 keyMap 中的内容
如果有和新前key一样的 就取过来 如果没有 我们取到的就是个undefined
我们运行项目 然后点击 更改dom 查看控制台
vue diff算法与虚拟dom知识整理(15) 终结篇,收尾新前到旧前全部不匹配情况
很显然 他输出了undefined
因为旧节点的子节点中 并没有key为QQQ的子节点
我们可以改一些src下的index.js
将 vnode1 改为

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

然后我们运行项目 点击更改dom
vue diff算法与虚拟dom知识整理(15) 终结篇,收尾新前到旧前全部不匹配情况
可以看到 这次我们就取到了

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

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

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

注意 就和之前的if连在一起 如下图
vue diff算法与虚拟dom知识整理(15) 终结篇,收尾新前到旧前全部不匹配情况
如果新前 新后 旧前 旧后取不到值 就做一下处理 向前 或向后处理一个节点 保证这个节点是存在的

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

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 将节点移动到当前旧前

然后 我们下面这个旧节点删除的处理要优化下
vue diff算法与虚拟dom知识整理(15) 终结篇,收尾新前到旧前全部不匹配情况
简单说 判断一下 确认 oldch[i] 是存在的再继续往下走

然后 我们此时运行项目
vue diff算法与虚拟dom知识整理(15) 终结篇,收尾新前到旧前全部不匹配情况
点击 更改dom
vue diff算法与虚拟dom知识整理(15) 终结篇,收尾新前到旧前全部不匹配情况
可以看到 我们 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)
}

然后 我们再运行项目
vue diff算法与虚拟dom知识整理(15) 终结篇,收尾新前到旧前全部不匹配情况
然后 我们点更改dom
这样就废了
vue diff算法与虚拟dom知识整理(15) 终结篇,收尾新前到旧前全部不匹配情况
啥都没了 因为我们并没有写这个新增节点的处理

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

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

然后 我们运行项目

vue diff算法与虚拟dom知识整理(15) 终结篇,收尾新前到旧前全部不匹配情况
然后点击更改dom
vue diff算法与虚拟dom知识整理(15) 终结篇,收尾新前到旧前全部不匹配情况
我们的更新就成功了文章来源地址https://www.toymoban.com/news/detail-476836.html

到了这里,关于vue diff算法与虚拟dom知识整理(15) 终结篇,收尾新前到旧前全部不匹配情况的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Vue 虚拟DOM

    在当今Web开发领域中,构建交互性强、可复用且易于维护的用户界面是至关重要的。而Vue.js作为一款现代化且流行的JavaScript框架,正是为了满足这些需求而诞生。它采用了MVVM架构模式,并通过数据驱动和组件化的方式,使我们能够更轻松地构建出优雅而高效的Web应用程序。

    2024年02月22日
    浏览(39)
  • vue的虚拟DOM

    虚拟DOM就是一个JS对象,用它来描述真实DOM demo1: 多次执行dom操作 demo2: 只执行一次dom操作 比较运行时间:得到结论 越多的真实dom操作,越损耗性能 操作数据要大大的减少性能损耗,提高渲染效率 第一种更新DOM的方案 第二种更新DOM的方案 第三种使用虚拟DOM的方案 key是虚拟

    2024年02月09日
    浏览(40)
  • Vue面试之虚拟DOM

        最近在整理一些前端面试中经常被问到的问题,分为vue相关、react相关、js相关、react相关等等专题,可持续关注后续内容,会不断进行整理~     虚拟 DOM 是用 JavaScript 对象来模拟实际 DOM 结构的一种抽象表示。它描述了组件的结构、属性和事件等信息,但与实际的页面

    2024年01月21日
    浏览(39)
  • vue中的虚拟dom

    DOM操作是Web开发中非常昂贵和低效的操作,尤其是在用户界面频繁更新的情况下。此时,在每次数据更新时重新渲染整个DOM树会导致应用程序性能下降。 为了解决这个问题,虚拟DOM被引入到前端开发中。虚拟DOM把整个DOM树抽象成一个JS对象,这样开发者就可以直接操作JS对象

    2024年02月09日
    浏览(41)
  • 【vue】diff 算法详解

    diff算法是一种通过 同层的树节点 进行比较的高效算法         diff算法的目的就是找出新旧不同虚拟DOM之间的差异,使最小化的更新视图,所以 diff 算法本质上就是比较两个js对象的差异 特点         1. 比较只会在同层级进行,不会跨层级比较         2. 在diff比较的构成

    2024年02月02日
    浏览(34)
  • vue 虚拟DOM的优劣说明

    Vue.js 使用虚拟 DOM(Virtual DOM)来提高应用的性能。虚拟 DOM 是一种编程概念,它通过在内存中创建一个与真实 DOM 结构相同的虚拟结构,来优化对真实 DOM 的操作。下面是对 Vue.js 中虚拟 DOM 的优劣说明和代码示例。 优势: 性能优化 :Vue.js 通过虚拟 DOM 减少了直接操作真实

    2024年01月25日
    浏览(33)
  • 什么是 VUE的虚拟 DOM?

    虚拟 DOM(Virtual DOM)是一个在内存中以 JavaScript 对象的形式表示的轻量级的 DOM 抽象层。当页面的状态发生改变时,Vue 3 会生成新的虚拟 DOM,并通过与上一次生成的虚拟 DOM 进行比较,找出实际发生了变化的部分。然后,Vue 3 仅对这些变化的部分进行实际 DOM 操作,而不是对整

    2024年02月14日
    浏览(44)
  • vue的diff算法原理

    vue基于虚拟DOM做更新,diff的核心就是比较两个虚拟节点的差异。 vue的diff算法是 平级比较 ,不考虑跨级比较的情况。内部采用 深度递归 + 双指针 的方式进行比较 先比较是否是相同节点 key tag (标识,标签名) 相同节点比较属性,并复用老节点(将老的虚拟dom复用给新的虚拟

    2023年04月25日
    浏览(35)
  • 关于“Python”的核心知识点整理大全15

    目录 ​编辑 7.3.2 删除包含特定值的所有列表元素 pets.py 7.3.3 使用用户输入来填充字典 mountain_poll.py 7.4 小结 第8章 函 数 8.1 定义函数 greeter.py 8.1.1 向函数传递信息 8.1.2 实参和形参 8.2.1 位置实参 2. 位置实参的顺序很重要 8.2.2 实参 往期快速传送门👆(在文章最后):

    2024年02月05日
    浏览(41)
  • vue diff 双端比较算法

    使用四个变量 oldStartIdx、oldEndIdx、newStartIdx 以及 newEndIdx 分别存储旧 children 和新 children 的两个端点的位置索引 除了位置索引之外,还需要拿到四个位置索引所指向的 VNode 使用旧 children 的头一个 VNode 与新 children 的头一个 VNode 比对,即 oldStartVNode 和 newStartVNode 比较对。 使用

    2024年02月14日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包