1. 通过JavaScript来构建虚拟的DOM树结构,并将其呈现到页面中;

2. 当数据改变,引起DOM树结构发生改变,从而生成一颗新的虚拟DOM树,将其与之前的DOM对比,将变化部分应用到真实的DOM树中,即页面中。

为什么要使用vitual dom?(转自:https://www.jianshu.com/p/616999666920)

当你用传统的源生api或jQuery去操作DOM时,浏览器会从构建DOM树开始从头到尾执行一遍流程。比如当你在一次操作时,需要更新10个DOM节点,理想状态是一次性构建完DOM树,再执行后续操作。但浏览器没这么智能,收到第一个更新DOM请求后,并不知道后续还有9次更新操作,因此会马上执行流程,最终执行10次流程。
操作DOM的代价仍旧是昂贵的,频繁操作还是会出现页面卡顿,影响用户的体验。
虚拟DOM就是为了解决这个浏览器性能问题而被设计出来的。例如前面的例子,假如一次操作中有10次更新DOM的动作,虚拟DOM不会立即执行DOM,而是将这10次更新的diff内容保存到本地的一个js对象中,最终将这个js对象一次性patch到DOM树上,通知浏览器去执行绘制工作,这样可以避免大量的无谓的计算量。

一、构建虚拟DOM

虚拟DOM,其实就是用JavaScript对象来构建DOM树,

通过JavaScript,我们可以很容易构建它,如下:

var elem = Element({tagName: 'ul',props: {'class': 'list'},children: [Element({tagName: 'li', children: ['item1']}),Element({tagName: 'li', children: ['item2']})]});

// Element构造函数function Element({tagName, props, children}){if(!(this instanceof Element)){return new Element({tagName, props, children})}this.tagName = tagName;this.props = props || {};this.children = children || [];
}

通过Element我们可以任意地构建虚拟DOM树了。但是有个问题,虚拟的终归是虚拟的,我们得将其呈现到页面中。

怎么呈现呢?

从上面得知,这是一颗树嘛,那我们就通过遍历,逐个节点地创建真实DOM节点:

  1. createElement;

  2. createTextNode.

怎么遍历呢?

因为这是一颗树嘛,对于树形结构无外乎两种遍历:

  1. 深度优先遍历(DFS)

  2. 广度优先遍历(BFS)

下面我们就来回顾下《数据结构》中,这两种遍历的思想:

1. DFS利用栈来遍历数据

2. BFS利用队列来遍历数据

(为了将孩子节点append到父节点中,采用DFS)

Element.prototype.render = function(){var el = document.createElement(this.tagName),props = this.props,propName,propValue;for(propName in props){propValue = props[propName];el.setAttribute(propName, propValue);}this.children.forEach(function(child){var childEl = null;if(child instanceof Element){childEl = child.render();}else{childEl = document.createTextNode(child);}el.appendChild(childEl);});return el;
};

此时,我们就可以轻松地将虚拟DOM呈现到指定真实DOM中。假设,我们将上诉ul虚拟DOM呈现到页面body中,如下:

var elem = Element({tagName: 'ul',props: {'class': 'list'},children: [Element({tagName: 'li', children: ['item1']}),Element({tagName: 'li', children: ['item2']})]});
document.querySelector('body').appendChild(elem.render());

二、处理DOM更新

在前一小结,我们成功地实现了虚拟DOM,并将其转化为真实DOM,呈现在页面中。

接下来,我们就处理当DOM更新时,怎样通过新旧虚拟DOM对比,然后将变化部分更新到真实DOM中的问题。

DOM更新,无外乎四种情况,如下:

  1. 新增节点;

  2. 删除节点;

  3. 替换节点;

  4. 父节点相同,对比子节点.

毫无疑问,遍历DOM树仍然采用DFS遍历。

因为我们要将变化的节点更新到真实DOM中,所以还得传入真实的DOM根节点,并且真实的DOM节点与虚拟的DOM节点,树形结构一致,故通过标记可以记录节点变化位置,如下:

实现函数如下:

function updateElement($root, newElem, oldElem, index = 0) {if (!oldElem){$root.appendChild(newElem.render());} else if (!newElem) { $root.removeChild($root.childNodes[index]); } else if (changed(newElem, oldElem)) { if (typeof newElem === 'string') { $root.childNodes[index].textContent = newElem; } else { $root.replaceChild(newElem.render(), $root.childNodes[index]); } } else if (newElem.tagName) { let newLen = newElem.children.length; let oldLen = oldElem.children.length; for (let i = 0; i < newLen || i < oldLen; i++) { updateElement($root.childNodes[index], newElem.children[i], oldElem.children[i], i) } } }

其中的changed方法,简单实现如下:

function changed(elem1, elem2) {return (typeof elem1 !== typeof elem2) || (typeof elem1 === 'string' && elem1 !== elem2) || (elem1.type !== elem2.type); }

好了,一个简单的虚拟DOM就实现了。

三、效果展示

通过JS构建一颗虚拟DOM(如上诉ul),并将其呈现到页面中,然后替换其子节点,动态更新到真实DOM中,如下:

<body><button id="refresh">refresh element</button><div id="root"></div><script src="./virtualDom.js"></script><script>var elem = Element({tagName: 'ul',props: {'class': 'list'},children: [Element({tagName: 'li', children: ['item1']}),Element({tagName: 'li', children: ['item2']})]});var newElem =  Element({tagName: 'ul',props: {'class': 'list'},children: [Element({tagName: 'li', children: ['item1']}),Element({tagName: 'li', children: ['hahaha']})]});var $root = document.querySelector('#root');var $refresh = document.querySelector('#refresh');updateElement($root, elem);$refresh.addEventListener('click', () => {updateElement($root, newElem, elem);});</script></body>

转载于:https://www.cnblogs.com/ceceliahappycoding/p/10769011.html

vitual dom实现(转)相关推荐

  1. vue:虚拟dom的实现

    Vitual DOM是一种虚拟dom技术,本质上是基于javascript实现的,相对于dom对象,javascript对象更简单,处理速度更快,dom树的结构,属性信息都可以很容易的用javascr ...

  2. 面试中的网红虚拟DOM,你知多少呢?深入解读diff算法

    深入浅出虚拟DOM和diff算法 一.虚拟DOM(Vitual DOM) 1.虚拟DOM(Vitual DOM)和diff的关系 2.真实DOM的渲染过程 3.虚拟DOM是什么? 4.解决方案 - v ...

  3. 【javascript】关于react的Virtual DOM 与数据更新

    一,关于Virtual DOM 真实的页面对应一个DOM树,传统的交互就是 DOM树 触发事件 -> 然后业务处理 ->操纵dom树.操作DOM性能消耗大,且繁琐,维护成本高. 于是 Re ...

  4. 前端基础知识点-每天一个基本知识点(100+个前端小知识,你是否都知道?)

    文章目录 前言 第一回合 一.知识点:cookie(21/09/06) 二.知识点:节流和防抖(21/09/07) 三.知识点:var和let以及const(21/09/08) 四:知识点:深拷贝和浅 ...

  5. 浅谈React和VDom关系

    组件化 组件的封装 组件的复用 组件的封装 视图 数据 视图和数据之间的变化逻辑 import React, {Component} from 'react';export default class ...

  6. 太棒了!2018-2020前端经典面试题整理合集,还附带大厂面试题分享!

    2018到2020年,3年经典面试题整理合集,话不多说,直接上题. 1,盒模型 1.1,ie 盒模型算上 border.padding 及自身(不算 margin),标准的只算上自身窗体的大小 css ...

  7. React Fiber

    React Fiber是对核心算法的一次重新实现 React Fiber的方式 破解JavaScript中同步操作时间过长的方法其实很简单--分片. 把一个耗时长的任务分成很多小片,每一个小片的运行时 ...

  8. mnv*框架开发时代

    2019独角兽企业重金招聘Python工程师标准>>> 原文出处:极限前端   当下前端开发框架设计显然已经在mvvm方式上又发展了一步,virtual dom 提出不久,使用前端代 ...

  9. 【JavaScript总结】JavaScript语法基础:DOM

    ->DOM的理解:文档对应dom树 ->有了DOM能做什么:DOM的操作 html文档做为DOM树模型,DOM树的节点就是对象.对象会触发事件来执行一些事件代码. C#中的事件是一个委托变 ...

最新文章

  1. [转载]分享WCF聊天程序--WCFChat
  2. 太赞了,Intellij IDEA 竟然把 Java8 的数据流问题这么完美的解决掉了!
  3. vSphere虚拟化之ESXi安装及部署
  4. mongodb java driver 聚合框架
  5. 如何处理Docker的错误消息request canceled:Docker代理问题
  6. spring 注释_Spring@主要注释
  7. 七牛云php20m文件上传不了,七牛云存储 - 用php上传图片,我在本地测试,用php 接口,不成功...
  8. bfs+优先队列(hdu1242)
  9. 3G时代 一起走近无线运维的3A标准——柳州市劳动和社会保障局
  10. centos下redis安全相关
  11. SQL2008--SQL语句-存储过程-触发器-事务处理-基本语法-函数
  12. SignalTap II里面Power-Up Trigger的使用
  13. spark on yarn 完全分部署_听说你熟悉Flink-On-Yarn的部署模式?
  14. 一文带你浏览Graph Transformers
  15. 来了!Python 官方发布了整套的中文PDF 文档(共27本)
  16. 美团在O2O场景下的广告营销
  17. 微信内置浏览器缓存如何避免,如何防止微信缓存
  18. Java编程公鸡5元一只,母鸡3元一只,小鸡1元三只,问100元怎样可以买100鸡?
  19. 工具分享-PDF 补丁丁
  20. 多开分身苹果版_苹果手机如何同时登陆两个微信 iPhone微信多开教程

热门文章

  1. dataframe数组做元素_数组 array 矩阵 list 数据框 dataframe
  2. python color属性_Python turtle.color方法代码示例
  3. 你生孩子的时候有什么神奇的经历吗?
  4. 镇定的反义词是什么,标准答案是
  5. 实体店想多赚钱就要学会互联网思维
  6. 把照片存QQ相册会越来越模糊,你们会把照片存在哪里?
  7. The developer claims that Bpytop
  8. 1.2.3 TCP/PI参考模型(应用层、传输层、网际层、网络接口层)、五层参考模型(应用层、传输层、网络层、数据链路层、物理层)、OSI与TCP/IP参考模型比较(转载)
  9. 游标sql server_SQL Server游标属性
  10. power bi dax_M语言和Power BI中的DAX之间的差异