虚拟DOM
定义
一个能代表 DOM 树的对象,通常含有标签名、标签上的属性、事件监听和子元素们,以及其他属性
优点
1、减少DOM 操作
虚拟 DOM 可以将多次操作合并为一次操作(减少频率)
虚拟 DOM 借助 DOM diff 可以把多余的操作省掉(减少范围)
2、可以跨平台
虚拟 DOM 本质上只是一个 JS 对象 (可以变成 DOM,还可以变成小程序、iOS 应用、安卓应用)
缺点
需要额外的创建函数,如createElement 或 h,但可以通过 JSX 来简化成 XML 语法
虚拟DOM
在React中的虚拟DOM
const vNode = {
key: null,
props: {
children: [
{type: 'span', ...},
{type: 'span', ...}
],
className: "red",
onClick: ()=>{}
},
ref: null,
type: "div",
...
}
在Vue中的虚拟DOM
const vNode = {
tag: 'div',
data: {
class: 'red',
on: {
click: ()=>{}
}
},
children: [
{tag: "span", ...},
{tag: "span", ...}
],
...
创建虚拟DOM
React
createElement('div',{className:'red',onClick:()=> {}},[
createElement('span', {}, 'span1'),
createElement('span', {}, 'span2')
]
)
// 通过 JSX 简化
<div className="X" onClick="{()=> {}}">
<span>span1</span>
<span>span2</span>
</div>
// 通过 babel 转为 createElement 形式
Vue
// 只能在 render 函数里得到 h
h('div', {
class: 'red',
on: {
click: () => { }
},
}, [h('span',{},'span1'), h('span', {}, 'span2'])
// 通过简化JSX
<div class="red" @click="fn">
<span>span1</span>
<span>span2</span>
</div>
// 通过 vue-loader 转为 h 形式
DOM Diff
DOM diff其实就是一个函数,它会对比 oldNode 与 newNode 的区别。从而减少不必要的渲染。但是DOM diff会有bug(可以使用key解决)
Tree diff :将新旧两棵 DOM 树,按照层级对应的关系,这样只需要对树进行一次遍历,就能够找到哪些元素是需要更新的; 如果节点是组件就看 Component diff ; 如果节点是标签就看 Element diff。
Component Diff: 在对比每一层的时候,每一层都有自己的组件, 那么组件之间的对比,叫做 Component diff
如果节点是组件,就先看组件类型
类型不同直接替换(删除旧的)
类型相同则只更新属性
然后深入组件做 Tree diff(递归)
- Element Diff : 如果新旧 DOM 树中的组件类型相同,会继续比较这两个组件内部的元素是否也相同,如果元素发生了改变,则找到需要修改的元素,有针对性的修改,这种组件内部元素级别的对比叫: Element Diff;
如果节点是原生标签,则看标签名
标签名不同直接替换,相同则只更新属性
然后进入标签后代做 Tree diff(递归)