虚拟Dom和Diff算法
首先,我们需要了解什么是虚拟Dom,又为什么需要虚拟Dom。虚拟Dom即Virtual Dom,他是用JS对象记录一个Dom节点的副本,当Dom发生更改时候,先用虚拟Dom进行Diff,算出最小差异,然后再修改真实Dom。我们之所以是使用Dom必定是因为他存在一定的优点,在我们用传统的方式操作Dom的时候,我们的浏览器会从构建DOM树开始从头到尾执行一遍过程,效率较低。
<ul id="aa">
<li class="a1">我是li1</li>
<li class="a2">我是li2</li>
<li class="a3">我是li3</li>
</ul>
以上面代码为例,按照传统的方式操作Dom我们就需要使用
var a = document.createElement('li')
document.querySelector('#aa').appendChild(a)
在js里面输入上面两行代码就会在我们的ul里面追加一个li标签,但是在我们的开发过程中对节点的操作并不少,因此大批量的数据更新会导致浏览器的运行速度减慢,这是使用传统方式的一个弊端,面对这种情况,我们的Vue提供了虚拟Dom。
虚拟Dom就是在我们遇到了数据较大、复杂文档的Dom结构,提供了一种便捷的工具。简单的说,就是我们的虚拟Dom工具的任务就是将虚拟的Dom转换成真是的Dom,当我们的数据发生改变的时候或者页面需要进行重新渲染的时候,会生成一个新的虚拟Dom,使用我们的diff算法,拿我们的新的虚拟Dom和旧的虚拟Dom做对比,找到不一样的地方,将需要更新的地方直接更新,没有更改的地方就无须进行操作。这样我们就可以大量减少真实的Dom操作,提高性能。
下面将通过以下代码来大致了解以下Vue的虚拟Dom:
<div id="app">
<my-component></my-component>
</div>
<template id="my-component">
<div id = "vd">
<ul>您好</ul>
<ol class = "ol"></ol>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
// 1.首先,我们需要内存中生成一个虚拟Dom树
//这是他的内部操作
// var vD = {
// // 标签
// tag:"div",
// attr:{
// id:"vd"
// },
// children:[
// {tag:"ul",content:"你好"},
// {tag:"ol",attrs:{className:"ol"}}
// ]
// }
// 其次,我们将内存中的虚拟dom树初始化渲染成真实dom树
Vue.component('my-component', {
template:"#my-component",
// functional: true,
// Props 是可选的
props: {
// ...
},
// 为了弥补缺少的实例
// 提供第二个参数作为上下文
})
// var data = {
// arr:[]
// }
// 当需要追加一条数据的时候
// data.arr.push('<li>我是新加进去的</li>')
// 再将之前的虚拟Dom结合新的数据渲染成一个新的虚拟Dom
//var newD = {
// 标签
// tag:"div",
// attr:{
// id:"vd"
// },
// children:[
// {tag:"ul",content:"你好"},
// {tag:"ol",attrs:{className:"ol"},children:[
// {tag:"li",content:"我是新加进去的"}
// ]}
// ]
// }
// 使用Diff算法将新生成的Dom树与之前的Dom数进行比较,将对比之后不同的数据进行真实Dom的数据渲染
//实例化对象
new Vue({
el:"#app",
data:{
}
})
以上就是我们的虚拟Dom转换成真实的Dom,其实他的渲染在内部是依靠一个叫做render的函数,具体参照文档render
当我们说到虚拟Dom的时候,我们知道我们的新旧Dom树是依靠Diff算法进行对比的,那么什么是Diff算法,他为什么会有这样的功能呢?
Diff算法的作用是用来计算出 Virtual DOM 中被改变的部分,然后针对该部分进行原生DOM操作,而不用重新渲染整个页面。下图是我们的diff算法的对比过程:
对比之后将我们的真实Dom渲染在页面上。上图是数据层面的比较,但是当我们的数据结构发生变化的时候,我们需要对它一层一层的进行比较,这个时候我们需要给一个key值,就像我们在电影院买票一样,每张票对应了一个座位,即使我们没有没人来的早,但是那个位置是在我的电影票生效的时候是属于我自己的,当我们需要在同级的结构下面操作,就需要用到key,这样不会取代别的结构的位置。
上图就是将我们的F插入到B和C之间。
我们内部当数据变化,生成一颗新的虚拟dom树,与上一次的虚拟dom树结构进行对比。也就是说,当数据变化的时候,大量操作的是虚拟dom,而虚拟dom属于内存数据,操作起来性能要高的多。而真实的dom操作,只有在追加的那一刻才会进行操作,大大提升了性能。