vue2-diff算法手写一步步增加功能

发布时间 2024-01-05 09:57:17作者: re大法好

前面

  • vue2 diff算法尽可能复用原来的老节点(比如老节点头尾跟新节点头尾看看是不是同一个节点,是的话打个补丁(更新class什么的,然后他的子节点继续调用这个diff算法), 没有找到可复用的就重新创建)。代码行数也不多,核心函数是 updateChildren

vue patch工作流程简单版本

  • 示例代码

<div class="app" @click="count++">{{count}}</div>
new Vue({
	data(){
		return {
			count: 0
		}
	}
})

首次$mount

  • 首次$mount的时候, vue会根据模板生成对应的VNode
  • 发现第一次渲染,直接根据vnode全量生成dom即可

// 第一次渲染的VNode
{
	tag: "div",
	attrs: {'class': 'app'},
	children: [
		{tag: undefined, text: 0}
	]
}

count变化的时候

  • 当count变化,会重新生成一次VNode
  • 与上一份的VNode进行比较,发现不一样的就去修改对应的dom,这时候一个优秀的diff算法就很重要了,优秀的diff算法可以最小化减少dom性能的消耗。

// count变化时候渲染的VNode
{
	tag: "div",
	attrs: {'class': 'app'},
	children: [
		{tag: undefined, text: 1}
	]
}

vue2 diff算法原则

  • 以组件为一个整体,如果发现根标签不是同一个元素, 会销毁所有的dom,全部重新创建。相关源码如下
    image
  • diff算法是只同层比较, 深度优先。先创建完元素,然后最后再删除不需要的。

开始实现

先实现一个h函数,专门生成VNode的。(类似于vue2的render函数)


function h(tag, attrs, children){
	// h('div', {}, [h(undefined, {}, '111')])
	if (tag){
		const node = {
			tag, attrs, 
			children
		}
		return node;
	}
	return {
		tag,
		attrs,
		text: children
	}
}
// <div>111</div>
h('div', {}, [h(undefined, {}, '111')])

  • 这样就可以生成我们想要的Vnode了。如下图所示
    image