【vue设计与实现】快速Diff算法 3-如何移动元素

在前面关于moved标识和source数组

  1. 通过moved来判断是否需要移动
  2. 后面会根据source数组计算出一个最长递增子序列,用来DOM移动操作

首先要搞清楚什么是递增子序列。
其实就是,给定一个数值序列,找到它的一个子序列,并且该子序列中的值是递增的,而子序列中的元素在原序列中不一定连续。一个序列可能有很多个递增子序列,其中最长的一个就称为最长递增子序列。当然,对于同一个数值序列来说,其最长递增子序列可能有多个,例如在[0,8,4,12] 中 最长递增子序列是[0,8,12] 也可以是[0,4,12]
在代码中可以是用lis函数获取最长递增子序列,并且lis函数返回的结果是最长递增子序列中的元素在参数数组中的位置索引
比如看下面代码

conse seq = lis(sources)
console.log(seq)

得到的结果是[0,1]
而[0,1] 对应的是 最长递增子序列在数组中的索引[2,3]

有了最长递增子序列的索引信息后,下一步就要重新对节点进行编号
为了完成节点的移动,还需要创建两个索引值 is
i 指向新子节点的最后一个节点
s 指向最长递增子序列的最后一个元素

然后再开启一个for循环,让变量t和s从后向前的顺序移动,如下代码:

if(moved){
	const seq = lis(source)
	let s = seq.length - 1
	let i = count - 1
	// for循环让i递减
	for(i; i>=0; i--){
		if(i !== seq[s]){
			// 如果节点的索引i不等于seq[s]的值,说明该节点需要移动
		}else{
			// 当i === seq[s]时,说明该位置的节点不需要移动
			// 只需要让s指向下一个位置
			s--
		}
	}
}

接下来就按照上面的思路进行更新

if(moved){
	const seq = lis(source)
	let s = seq.length - 1
	let i = count - 1
	for(i; i>=0; i--){
		if(source[i] === -1){
			// 在source数组中相同位置的元素值为-1,说明是全新的节点,应该将其挂载
			// i+newStart 是该节点在新children中的真实位置索引
			const pos = i + newStart
			const newVNode = newChildren[pos]
			// 该节点的下一个节点的位置索引
			const nextPos = pos + 1
			// 锚点
			const anchor = nextPos < newChildren.length?newChildren[nextPos].el:null
			// 挂载
			patch(null,newVNode,container,anchor)
		}else if(i!==seq[s]){
			// 如果节点的索引i不等于seq[s]的值,说明该节点需要移动
		}else{
			// 当i === seq[s]时,说明该位置的节点不需要移动
			// 只需要让s指向下一个位置
			s--
		}
	}
}

新节点创建完成后,此时索引i向上移动了一步,接着再进行下一轮for循环

if(moved){
	const seq = lis(source)
	let s = seq.length - 1
	let i = count - 1
	for(i; i>=0; i--){
		if(source[i] === -1){
			// 省略
		}else if(i!==seq[s]){
			// 如果节点的索引i不等于seq[s]的值,说明该节点需要移动
			const pos = i + newStart
			const newVNode = newChildren[pos]
			// 该节点的下一个节点的位置索引
			const nextPos = pos + 1
			// 锚点
			const anchor = nextPos<newChildren.length?newChildren[nextPos].el:null
			// 移动
			insert(newVNode.el,container,anchor)
		}else{
			// 当i === seq[s]时,说明该位置的节点不需要移动
			// 只需要让s指向下一个位置
			s--
		}
	}
}

之后在进行循环直到更新完成

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值