• 虚拟 DOM 和 diff 算法



    本文重点是什么?

    1. 虚拟 DOM 是什么?
    2. 虚拟 DOM 如何产生?—— h 函数
    3. diff 算法原理?—— diff 函数
    4. 虚拟 DOM 如何通过 diff 变为真正的 DOM 的? —— diff 函数

    虚拟DOM

    简介:

    • 介绍:是一个 JavaScript 对象,用来描述真实的DOM结构。
    • 如下图,有三个属性:
      (1)sel:标签名;(2)data:属性信息;(3)children:子元素对象。

    在这里插入图片描述

    优点:

    区别于真实DOM

    • 无需手动操作 DOM,提高开发效率;
    • 复杂场景下,防止频繁触发重绘,可以提高性能;
    • 虚拟 DOM 实际是 JavaScript 对象,可以进行跨平台操作。

    问题:数据发生改变,试图怎么更新
    当数据改变时,会触发setter,并且通过Dep.notify去通知所有订阅者Watcher(组件),订阅者们就会调用patch方法,给真实DOM打补丁,更新相应的视图。

    diff 函数

    简介:

    计算最小更新 DOM 的方式。

    • 将 DOM 抽象为虚拟 DOM ;
    • 然后通过新旧虚拟 DOM 这两个对象的差异( Diff 算法);
    • 最终只把变化的部分重新渲染,提高渲染效率的过程。

    流程图:
    其中包含 patch 函数、pachVnode 函数、UpdateVnode 函数(未详细介绍)
    请添加图片描述

    案例:

    使用 snabbdom 虚拟 DOM 库 :snabbdom

    /** src/index.js */
    import { init } from 'snabbdom/init'
    import { classModule } from 'snabbdom/modules/class'
    import { propsModule } from 'snabbdom/modules/props'
    import { styleModule } from 'snabbdom/modules/style'
    import { eventListenersModule } from 'snabbdom/modules/eventlisteners'
    import { h } from 'snabbdom/h' // helper function for creating vnodes
    
    // 1、创建出 patch 函数
    const patch = init([
      classModule,
      propsModule,
      styleModule,
      eventListenersModule
    ])
    // 2、使用 h 函数创建虚拟节点
    const vnode1 = h('ul', {}, [
      h('li', {}, 'A'),
      h('li', {}, 'B'),
      h('li', {}, 'C'),
      h('li', {}, 'D')
    ])
    // 3.创建空的容器
    const container = document.getElementById('container')
    // 4.将 DOM 塞入container
    patch(container, vnode1)
    
    const vnode2 = h('ul', {}, [
      h('li', {}, 'A'),
      h('li', {}, 'B'),
      h('li', {}, 'C'),
      h('li', {}, 'D'),
      h('li', {}, 'E')
    ])
    
    // 点击按钮时,将vnode1变为vnode2
    const btn = document.getElementById('btn')
    btn.onclick = function () {
      // 使用最小改变 来达到 新的vnode 覆盖 旧的 vnode2
      patch(vnode1, vnode2)
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    patch 函数

    接收参数存在: element(真实 DOM ) 和 vnode(虚拟 DOM ) 两种类型
    首次插入有两个使用场景:判断 key 和 sel 是相同

    场景1、vnode.key 和 vnode.sel 都相同2、vnode.key 或 vnode.sel 不同
    是否同一个Vnode
    结果更新(调用 pachVnode )创建新的DOM,删除老的DOM

    pachVnode 函数

    虚拟节点 text 和 children 最多只能有一个

    1. 保存(旧的相关联)的 DOM 元素 eml 给新的 Vnode(eml 记录新的 Vnode 插入位置)
    2. 比较新、旧 vnode 的 children 情况
    3个情况1、新 vnode === 旧 vnode(全等)2、新 Vnode :无 text3、新 Vnode :有 text
    不需更新,返回1.新、老 Vnode 都有 children,即调用(updateChildren);
    2.老 Vnode 无 children,即添加 children ;
    3.新的无 children ,即删除 children
    删除 children ,更新新的 text
  • 相关阅读:
    TSINGSEE青犀视频平台EasyCVR如何搭建自然保护区视频监控系统
    Tomcat架构详解
    常见的http请求头以及响应头
    《爆肝整理》保姆级系列教程-玩转Charles抓包神器教程(8)-Charles如何进行断点调试
    Manjaro如果yay使用了aur的清华源,出现报错,解决方法
    shopify二次开发在首页调用最新的博客文章
    什么是遗留代码:有效地处理遗留代码的8个小贴士
    Win10系统中GPU深度学习环境配置记录
    【Redis设计与实现】第一部分 :Redis数据结构和对象 总结
    解决vscode中git push/pull需要输入用户名和密码的问题
  • 原文地址:https://blog.csdn.net/puhuihui/article/details/126072954