vue的diff算法讲解

·  阅读 489

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第15天,点击查看活动详情

当数据发生变化时,vue是怎么运作的?

vue会根据真实DOM生成virtual dom,当虚拟DOM节点数据变化时会生成一个新的vnode,然后vnode和oldVnode作对比,如果有不一样的地方就直接修改在真实的dom上,然后将oldVnode更新为vnode,diff的过程就是调用patch(打补丁)函数,比较新旧节点,一边比较一边给真实的DOM打补丁

虚拟DOM和真实DOM都是什么样的?

<div>
	<span>我是真实DOM<</span>
</div>
复制代码
let vnode = {
	tag: 'div',
	children: [
		{tag: 'span', text: '我是虚拟DOM'}
	]
}
复制代码

vue的diff只会比较新旧节点,并且只会在同级比较,不会进行跨层级比较

diff过程

在学习diff的过程前,我们需要知道当数据发生变化,会触发obderve中的set方法,set方法会调用Dep.notify通知所有订阅者watcher,订阅者就会调用patch给真实的DOM打补丁(对Vue的observe、watch、compile概念不清楚的可以去看我的vue双向绑定原理文章)

在这里插入图片描述

在patchVnode方法中还调用了一个方法updateChildren

  • 这个方法将vnode的子节点vCh和oldVnode的子节点oldCh作对比进行更新,简单来说就是,将旧节点集合以新节点集合为标准调整

  • oldCh和vCh各有两个头尾的变量StartIdx和EndIdx,它们的2个变量相互比较,一共有4种比较方式。如果4种比较都没匹配,如果设置了key,就会用key进行比较,在比较的过程中,变量会往中间靠,一旦StartIdx>EndIdx表明oldCh和vCh至少有一个已经遍历完了,就会结束比较

大家来跟我看图就明白了 在这里插入图片描述

oldVnode是更新前的节点,vnode是更新后的节点,那么我们来看看,旧节点集合是怎么根据新节点集合来进行调整的

在这里插入图片描述

现在分别对oldS、oldE、S、E两两做sameVnode比较,所以有四种比较方式,当其中两个能匹配上那么真实dom中的相应节点会移到Vnode相应的位置

  • 如果是oldS和E匹配上了,那么真实dom中的第一个节点会移到最后
  • 如果是oldE和S匹配上了,那么真实dom中的最后一个节点会移到最前,匹配上的两个指针向中间移动
  • 如果四种匹配没有一对是成功的,那么遍历oldChild,S挨个和他们匹配,匹配成功就在真实dom中- 将成功的节点移到最前面,如果依旧没有成功的,那么将S对应的节点插入到dom中对应的oldS位置,oldS和S指针向中间移动。

第一步: a = oldS, d = oldE a = s, b = e oldS和s匹配上了,但是都在第一个,所以不用做任何操作 此时DOM为a b d,最后oldS指针和s指针向内部移动oldS指向旧集合的b,s指向新集合的c,如下图所示。

第二步: 在这里插入图片描述 b = oldS, d = oldE c = s, b = e 发现oldS指针和e指针指向的内容匹配,所以将旧集合中的b元素移动到最后 (当其中两个能匹配上那么真实dom中的相应节点会移到Vnode相应的位置) 此时DOM为a d b,最后oldS指针和e指针向内部移动oldS指向旧集合的d,e指向新集合的d,如下图所示。

第三步: 在这里插入图片描述 d = oldE, d = oldS c = s, d = e 发现oldE和d是匹配的,位置不变 然后oldS++ ,oldE-- oldS > oldE,遍历结束,说明oldCh先遍历完,将剩余的节点按照自己的index插入到真是dom中,此时DOM为a c d b。

分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改