zoukankan      html  css  js  c++  java
  • 前沿技术解密——VirtualDOM

    作为React的核心技术之一Virtual DOM,一直披着神秘的面纱。

    实际上,Virtual DOM包含:

    1. Javascript DOM模型树(VTree),类似文档节点树(DOM)
    2. DOM模型树转节点树方法(VTree -> DOM)
    3. 两个DOM模型树的差异算法(diff(VTree, VTree) -> PatchObject)
    4. 根据差异操作节点方法(patch(DOMNode, PatchObject) -> DOMNode)

    接下来我们分别探讨这几个部分:

    VTree

    VTree模型非常简单,基本结构如下:

    {
        // tag的名字
        tagName: 'p',
        // 节点包含属性
        properties: {
            style: {
                color: '#fff'
            }
        },
        // 子节点
        children: [],
        // 该节点的唯一表示,后面会讲有啥用
        key: 1
    }
    

    所以我们很容易写一个方法来创建这种树状结构,例如React是这么创建的:

    // 创建一个div
    react.createElement('div', null, [
        // 子节点img
        react.createElement('img', { src: "avatar.png", class: "profile" }),
        // 子节点h3
        react.createElement('h3', null, [[user.firstName, user.lastName].join(' ')])
    ]);
    

    VTree -> DOM

    这方法也不太难,我们实现一个简单的:

    function create(vds, parent) {
      // 首先看看是不是数组,如果不是数组统一成数组
      !Array.isArray(vds) && (vds = [vds]);
      //  如果没有父元素则创建个fragment来当父元素
      parent = parent || document.createDocumentFragment();
      var node;
      // 遍历所有VNode
      vds.forEach(function (vd) {
        // 如果VNode是文字节点
        if (isText(vd)) {
          // 创建文字节点
          node = document.createTextNode(vd.text);
        // 否则是元素
        } else {
          // 创建元素
          node = document.createElement(vd.tag);
        }
        // 将元素塞入父容器
        parent.appendChild(node);
        // 看看有没有子VNode,有孩子则处理孩子VNode
        vd.children && vd.children.length &&
          create(vd.children, node);
    
        // 看看有没有属性,有则处理属性
        vd.properties &&
          setProps({ style: {} }, vd.properties, node);
      });
      return parent;
    }
    

    diff(VTree, VTree) -> PatchObject

    差异算法是Virtual DOM的核心,实际上该差异算法是个取巧算法(当然你不能指望用O(n^3)的复杂度来解决两个树的差异问题吧),不过能解决Web的大部分问题。

    那么React是如何取巧的呢?

    1. 分层对比

    如图,React仅仅对同一层的节点尝试匹配,因为实际上,Web中不太可能把一个Component在不同层中移动。

    1. 基于key来匹配

    还记得之前在VTree中的属性有一个叫key的东东么?这个是一个VNode的唯一识别,用于对两个不同的VTree中的VNode做匹配的。

    这也很好理解,因为我们经常会在Web遇到拥有唯一识别的Component(例如课程卡片、用户卡片等等)的不同排列问题。

    1. 基于自定义元素做优化

    React提供自定义元素,所以匹配更加简单。

    patch(DOMNode, PatchObject) -> DOMNode

    由于diff操作已经找出两个VTree不同的地方,只要根据计算出来的结果,我们就可以对DOM的进行差异渲染。

    扩展阅读

    具体可参考下面两份代码实现:

    1. @Matt-Esch实现的:virtual-dom
    2. 我们自己做的简版实现,用于Mobile页面渲染的:qvd
  • 相关阅读:
    MUI DtPicker 显示自定义日期
    Windows10更新后,远程桌面无法登录服务器 提示远程桌面协议 CredSSP 出现漏洞
    微信Access Token 缓存方法
    在Windows7/8/10上,安装IIS
    启明星系统微信接口配置
    c#使用QQ邮箱的SSL收发邮件
    使用ASP.NET+Jquery DataTables的服务器分页
    总是容易忘记:enum、int、string之间的快速转换
    Chrome浏览器导出pdf时,隐藏链接HREF
    SQL Builder 1.04
  • 原文地址:https://www.cnblogs.com/justany/p/4401118.html
Copyright © 2011-2022 走看看