要说diff算法,不能不说虚拟dom,那么,什么是虚拟dom呢?
虚拟dom是用js模拟一颗dom树,放在浏览器内存中,相当于在js和真实dom中加了一个缓存,利用dom difl算法避免了没有必要的dom操作,从而提高性能。
虚拟DOM 在 VUE.js中,我们使用模板来描述状态与DOM之间的映射关系,vue.js通过编译模板转换成渲染函数(render),执行渲染函数(render)就可以得到一个虚拟节点树,使用这个虚拟节点树就可以渲染页面
模板——》渲染函数————》vnode————》视图(页面)
虚拟DOM的最终目标是将虚拟节点(vnode)渲染到视图上,但是如果直接使用虚拟节点覆盖旧节点的话,会有很多不必要的dom操作。 为了避免不必要的DOM操作,虚拟DOM在虚拟节点映射到视图的过程中,将虚拟节点与上一次渲染视图所使用的旧虚拟节点做对比,找到真正需要更新的节点来进行DOM操作,从而避免操作其他无需改动的dom (diff算法)
1. 提供与真实DOM节点所对应的虚拟节点 vnode
2. 将虚拟节点 vnode 和旧虚拟节点 oldVnode 进行对比,然后更新视图
下面到了正题了,diff算法的对比原则:
1、把树按照层级做对比
同一层只和当前层做对比,大人和大人做对比,小孩和小孩做对比
对比时如果标签一样,会直接在当前标签上修改内容,而不会创建一个新的标签,标签不同会直接删掉然后创建新的标签。
2、同key值对比
3、同组件对比
组件相同会对比着修改,不同直接删除然后创建新的
下面我用代码来帮大家加深一下印象
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
/*设置列表的样式*/
.list-item {
background: red;
color: white;
width: 200px;
margin-bottom: 10px;
display: flex;
justify-content: space-between;
}
/*设置列表transition-group的name为list的入场以及离场动画效果*/
.list-enter-active, .list-leave-active {
transition: all 1s;
}
.list-enter, .list-leave-to
{
opacity: 0;
transform: translateX(-100px);
}
</style>
</head>
<body>
<div id="app">
<input type="text" v-model="renwu" name="" id="" value="" />
<button v-on:click="add">添加任务</button>
<ul>
<transition-group name="list" tag="p">
<li v-for="(item,index) in items" :key="index" class="list-item">
{{ item }}<button @click="remove(index)">删除任务</button>
</li>
</transition-group>
</ul>
</div>
</body>
</html>
<script src="js/vue.js"></script>
<script type="text/javascript">
// 2\. 创建一个Vue的实例
var vm = new Vue({
el: '#app',
data: {
items: ['任务1','任务2','任务3'],
renwu:''
},
methods:{
add(){
this.items.push(this.renwu)
},
remove(index){
this.items.splice(index, 1)
},
}
})
</script>
大家可以复制下来试一试,这个是个有问题的,我的transtion-group中包裹的li的key我设置的是index,这样大家点击删除按钮后,会发现删是删掉了,但是动画总是在最后一个li上面,这里就可以用diff算法原则来解释了。
同key值对比原则,对比发现前两个是内容被替换了,然后key=2的是节点被删除了,所以删除的动画效果一直是在最后一个li上面。
只需要把li的key设置为一个唯一的key即可,记住,一定不要在transtion-group中将key设置为index