虚拟 DOM 和 DOM diff

86 阅读2分钟

Web 界面是由DOM树(树的意思是数据结构)构建而成的,当其中一部分改变时,对应某个DOM节点发生了变化。DOM 元素是非常庞大的,一旦对 DOM 进行操作就可能会导致页面重绘或重排,这样将会对页面的性能造成影响,所以为了减少由于重绘或重排造成的性能影响问题,都要尽可能少的去操作DOM节点。

虚拟 DOM

一个能代表 DOM 树的对象,通常含有标签名、标签上的属性、事件监听和子元素以及其他属性

优点

  1. 减少 DOM 操作:虚拟 DOM 可以把多次操作合并为一次操作;通过DOM diff 可以把多余操作省掉

  2. 跨平台:不仅可以变成DOM,还可以变成小程序、IOS应用、安卓应用

如何创建虚拟 DOM

React

createElement('div',{className:'red',onClick:()=>{}},[
	createElement('span',{},'span1'),
	createElement('span',{},'span2'),
	]
)

Vue

h('div',{
	class:'red',
    on:{
    	click:()=>{}
    },
},[
	h('span',{},'span1'),
    h('span',{},'span2')
    ]
)

通过 JSX 创建 (推荐)

React
<div className="red" onClcik={fn}>
	<span>span1</span>
    <span>span2</span>
</div>
Vue
<div className="red"@clcik="fn">
	<span>span1</span>
    <span>span2</span>
</div>

DOM diff

DOM diff 就是一个函数,我们称之为 patch ,他会对比渲染更新前和更新后的两个虚拟 DOM 对象的差异,形成一个差异补丁,并将其运用到真实的 DOM 上。

DOM diff 的大概逻辑

1.Tree Diff

  • 新旧两棵树结构逐层比较,找出那些节点需要更新
  • 如果节点是组件就看 Component Diff
  • 如果节点是标签或者元素就看 Element Diff
  1. omponent Diff
  • 如果组件类型不同,删除旧内容的内容替换为新内容
  • 如果组件类型相同,则只更新属性,然后深入组件做 Tree diff(递归)
  1. Element Diff
  • 如果节点是原生标签,则看标签名做比较,不同直接替换,相同只更新属性
  • 然后进入标签后代递归 Tree diff(递归)

DOM diff的问题

没有唯一key值的更新问题

当做动态改变的时候,没有唯一的key值,有可能引起更新错误,因此,不建议使用 :key="index",应该使用:key="id"