【vue设计与实现】简单Diff算法 4-添加新元素 & 移除不存在的元素

新的子节点组多了一个节点,而旧的一组子节点没有这个节点,因将其视为新增节点。那么要更新时要将新节点正确的挂载主要分为两步:

  • 要找到新增节点
  • 将新增节点挂载到正确位置

下面直接看代码:

function patchChildren(n1,n2,container){
	if(typeof n2.children === 'string'){
		// 省略部分代码
	}else if(Array.isArray(n2.children){
		const oldChildren = n1.children
		const newChildren = n2.children
	
		let lastIndex = 0
		for(let i=0;i<newChildren;i++){
			const newVNode = newChildren[i]
			let j = 0
			// 在第一层循环中定义变量find,代表是否在旧的一组子节点中找到可复用的节点,
			// 初始值为false,代表没找到
			let find = false
			for(j;j<oldChildren.length;j++){
				const oldVNode = oldChildren[j]
				if(newVNode.key === oldVNode.key){
					// 一旦找到可复用的节点,则将变量find的值设为true
					find = true
					patch(oldVNode, newVNode, container)
					if(j<lastIndex){
						const preVNode = newChildren[i-1]
						if(preVNode){
							const anchor = preVNode.el.nextSibling
							insert(newVNode.el,container, anchor)
						}
					}else{
						lastIndex = j
					}
					break
				}
			}
			// 如果代码运行到这里,find仍然为false
			// 说明当前newVNode没有在旧的子节点组中找到可复用的节点
			// 也就是说当前newVNode是新增节点,需要挂载
			if(!find){
				// 为了将节点挂载到正确位置,需要先获取锚点元素
				// 首先获取当前newVNode的前一个vnode节点
				const preVNode = newChildren[i-1]
				let anchor = null
				if(prevVNode){
					// 如果有前一个vnode节点,则使用下一个兄弟节点作为锚点元素
					anchor = prevVNode.el.nextSibling
					
				}else{
					// 如果没有前一个vnode节点,说明即将挂载的新节点是第一个子节点
					// 这时我们使用容器元素的firstChild作为锚点
					anchor = container.firstChild
				}
				// 挂载newVNode
				patch(null, newVNode, container, anchor)
			}
		}
	}else{
		// 省略部分代码
	}
	
}

这里我们目前实现的patch函数还不支持传递第四个参数,所以需要调整patch函数的代码,如下所示:

// patch函数需要接受第四个参数,即锚点元素
function patch(n1,n2,container,anchor){
	// 省略部分代码
	if(typeof type === 'string'){
		if(!n1){
			// 挂载是将锚点元素作为第三个参数传递给mountElement函数
			mountElement(n2,container,anchor)
		}else{
			patchElement(n1,n2)
		}
	}else if(type === Text){
		// 省略部分代码
	}else if(type === Fragment){
		// 省略部分代码
	}
}
// mountElement 函数需要增加第三个参数,即锚点元素
function mountElement(vnode, container, anchor){
	// 省略部分代码
	// 在插入节点时,将锚点元素传递给insert函数
	insert(el,container,anchor)
	
}

移除不存在的元素

在更新子节点时,不仅会遇到新增元素,还会出现元素被删除的情况,其实思路很简单,就是遍历旧的一组子节点,然后在新的一组子节点中寻找具有相同key值的节点。如果找不到就应该删除该节点,如下代码所示:

function patchChildren(n1,n2,container){
	if(typeof n2.children === 'string'){
		// 省略部分代码
	}else if(Array.isArray(n2.children){
		const oldChildren = n1.children
		const newChildren = n2.children
	
		let lastIndex = 0
		for(let i=0;i<newChildren;i++){
			// 省略代码
		}
		// 在上面更新操作完成后
		// 遍历旧的一组子节点
		for(let i=0;i<oldChildren.length;i++){
			const oldVNode = oldChildren[i];
			// 拿旧自己诶单oldVNode去新的一组子节点中寻找具有相同key值的节点
			const has = newChildren.find(vnode=>vnode.key === oldVNode.key)
			if(!has){
				// 如果没找到,就要删除该节点
				unmount(oldVNode)
			}
		}
	}else{
		// 省略部分代码
	}
	
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值