首先要明确的一点是:DOM操作慢是对比JS原生API,如数组操作。任何基于DOM的库(Vue,React)都不可能在操作DOM时比DOM快。DOM操作不算太慢,慢的是浏览器渲染时间,而浏览器在渲染时是无法交互的。
但在某些情况下,虚拟DOM会比真实DOM快。规模较小时,虚拟DOM比DOM快,担当规模达到一定程度时,DOM可能比虚拟DOM快。
虚拟DOM的优点
减少DOM操作
即减少DOM操作次数。虚拟DOM可以将多次操作合并为一次操作。
举个例子,比如说要添加1000个节点,真实DOM是一个接一个添加的,而虚拟DOM是一次性添加1000个节点。
还是这个例子,如果你要在已经添加完1000个节点的页面上再新增10个节点,真实DOM可能无法区分,只能重新渲染1010个节点。而虚拟DOM可以通过DOM diff对比前后区别只重新渲染10个新增节点。
跨平台
虚拟DOM不仅可以变成DOM,还可以变成小程序、IOS应用、安卓应用,因为虚拟DOM本质上只是一个JS对象。
虚拟DOM是什么
一个能代表DOM树的对象,通常含有标签名、标签上的属性、事件监听和子元素们,以及其他属性。
虚拟DOM的缺点
需要额外的创建函数,如createElement(React)或h(Vue),但可以通过JSX语法简化XML写法。但这样严重依赖打包工具,否则浏览器不认识,更无法运行。
DOM diff
DOM diff是虚拟DOM的对比算法。就是一个函数,用于对比上下两次DOM树的区别,获得需要运行的DOM操作。
DOM diff的运行逻辑
Tree diff
- 将新旧两颗DOM树进行对比,找出哪些节点需要更新
- 如果节点是组件就看Component diff
- 如果是标签更新就看Element diff
Component diff
- 如果节点是组件,就先看组件
- 类型不同就直接替换(删除旧的)
- 类型相同则只更新属性
- 然后深入组件做Tree diff(递归)
Element diff
- 如果节点是原生标签,则看标签名
- 标签名不同直接替换,相同则值更新属性
- 然后进入标签后代做Tree diff(递归)
DOM diff的问题
同级比较存在BUG,需要添加key来做标记。
出现的问题可以参考文章Vue2.0 v-for 中 :key 到底有什么用?