详解vue的diff算法原理
我的目标是写一个非常详细的关于diff的干货,所以本文有点长。也会用到大量的图片以及代码举例,目的让看这篇文章的朋友一定弄明白diff的边边角角。 先来了解几个点... 1. 当数据发生变化时,vue是怎么更新节点的?要知道渲染真实DOM的开销是很大的,比如有时候我们修改了某个数据,如果直接渲染到真实dom上会引起整个dom树的重绘和重排,有没有可能我们只更新我们修改的那一小块dom而不要更新整个dom呢?diff算法能够帮助我们。 我们先根据真实DOM生成一颗 diff的过程就是调用名为 真实的DOM打补丁。2. virtual DOM和真实DOM的区别?virtual DOM是将真实的DOM的数据抽取出来,以对象的形式模拟树形结构。比如dom是这样的: 123 对应的virtual DOM(伪代码): (温馨提示: 3. diff的比较方式?在采取diff算法比较新旧节点的时候,比较只会在同层级进行,不会跨层级比较。 123
456
上面的代码会分别比较同一层的两个div以及第二层的p和span,但是不会拿div和span作比较。在别处看到的一张很形象的图: diff流程图 当数据发生改变时,set方法会让调用 具体分析 patch 来看看 patch函数接收两个参数 判断两节点是否值得比较,值得比较则执行 的时候,type必须相同
)
}
不值得比较则用 如果两个节点都是一样的,那么就深入检查他们的子节点。如果两个节点不一样那就说明 虽然这两个节点不一样但是他们的子节点一样怎么办?别忘了,diff可是逐层比较的,如果第一层不一样那么就不会继续深入比较第二层了。(我在想这算是一个缺点吗?相同子节点不能重复利用了...) patchVnode当我们确定两个节点值得比较之后我们会对两个节点指定 这个函数做了以下事情:
其他几个点都很好理解,我们详细来讲一下updateChildren updateChildren代码量很大,不方便一行一行的讲解,所以下面结合一些示例图来描述一下。 oldEndIdx) {
before = newCh[newEndIdx + 1] == null ? null : newCh[newEndIdx + 1].el
addVnodes(parentElm,before,newCh,newStartIdx,newEndIdx)
}else if (newStartIdx > newEndIdx) {
removeVnodes(parentElm,oldEndIdx)
}
}
先说一下这个函数做了什么
图解updateChildren终于来到了这一部分,上面的总结相信很多人也看得一脸懵逼,下面我们好好说道说道。(这都是我自己画的,求推荐好用的画图工具...) 粉红色的部分为oldCh和vCh 我们将它们取出来并分别用s和e指针指向它们的头child和尾child 现在分别对
再配个图
第二步
第三步
oldE;
遍历结束,说明 一次模拟完成。 这个匹配过程的结束有两个条件:
下面再举一个例子,可以像上面那样自己试着模拟一下 当这些节点 就这样层层递归下去,直到将oldVnode和Vnode中的所有子节点比对完。也将dom的所有补丁都打好啦。那么现在再回过去看updateChildren的代码会不会容易很多呢? 总结以上为diff算法的全部过程,放上一张文章开始就发过的总结图,可以试试看着这张图回忆一下diff的过程。 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程之家。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |