diff 算法
简单的diff算法
-
减少dom的操作,
当更新节点的时候,会进行对比,如果新旧节点只有文本内容不同,则只更新文本节点的内容,这样我们不需要将原节点卸载之后在进行挂载。
当进行新旧两组节点更新的时候,应该遍历最短的节点,这样才能尽可能多的的调用patch 进行节点的更新, 如果新的节点更改,说明有需要进行挂载的节点,如果旧的节点更长,说明有需要进行卸载的节点
-
dom复用与key的作用
1.通过dom 的移动来进行复用dom
-
如何确定dom 是否可以复用,
- 通过 vnode.type
- 通过 key 来进行dom是否可以进行复用
- 如果以上两个都相同了,仍然需要进行内容的更新
实现: 通过两层的嵌套for循环来对比新旧节点的key ,找到可以复用的节点,更新节点的内容,完成节点的复用,还需要进行移动节点的位置,来实现更新
2.复用节点的移动
-
如何找到移动的节点
- 先将新旧节点按照位置进行索引值的排序 , 即旧节点 顺序 0,1,2,3,4,5 .... , 新节点的顺序 0,1,2,3,4,5 ...
- 取新的节点的第一个值,通过key 向旧节点查找相同的key ,并记录找到的旧节点的 index值,记做 maxIndex
- 新节点继续向下遍历,通过下一个值的key 从旧节点里找可以复用的节点, 如果发现 找到的旧节点的index的值 小于 记录的 旧节点的index值,则说明,新找到的旧节点应该在 ,记录的maxIndex 的旧节点的前面,这样就找到了需要进行移动的旧节点, 也就是在旧节点找到的可以复用的节点的位置,打破了新节点中index值递增的顺序,也就意味着旧节点需要进行节点的移动
-
如何移动节点
- 移动真实的dom 需要知道真实dom的引用
- 当一个虚拟节点被挂载之后,vnode.el 存储的就是真实dom 的引用
- 我们可以将旧节点的 vnode.el 赋值给新节点的 vnode.el 就可以让 新节点也拥有真实dom的引用了
- 移动的位置: 需要获取节点的前一个虚拟节点,即 newChild[i-1] ,然后使用inset函数来完成节点的移动,使用的浏览器原生的 inserBefore(el,anchor) anchor 锚点元素,用来将真实的dom 插入元素。也就是将节点移动到上一个新节点在旧节点中的位置的后面,
-
-
添加新元素
-
找到新增元素
- 通过key 在旧节点中找是否有重复key , 如果没有则表示该节点为新节点
-
将新增的元素挂载到正确的位置
- 在新节点找到前一个元素的位置,通过前一个元素来进行新节点的挂载
-
-
移除旧元素
- 但基本的更新结束的时候
- 我们遍历旧节点,然后去新节点找时候有旧节点的key ,如果找不到则删除该节点,