前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >前沿技术解密——VirtualDOM

前沿技术解密——VirtualDOM

作者头像
IMWeb前端团队
发布2017-12-29 15:25:43
8350
发布2017-12-29 15:25:43
举报
文章被收录于专栏:IMWeb前端团队IMWeb前端团队

作为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模型非常简单,基本结构如下:

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

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

代码语言:javascript
复制
// 创建一个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

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

代码语言:javascript
复制
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在不同层中移动。

  • 基于key来匹配

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

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

  • 基于自定义元素做优化

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

patch(DOMNode, PatchObject) -> DOMNode

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

扩展阅读

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

  1. @Matt-Esch实现的:virtual-dom
  2. 我们自己做的简版实现,用于Mobile页面渲染的:qvd
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • VTree
  • VTree -> DOM
  • diff(VTree, VTree) -> PatchObject
  • patch(DOMNode, PatchObject) -> DOMNode
  • 扩展阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档