vue diff算法与虚拟dom知识整理(6) 感受diff算法 (不要神话虚拟dom更不要做完美主义)

这篇具有很好参考价值的文章主要介绍了vue diff算法与虚拟dom知识整理(6) 感受diff算法 (不要神话虚拟dom更不要做完美主义)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

我们还是打开之前的案例
然后 将src下的index.js代码修改如下

import {
    init,
    classModule,
    propsModule,
    styleModule,
    eventListenersModule,
    h,
  } from "snabbdom";

  //创建patch函数
  const patch = init([
    classModule,
    propsModule,
    styleModule,
    eventListenersModule
  ]);
 
  //创建虚拟节点
  var vonm = h("ul",{},[
    h("li",{},"a"),
    h("li",{},"b"),
    h("li",{},"c")
  ]);

  //让虚拟节点上树
  const container = document.getElementById('container');
  patch(container,vonm);

首先 我们写入节点的方法叫 patch
我们来查一下这个单纯的意思
vue diff算法与虚拟dom知识整理(6) 感受diff算法 (不要神话虚拟dom更不要做完美主义)
其实 他不是一个暴力装卸的方法 而是 修补的一个概念

因为 我们需要一个触发事件的工具 所以 我们在www文件夹下的index.html中加一个id为btn的按钮
参考代码如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button id = "btn">更改dom</button>
    <div id="container"></div>
    <script src="/xuni/bundle.js"></script>
</body>
</html>

然后我们改写 src下的index.js代码如下

import {
    init,
    classModule,
    propsModule,
    styleModule,
    eventListenersModule,
    h,
  } from "snabbdom";

  //创建patch函数
  const patch = init([
    classModule,
    propsModule,
    styleModule,
    eventListenersModule
  ]);
 
  //创建虚拟节点
  var vonm = h("ul",{},[
    h("li",{},"a"),
    h("li",{},"b"),
    h("li",{},"c")
  ]);

  //让虚拟节点上树
  const container = document.getElementById('container');
  patch(container,vonm);

  //定义第二个虚拟dom节点
  var vonm2 = h("ul",{},[
    h("li",{},"a"),
    h("li",{},"b"),
    h("li",{},"c"),
    h("li",{},"d")
  ]);

  //获取btn节点
  const btn = document.getElementById('btn');

  //监听用户点击按钮
  btn.onclick = function() {
    //属性替换
    patch(vonm,vonm2);
  }

这里 我们获取了 btn 按钮 给他定义了一个点击事件 点击他 做了一个patch操作
这就是patch的神奇之后 不需要再传节点了 直接传两个需要比较的变量即可
然后我们运行项目
vue diff算法与虚拟dom知识整理(6) 感受diff算法 (不要神话虚拟dom更不要做完美主义)
我们可以看到 现在运行的是 vonm的 abc
我们点击上面按钮
vue diff算法与虚拟dom知识整理(6) 感受diff算法 (不要神话虚拟dom更不要做完美主义)
可以看到 这里就变成了 vonm2的 abcd

这里 我们要清除 不是直接暴力的 把vonm2又渲染上去了 而是对比两者差异 哦 发现只有一个 d不一样 就追加了一个d上去
这是patch的意义

那么 怎么证明呢
我们刷新界面
然后在控制台修改节点的文本
vue diff算法与虚拟dom知识整理(6) 感受diff算法 (不要神话虚拟dom更不要做完美主义)
我们直接在控制台上 通过节点编辑 将a 改成丑八怪
vue diff算法与虚拟dom知识整理(6) 感受diff算法 (不要神话虚拟dom更不要做完美主义)
然后 我们再次点击按钮 如果他是重新渲染 那么 这个a是不是该变回去啊?
那我们点击按钮
vue diff算法与虚拟dom知识整理(6) 感受diff算法 (不要神话虚拟dom更不要做完美主义)
很显然 d出来了 但a没有复原 因为在程序中 他们确认过 第一个节点是一样的 我们在控制台改了内容js并不知道
所以 这就是 diff的好处 最小量更新

但你如果以为他是在最后面插入 那么我们就要思考另一个问题
它怎么实现前面或中间的更改呢?

我们将 src 下的 index.js代码更改如下

import {
    init,
    classModule,
    propsModule,
    styleModule,
    eventListenersModule,
    h,
  } from "snabbdom";

  //创建patch函数
  const patch = init([
    classModule,
    propsModule,
    styleModule,
    eventListenersModule
  ]);
 
  //创建虚拟节点
  var vonm = h("ul",{},[
    h("li",{},"a"),
    h("li",{},"b"),
    h("li",{},"c")
  ]);

  //让虚拟节点上树
  const container = document.getElementById('container');
  patch(container,vonm);

  //定义第二个虚拟dom节点
  var vonm2 = h("ul",{},[
    h("li",{},"d"),
    h("li",{},"a"),
    h("li",{},"b"),
    h("li",{},"c")
  ]);

  //获取btn节点
  const btn = document.getElementById('btn');

  //监听用户点击按钮
  btn.onclick = function() {
    //属性替换
    patch(vonm,vonm2);
  }

这次 我们把D放到最前面
我们运行之后 我们在上面 将 a 改成 丑八怪 b 改成 搭好
vue diff算法与虚拟dom知识整理(6) 感受diff算法 (不要神话虚拟dom更不要做完美主义)我们点击按钮
vue diff算法与虚拟dom知识整理(6) 感受diff算法 (不要神话虚拟dom更不要做完美主义)
会发现 它既然变成了 dabc
vue diff算法与虚拟dom知识整理(6) 感受diff算法 (不要神话虚拟dom更不要做完美主义)
其实 也不是重新渲染 但也差的不多 他把 a 变成了 d , b变成了 a ,c变成了 b 在最后面 又追加了一个c

这里证明的 是因为 前面的也被改了 丑八怪和搭好就被覆盖了
可能 这时 有小伙伴就会想 这也不是很智能啊
不是哦 是我们没有给他加key

我们将 src下的index.js入口文件修改如下

import {
    init,
    classModule,
    propsModule,
    styleModule,
    eventListenersModule,
    h,
  } from "snabbdom";

  //创建patch函数
  const patch = init([
    classModule,
    propsModule,
    styleModule,
    eventListenersModule
  ]);
 
  //创建虚拟节点
  var vonm = h("ul",{},[
    h("li",{key: "a"},"a"),
    h("li",{key: "b"},"b"),
    h("li",{key: "c"},"c")
  ]);

  //让虚拟节点上树
  const container = document.getElementById('container');
  patch(container,vonm);

  //定义第二个虚拟dom节点
  var vonm2 = h("ul",{},[
    h("li",{key: "d"},"d"),
    h("li",{key: "a"},"a"),
    h("li",{key: "b"},"b"),
    h("li",{key: "c"},"c")
  ]);

  //获取btn节点
  const btn = document.getElementById('btn');

  //监听用户点击按钮
  btn.onclick = function() {
    //属性替换
    patch(vonm,vonm2);
  }

这次 我们给这些虚拟节点加上了 key属性 然后我们再次运行项目
vue diff算法与虚拟dom知识整理(6) 感受diff算法 (不要神话虚拟dom更不要做完美主义)
我们还是像之前一样 在控制台改一下a b 节点的文本
然后我们点击按钮 改变一下dom
vue diff算法与虚拟dom知识整理(6) 感受diff算法 (不要神话虚拟dom更不要做完美主义)
可以很明显的看到 这次他就没动 a b 节点了 因为我们控制台改的内容并没有被覆盖 说明 这两个节点它没动
只是在最上面加了一个d 这就是key对虚拟dom的作用

key是节点的唯一标识 他能帮助我们完成真正意义上的最小量更新

然后 我们来看第二个东西
将 src下的 index.js代码修改如下

import {
    init,
    classModule,
    propsModule,
    styleModule,
    eventListenersModule,
    h,
  } from "snabbdom";

  //创建patch函数
  const patch = init([
    classModule,
    propsModule,
    styleModule,
    eventListenersModule
  ]);
 
  //创建虚拟节点
  var vonm = h("ul",{},[
    h("li",{key: "a"},"a"),
    h("li",{key: "b"},"b"),
    h("li",{key: "c"},"c")
  ]);

  //让虚拟节点上树
  const container = document.getElementById('container');
  patch(container,vonm);

  //定义第二个虚拟dom节点
  var vonm2 = h("ol",{},[
    h("li",{key: "a"},"a"),
    h("li",{key: "b"},"b"),
    h("li",{key: "c"},"c")
  ]);

  //获取btn节点
  const btn = document.getElementById('btn');

  //监听用户点击按钮
  btn.onclick = function() {
    //属性替换
    patch(vonm,vonm2);
  }

这次 我们不改里面的li标签了 我们直接将他们的父节点 重 ul无序列表改为 ol 有序列表

那最小量更新就是 改一下父标签 对吗?
那么 我们来试一下是不是这样

我们运行项目 就还是在控制台把文本改了
vue diff算法与虚拟dom知识整理(6) 感受diff算法 (不要神话虚拟dom更不要做完美主义)
然后 我们点击更新dom
vue diff算法与虚拟dom知识整理(6) 感受diff算法 (不要神话虚拟dom更不要做完美主义)
可以看到 确实是边有序列表了 但 有没有发现 子节点也被更新了啊?

简单说 只有是同一个节点 才进行精细化 比较 简单说 他在接到这个 ul改ol时 已经视为 两者不是同一个节点了 那就直接暴力拆掉 然后重新装上去
等于 把整个全换了
当 选择器(就是标签类型) 或者 key不同时 他就会视为不是同一个节点
那可能有人会说 那这最小化更新不厉害啊?
但你们仔细想一下 在正式开发中 你们会遇到需要改父节点标签类型的逻辑吗? 所以 这是无伤大雅的 不要做完美主义

所以 这里写的所有内容 都是在vue中会发生的 父节点选择器改变时 子节点是不精细化校验更新的 他直接就旧的拆掉 新的上树 简单说 整个从内到外全换新
面试官面前 这些都可以聊

还有一个经常在文章和公众号文档中出现的 一个概念 只有同层才进行比较 但说的都很笼统 我们来好好研究一下

比如 我们这里 将src/index.js代码修改如下

import {
    init,
    classModule,
    propsModule,
    styleModule,
    eventListenersModule,
    h,
  } from "snabbdom";

  //创建patch函数
  const patch = init([
    classModule,
    propsModule,
    styleModule,
    eventListenersModule
  ]);
 
  //创建虚拟节点
  var vonm = h("div",{},[
    h("p",{key: "a"},"a"),
    h("p",{key: "b"},"b"),
    h("p",{key: "c"},"c")
  ]);

  //让虚拟节点上树
  const container = document.getElementById('container');
  patch(container,vonm);

  //定义第二个虚拟dom节点
  var vonm2 = h("div",{},[
    h("p",{key: "a"},"a"),
    h("p",{key: "b"},"b"),
    h("p",{key: "c"},"c")
  ]);

  //获取btn节点
  const btn = document.getElementById('btn');

  //监听用户点击按钮
  btn.onclick = function() {
    //属性替换
    patch(vonm,vonm2);
  }

我们将他从div下三个p 改为一模一样的内容 然后我们点击按钮更新
vue diff算法与虚拟dom知识整理(6) 感受diff算法 (不要神话虚拟dom更不要做完美主义)
会发现控制台没什么反应 说明 他判断 都是一样的 就不更新了
但我们将 src/index 下的代码更改成这样

import {
    init,
    classModule,
    propsModule,
    styleModule,
    eventListenersModule,
    h,
  } from "snabbdom";

  //创建patch函数
  const patch = init([
    classModule,
    propsModule,
    styleModule,
    eventListenersModule
  ]);
 
  //创建虚拟节点
  var vonm = h("div",{},[
    h("p",{key: "a"},"a"),
    h("p",{key: "b"},"b"),
    h("p",{key: "c"},"c")
  ]);

  //让虚拟节点上树
  const container = document.getElementById('container');
  patch(container,vonm);

  //定义第二个虚拟dom节点
  var vonm2 = h("div",{},
    h("div",{},[
      h("p",{key: "a"},"a"),
      h("p",{key: "b"},"b"),
      h("p",{key: "c"},"c")
    ])
  );

  //获取btn节点
  const btn = document.getElementById('btn');

  //监听用户点击按钮
  btn.onclick = function() {
    //属性替换
    patch(vonm,vonm2);
  }

我们在更改后端内容内多加一层div
这里 我们刚运行项目 这里 节点结构明显是div下三个p
vue diff算法与虚拟dom知识整理(6) 感受diff算法 (不要神话虚拟dom更不要做完美主义)
然后点击 他就变成了 div下一个div 下面三个p
vue diff算法与虚拟dom知识整理(6) 感受diff算法 (不要神话虚拟dom更不要做完美主义)
那么 我们思考 他是否是最小量更新?
最小量更新就是 不要动三个p 在外面多套个div
可以先告诉大家 这个想法太美好了 但现实比较残酷
我们还是 文本测试法

我们在控制台上更改三个p的文本
vue diff算法与虚拟dom知识整理(6) 感受diff算法 (不要神话虚拟dom更不要做完美主义)
然后点击按钮
vue diff算法与虚拟dom知识整理(6) 感受diff算法 (不要神话虚拟dom更不要做完美主义)
让人失望的是 它全部覆盖了

说明的很简单 他把原本的三个p干掉了 然后重新插入了 div里面重写写入了三个p
意思就是 他只有同层会比较 就算你没有换标签 只要 他们层级不一样 也不会再比较了 也就没有精细化比较了

暴力拆掉旧的 强行插入新的
这个操作 我觉得会比上面那个换父标签类型可能更现实一点 但也基本遇不到 所以 没必要做完美主义 人家做开源还懒得做兼容呢 没什么人弄的东西 没必要强求

但同层 就算乱序 也可以最小量比较更新
我们将 src/index代码更改如下

import {
    init,
    classModule,
    propsModule,
    styleModule,
    eventListenersModule,
    h,
  } from "snabbdom";

  //创建patch函数
  const patch = init([
    classModule,
    propsModule,
    styleModule,
    eventListenersModule
  ]);
 
  //创建虚拟节点
  var vonm = h("div",{},[
    h("p",{key: "a"},"a"),
    h("p",{key: "b"},"b"),
    h("p",{key: "c"},"c")
  ]);

  //让虚拟节点上树
  const container = document.getElementById('container');
  patch(container,vonm);

  //定义第二个虚拟dom节点
  var vonm2 = h("div",{},[
      h("p",{key: "b"},"b"),
      h("p",{key: "c"},"c"),
      h("p",{key: "a"},"a")
    ]
  );

  //获取btn节点
  const btn = document.getElementById('btn');

  //监听用户点击按钮
  btn.onclick = function() {
    //属性替换
    patch(vonm,vonm2);
  }

我们这里 前后节点没有结构变化 只是改变了一下 abc的顺序
然后我们运行项目
vue diff算法与虚拟dom知识整理(6) 感受diff算法 (不要神话虚拟dom更不要做完美主义)
还是在控制台更改一下内容
然后点击按钮更新dom
vue diff算法与虚拟dom知识整理(6) 感受diff算法 (不要神话虚拟dom更不要做完美主义)
可以看到 并没有强行去拆 而是做了最小量的比较更新 只是换了顺序 我们更改的文本还在 说明节点没有换
这就是patch内部算法的强大
那么 我之后也会出问题讲一下 patch 并带大家手写一个自己的 patch
好啦 那就到这啦文章来源地址https://www.toymoban.com/news/detail-439975.html

到了这里,关于vue diff算法与虚拟dom知识整理(6) 感受diff算法 (不要神话虚拟dom更不要做完美主义)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • Vue 虚拟DOM

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

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

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

    2024年02月09日
    浏览(29)
  • vue中的虚拟dom

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

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

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

    2024年01月21日
    浏览(27)
  • 【vue】diff 算法详解

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

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

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

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

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

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

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

    2023年04月25日
    浏览(26)
  • vue diff 双端比较算法

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

    2024年02月14日
    浏览(33)
  • vue源码阅读之什么是虚拟dom

    前面简单说过数据响应式原理,大体是个怎么流程,数据发生变化,我们界面如何更新。 依赖收集收集的是watcher,然后当数据发生变化的时候dep通知watcher,然后watcher负责updateComponent。 那么更新组件过程中,有个很重要的概念叫做虚拟dom。 所谓虚拟dom,就是用一个js对象来

    2024年02月13日
    浏览(35)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包