Vue原理--虚拟DOM
为什么需要虚拟DOM?
如果对前端工作进行抽象的话,主要就是维护状态和更新视图,而更新视图和维护状态都需要DOM操作。其实近年来,前端的框架主要发展方向就是解放DOM操作的复杂性。
运行js的速度是很快的,大量的操作DOM就会很慢,时常在更新数据后会重新渲染页面,这样造成在没有改变数据的地方也重新渲染了DOM 节点,这样就造成了很大程度上的资源浪费。
在jQuery出现以前,我们直接操作DOM结构,这种方法复杂度高,兼容性也较差。有了jQuery强大的选择器以及高度封装的API,我们可以更方便的操作DOM,jQuery帮我们处理兼容性问题,同时也使DOM操作变得简单。
但是聪明的程序员不可能满足于此,各种MVVM框架应运而生,有angularJS、avalon、vue.js等,MVVM使用数据双向绑定,使得我们完全不需要操作DOM了,更新了状态,视图会自动更新。更新了视图数据状态也会自动更新,可以说MVVM使得前端的开发效率大幅提升。但是其大量的事件绑定使得其在复杂场景下的执行性能堪忧,有没有一种兼顾开发效率和执行效率的方案呢?由此引入Virtual DOM(虚拟DOM)。
利用在内存中生成与真实DOM与之对应的数据结构,这个在内存中生成的结构称之为虚拟DOM 。
当数据发生变化时,能够智能地计算出重新渲染组件的最小代价并应用到DOM操作上。
Virtual DOM 算法
所谓的 Virtual DOM 算法。包括几个步骤:
1.用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,插到文档当中;
2.当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异;
3.把2所记录的差异应用到步骤1所构建的真正的DOM树上,视图就更新了。
Virtual DOM 本质上就是在 JS 和 DOM 之间做了一个缓存。可以类比 CPU 和硬盘,既然硬盘这么慢,我们就在它们之间加个缓存。
既然 DOM 这么慢,我们就在它们 JS 和 DOM 之间加个缓存。CPU(JS)只操作内存(Virtual DOM),最后的时候再把变更写入硬盘(DOM)。
比较两棵虚拟DOM树的差异
比较两棵DOM树的差异是 Virtual DOM 算法最核心的部分,这也是所谓的 Virtual DOM 的 diff 算法。
两个树的完全的 diff 算法是一个时间复杂度为 O(n^3) 的问题。但是在前端当中,你很少会跨越层级地移动DOM元素。所以 Virtual DOM 只会对同一个层级的元素进行对比:
上面的div
只会和同一层级的div
对比,第二层级的只会跟第二层级对比。这样算法复杂度就可以达到 O(n)。
在实际的代码中,会对新旧两棵树进行一个深度优先的遍历,这样每个节点都会有一个唯一的标记,如下图所示:
Virtual DOM 算法实现
Virtual DOM 算法得实现主要是用三个函数:element,diff,patch。然后就可以实际的进行使用,如下面代码所示:
// 1. 构建虚拟DOM
var tree = el('div', {'id': 'container'}, [
el('h1', {style: 'color: blue'}, ['simple virtal dom']),
el('p', ['Hello, virtual-dom']),
el('ul', [el('li')])
]) // 2. 通过虚拟DOM构建真正的DOM
var root = tree.render()
document.body.appendChild(root) // 3. 生成新的虚拟DOM
var newTree = el('div', {'id': 'container'}, [
el('h1', {style: 'color: red'}, ['simple virtal dom']),
el('p', ['Hello, virtual-dom']),
el('ul', [el('li'), el('li')])
]) // 4. 比较两棵虚拟DOM树的不同
var patches = diff(tree, newTree) // 5. 在真正的DOM元素上应用变更
patch(root, patches)
diff算法
用 三大策略 将O(n^3)复杂度 转化为 O(n)复杂度
- 策略一(tree diff):
Web UI中DOM节点跨层级的移动操作特别少,可以忽略不计。
- 策略二(component diff):
拥有相同类的两个组件 生成相似的树形结构,
拥有不同类的两个组件 生成不同的树形结构。
- 策略三(element diff):
对于同一层级的一组子节点,通过唯一id区分。
tree diff
(1)通过updateDepth对Virtual DOM树进行层级控制。
(2)对树分层比较,两棵树只对同一层次节点进行比较。如果该节点不存在时,则该节点及其子节点会被完全删除,不会再进一步比较。
(3)只需遍历一次,就能完成整棵DOM树的比较。
diff只简单考虑同层级的节点位置变换,如果是跨层级的话,只有创建节点和删除节点的操作。
如上图所示,以A为根节点的整棵树会被重新创建,而不是移动,因此官方建议不要进行DOM节点跨层级操作,可以通过CSS隐藏、显示节点,而不是真正地移除、添加DOM节点。
Vue原理--虚拟DOM的更多相关文章
- vue之虚拟DOM、diff算法
一.真实DOM和其解析流程? 浏览器渲染引擎工作流程都差不多,大致分为5步,创建DOM树——创建StyleRules——创建Render树——布局Layout——绘制Painting 第一步,用HTM ...
- 最近发现了一篇讲解Vue的虚拟DOM,diff很棒的文章,特定记录转载一下
本文章是转载的,为了方便以后复习,特地记录一下.他人请去原地址观看!!! 文章原地址:https://blog.csdn.net/m6i37jk/article/details/78140159 作者 ...
- Vue之虚拟DOM
一.真实DOM和其解析流程? 浏览器渲染引擎工作流程都差不多,大致分为5步,创建DOM树——创建StyleRules——创建Render树——布局Layout——绘制Painting 第一步,用HTM ...
- vue 的虚拟 DOM 有什么好处?
vue 中的虚拟DOM有什么好处?快! 首先了解浏览器显示网页经历的5个过程 1.解析标签,生成元素树(DOM树) 2.解析样式,生成样式树 3.生成元素与样式的关系 4.生成元素的显示坐标 5.显示 ...
- vue核心---虚拟dom的实现
生成dom的过程 由vue模板生成虚拟dom 虚拟dom转换成真实dom渲染到html页面 代码实现 要实现的真实dom <div id="box"> <p cl ...
- 从虚拟dom了解vue渲染函数
vue渲染函数就是render函数,他会返回一个VNode,VNode是一个js对象,是dom的映射 vue在介绍渲染函数那个章节看的不是很懂,所以想要彻底的理解渲染函数,首先需要了解vue的虚拟do ...
- vue虚拟dom和diff算法
vue的虚拟dom和diff算法 1.虚拟dom 虚拟dom,我的理解就是通过js对象的方式来具体化每一个节点,把dom树上面的每个节点都变为对象里的一个元素,元素的子元素变为子节点,节点上面的cla ...
- 解密虚拟 DOM——snabbdom 核心源码解读
本文源码地址:https://github.com/zhongdeming428/snabbdom 对很多人而言,虚拟 DOM 都是一个很高大上而且远不可及的专有名词,以前我也这么认为,后来在学习 V ...
- 虚拟Dom详解 - (一)
随着Vue和React的风声水起,伴随着诸多框架的成长,虚拟DOM渐渐成了我们经常议论和讨论的话题.什么是虚拟DOM,虚拟DOM是如何渲染的,那么Vue的虚拟Dom和React的虚拟DOM到底有什么区 ...
随机推荐
- maven加载springboot project
maven加载springboot project 1● 下载项目 2● 构建project mvn install mvn package 3● idea加载 4● run启动 ==== ...
- .gitconfig
[user] name = 1111 email = 111@111.com[credential] helper = store
- maven到Gradle,一些对比和分享
Gradle作为一款基于Groovy语言的构建工具,已经吸引众多的ant,maven使用者转投gradle的怀抱,和Gradle相比,ant显得冗余复杂,maven显得有些死板落后,而gradle基于 ...
- 我是如何通过学习拿到年薪80w
本人做了5年Java,如今还是一个码农,天天写业务代码,直到2018年10月中旬遇到一位技术大牛,他给我一套技术思维导图让我又看到了希望!今天分享给各位想要提升.升职.加薪的你. 普通Java程序员与 ...
- js中时间戳与日期格式的相互转换
1. 将时间戳转换成日期格式: function timestampToTime(timestamp) { var date = new Date(timestamp * 1000);//时间戳为10 ...
- python之路-格式化输出、编码
格式化输出 user = input('Username:') pwd = input('Password:') msg = 'your username:%s,your password:%d,10 ...
- C#中枚举的使用
一.什么是枚举类型 枚举类型(也称为枚举):该类型可以是除 char以外的任何整型(重点). 枚举元素的默认基础类型为 int.准许使用的枚举类型有 byte.sbyte.short.ushort.i ...
- Touch事件分发源码解析
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 以下源码基于Gingerbread 2.3.7 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1.先看ViewGroup的di ...
- 【基于微信小程序的社区电商平台】需求分析心得——小豆芽
一.项目内容 基于微信小程序,做一个社区电商平台,抓住社区电商的特点,做出特色,与微信集成,实现商品的个性化发布,以及个性化营销. 个性化发布:用户可以在应用上直接发布自己的商品,通过搜索心愿单可以查 ...
- java实现链栈
package linkstack; /** * Created by Administrator on 2019/4/18. */ public class LinkStack { private ...