前面
- 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,全部重新创建。相关源码如下
- 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了。如下图所示