什么是虚拟DOM
虚拟DOM本质上就是一个JS对象,是更加轻量级的对DOM的描述。
比如template里面的标签结构
<template>
<div id="box">
<p class="text">这是一段文字</p>
</div>
</template>
对于的虚拟DOM结构
const dom = {
type: 'div',
attributes: [{ id: 'box' }],
children: {
type: 'p',
attributes: [{ class: 'text' }],
text: '这是一段文字'
}
}
为什么需要虚拟DOM?
- 真实DOM身上有很多的属性和方法,频繁操作真实DOM,会造成浏览器的重绘和回流,性能会比较差。
- 虚拟DOM会等到数据更新完成之后,只更新真实DOM需要改变的地方,只会有一次重绘和回流,相对操作真实DOM性能更好。
- vue组件在初始化的时候会生成一个虚拟DOM树,当数据更新的时候,会生成一个新的虚拟DOM树,然后利用diff算法将两份DOM树进行对比,只更新其中变化的部分,实现高效更新。
diff算法
diff算法有三种情况:
- 一种是元素变了(也就是标签发生变化),那就会删除元素,重新创建新的元素。
- 第二种是元素没变,属性或者内容发生变化,那就只更新属性和内容。
- 第三种是v-for遍历的时候,它又分为两种情况:
- 第一种是没有key或者key为索引值的时候,这种情况会采用就地更新的原则。按照顺序进行比对,顺序一样或者索引一样的就认为是同一个元素,在不打乱顺序的情况下可以实现高效更新,但是如果顺序被打乱就会造成不必要的更新。
旧虚拟DOM
<ul>
<li>a</li>
<li>b</li>
<li>c</li>
</ul>
新虚拟DOM
<ul>
<li>d</li>
<li>a</li>
<li>b</li>
<li>c</li>
</ul>
- 第二种是有key的情况,key就是一个唯一表示,有了它之后,就算顺序被打乱,也会根据key值去找到同一个元素,就不会去更新旧的元素
旧虚拟 dom
<ul>
<li key="a">a</li>
<li key="b">b</li>
<li key="c">c</li>
</ul>
新虚拟 dom
<ul>
<li key="d">d</li>
<li key="a">a</li>
<li key="b">b</li>
<li key="c">c</li>
</ul>
补充:虚拟dom除了可以实现高效更新外,它最大的作用是可以实现跨平台,只要一套代码就可以实现不同平台的复用。原因就是虚拟dom它本身是一个JS对象,他不会固定为某一种固定结构,会根据不同的运行环境生成不同的结构。