虚拟DOM
是什么
一个能代表DOM树的对象,通常含有标签名,标签上的属性,事件监听和子元素们,以及其他属性。
优点(相比于操作原生DOM只在以下情况下快)
减少不必要的DOM操作
可以通过合并DOM操作来减少DOM操作的次数;
也可以通过DOM diff算法来减少需要改变的个数,缩小范围。
跨平台
虚拟DOM本质上是一个JS对象,它不仅可以变成DOM对象,而且可以变成小程序、IOS应用、安卓应用等。
//React 中的虚拟DOM
const vNode = {
key:null,
props:{
children:[
{type:'span','span1'},
{tyoe:'span','span2'}
],
className:'red'
onclick:()=>{}
},
ref:null,
type:'div',
...
}
//创建虚拟DOM
createElement('div',{className:'red',onClick:()=>{}},[
createElement('span',{},'span1'),
createElement('span',{},'span2'),
]
)
//Vue中的虚拟DOM
const vNode = {
tag:'div',
data:{
class:'red',
on:{
click:()=>{}
}
},
children:[
{tag:'span','span1'},
{tag:'span','span2'}
],
...
}
//创建虚拟DOM
h('div',{
class:'red',
on:{
click:()=>{}
},
},[h('span',{},'span1'),h('span',{},'span2')])
React使用JSX语法来简化创建虚拟DOM,通过babel转为createElement形式。
<div className='red' onClick='{()=>{}}'>
<span>span1</span>
<span>span2</span>
</div>
Vue使用Vue Template来简化创建虚拟DOM,通过vue-loader转为h形式。
<div class='red' @click='fn'>
<span>span1</span>
<span>span2</span>
</div>
缺点
必须使用babel或vue-loader来将JSX语法/vue-template转化为创建函数createElement或者h。
DOM diff
当数据变化时,DOM diff算法会只更新变化的地方,如标签的属性从class='red'变为class='green'时,只需更新标签的属性。其他均不更新。
一个函数,patch,patches=patch(oldNode,newNode)。
大致的作用原理:Tree diff,将新旧DOM树逐层对比,找出需要更新的节点。如果节点是组件,就看Component diff;如果节点是标签,就看Element diff。
Component diff:如果节点是组件,就先看组件类型,类型不同直接替换,类型相同就只更新属性。然后继续深入组件做Tree diff。
Element diff:如果节点是原生标签,则看标签名。标签名不同直接替换,相同则只更新属性。然后进入标签后作Tree diff。
缺点
同级比较时存在bug,需要使用key值来确定需要更新的节点。