虚拟dom和diff算法
前言
如果我们修改一个值,页面就得重新刷新渲染整个dom树,那么不利于我们提升渲染页面的性能,因此我们可以完成最小量更新,即前后一致的地方不需要重新渲染,只渲染改变的部分
概念
虚拟dom: 对于虚拟dom有关概念的理解,可以把它看成是一个对象。页面上我们可以操作的节点可以看作是一个对象,而每个对象中包含当前dom的一些属性,当我们想要用新dom替换旧dom时,我们可以来比较两者某些属性的异同点,并且对此进行diff算法完成最小区域更新
diff算法: diff算法顾名思义,用来比较两个节点之间一些不同的属性,并对这些属性进行某些操作,实现最小区域更新,来提升我们渲染页面的速度
snabbdom: snabbdom库,是diff算法的鼻祖,它可以有效的实现dom的局部快速更新,现在流行的一些框架中就借用了snabbdom库,关于snabbdom的了解,点击详情:github.com/snabbdom/sn…
有关于snabbdom及webpack的测试环境搭建,大家可参考考webpack官网
运行流程
在h . js文件中我们暴露一个h函数,它首先会对传进来的参数的个数进行判断,要满足有且只有三个参数。它可以对传进来的最后一个参数c的属性进行判断,这个c属性有以下几种不同的情况
-
c仅为字符串或者数字,此时返回并调用vnode函数
-
c为数组,此时证明当前父节点有子元素,经过遍历把这个数组里的虚拟dom添加至children当中,此时返回并调用vnode函数
-
c为一个对象,且这个对象拥有sel属性,此时把c添加至children数组当中,此时返回并调用vnode函数
-
c的类型不正确,抛错即可
在vnode.js文件中,我们要对传递进来的参数做一个对象化处理,并将这个对象导出
export default function (sel, data, children, text, elm) {
const key = data.key
return {
sel, data, children, text, elm, key
};
}
接着在patch.js文件中,暴露一个patch函数。我们在调用patch函数传递两个参数,分别是老节点oldVnode和新节点newVnode,也就是可能要替换的节点,这一步我们要完成几个判断,如下
-
oldVnode无sel属性,此时需要调用vnode函数,并传递相应的参数,迫使oldVnode变成虚拟dom
-
判断oldVnode和newVnode是不是同一个节点,如果是,则调用patchVnode函数,并传递oldVnode和newVnode两个参数
-
如果新老节点不是同一个节点,则需要添加新节点,删除老节点
如果以上各自的判断语句进行完毕,则需要调用createElement函数创建真实的dom节点,并在patch函数内部显示在页面上
这里注意,patch函数就是用来帮助虚拟dom上树的
在createElement.js文件中,暴露一个createElement函数,这个函数用来帮助把虚拟dom变为真实dom,注意此时还未上树,新dom进入到这个函数体内,执行的流程如下
-
利用document.createElement( )函数创建真正的dom
-
其次判断这个虚拟dom身上有没有文本,如果有,直接把这个文本赋值给新的真实dom里的innerHTML
-
如果没有文本,那就必定是数组,此时要依次对这个数组进行递归,创建子节点,添加到父节点内部,最终返回这个节点整体
-
完成新旧dom的整体或者部分更新
createElement函数的作用就是创建真正dom节点,并交付给patch函数完成上树
patchVnode . js文件内部向外导出一个patchVnode函数,这个函数就是对同一个虚拟节点,即新老节点的key相同,以及sel相同,来做一些覆盖性操作。此时我们需要对新老节点上的一个属性进行一个较为详细的判断,这个属性是text或者数组,看图
可以看出这个流程,如果新老节点都相同,但只有它们身上的数组不一样,例如我只想更改老节点中子节点的某些属性,那此时就需要对新老节点中的子数组进行精细化比较,这个比较也是最为复杂的
这里就要涉及到 “四个命中查找” 有关的理解
图片来自于[尚硅谷]
这里简单理解一下,我们会首先比较两个子数组中上锚点指向的元素是否相同,如果相同,新旧中的上锚点会同时往下走一个单位长度,此时比较为 “新前与旧前”
如果不相同,则会让新老数组中下锚点指向的元素进行对比,看看是否相同,此时比较为 “新后与旧后”,如果此时比较相同,则新老的下锚点会往同时上走一个单位长度
如果比较不同,则会再进行对比,这一次的对比为新数组中下锚点指向的元素与旧节点上锚点指向的元素对比,看看两者是否相同,如果相同,则新元素的下锚点向上走一个单位长度,老节点的上锚点会往下走一个单位长度,此时比较为 “新后与旧前”
如果还不同,则会让新元素的上锚点指向的元素与旧节点的下锚点指向的元素进行比较,看看是否相同,如果相同,则锚点移动顺序与上面类似,稍后会进行总结,此时为“新前与旧后”
如果四种命中查找都没实现,则会进行一个for循环来实现新老节点的有关更替
在编程中,默认把上锚点设置为新老数组第一个元素的索引值,把下锚点设置为新老数组的最后一个元素
然后就可以根据这四种查找机制编写相应的逻辑代码,因代码量巨大,需要的评论区dd
总结
掌握好虚拟dom和diff算法的概念,以及运用的背景,了解相关的实现步骤,可以有效的提升逻辑思维