Vue之虚拟DOM和diff算法

首先介绍一下snabbdom,snabbdom是著名的虚拟DOM库,是diff算法的鼻祖,Vue源码借鉴了snabbdom。

1、什么是虚拟DOM

虚拟DOM是用JavaScript对象描述DOM的层次结构。DOM中的一切属性都在虚拟DOM中有对应的属性。本质上是JS 和 DOM 之间的一个映射缓存虚拟DOM就是为了提高页面渲染性能。

要点:虚拟 DOM 是 JS 对象;虚拟 DOM 是对真实 DOM 的描述

为什么要使用虚拟DOM?

用JS对象模拟DOM节点的好处是,页面的更新可以先全部反映在JS对象(虚拟DOM)上,操作内存中的JS对象的速度显然要更快,等更新完成后,再将最终的JS对象映射成真实的DOM,交由浏览器去绘制。

diff发生在虚拟DOM上。diff算法是在新虚拟DOM和老虚拟DOM进行diff(精细化比对),实现最小量更新,最后反映到真正的DOM上。

1)最小量更新。key是vnode节点的唯一标识,告诉了diff算法,更改前后他们是同一个节点。

2)只有是同一个虚拟节点,才进行精细化比较,否则就暴力删除旧的、插入新的。

3)只进行同层比较,不会进行跨层比较。

2、h函数

我们前面知道diff算法发生在虚拟DOM上,而虚拟DOM是如何实现的呢?实际上虚拟DOM是有一个个虚拟节点组成。

h函数用来产生虚拟节点(vnode)。虚拟节点有如下的属性:

1)sel: 标签类型,例如 p、div;

2)data: 标签上的数据,例如 style、class、data-*;

3)children :子节点;

4) text: 文本内容;

5)elm:虚拟节点绑定的真实 DOM 节点;

通过h函数的嵌套,从而得到虚拟DOM树。

 我们编写了一个低配版的h函数,必须传入3个参数,重载较弱。

 * 形态1:h('div', {}, '文字')

 * 形态2:h('div', {}, [])

 * 形态3:h('div', {}, h())

首先定义vnode节点,实际上就是把传入的参数合成对象返回。

然后编写h函数,根据第三个参数的不同进行不同的响应。

3、patch函数

如何定义是同一个节点呢?旧节点的key要和新节点的key相同选择器也相同

当调用patch函数时,会传入旧、新节点。首先我们判断旧节点oldVnode是否是虚拟节点,如果传入的不是虚拟节点是DOM节点,我们需要进行包装成虚拟节点,即调用vnode函数进行转化。

然后判断oldVnode和newVnode是不是同一个节点,如果是则进行精细化比较(这个后面再完成);若不是,则将新节点创建为DOM,然后添加到页面中,并移除旧节点。

patch函数

createElement函数用来创建节点,将vnode节点创建为DOM。若vnode节点中存在嵌套,我们需要递归调用createElement完成子节点的创建。若为文本或undefined,则为直接转换为DOM。

createElement函数

如果oldVnode和newVnode是同一个节点,我们需要继续进行判断比较。首先判断oldVnode和newVnode是同一个对象,是则什么都不做,若不是,

判断newVnode有没有text属性,有则判断text相不相同,不同则用新的text属性代替;

若newVnode没有text属性,意味着有newVnode有children,再判断oldVnode有没有children,没有(意味着有oldVnode有text),清空oldVnode的text,将newVnode的children添加到DOM中;

若oldVnode有children,则需要进行diff了(后面再续)。

4、diff算法

当我们进行比较的过程中,我们采用的4种命中查找策略:

1)新前与旧前:命中则指针同时往后移动。

2)新后与旧后:命中则指针同时往前移动。

3)新后与旧前:命中则涉及节点移动,那么新后指向的节点,移到旧后之后。

4)新前与旧后:命中则涉及节点移动,那么新前指向的节点,移到旧前之前。

命中上述4种一种就不在命中判断了,如果没有命中,就需要循环来寻找,移动到旧前之前。直到while(新前<=新后&&旧前<=就后)不成立则完成。

如果是新节点先循环完毕,如果老节点中还有剩余节点(旧前和旧后指针中间的节点),说明他们是要被删除的节点。

如果是旧节点先循环完毕,说明新节点中有要插入的节点。

当新老VNode节点的start相同时,直接patchVnode,同时新老VNode节点的开始索引都加 1

当新老VNode节点的end相同时,同样直接patchVnode,同时新老VNode节点的结束索引都减 1

当老VNode节点的start和新VNode节点的end相同时,这时候在patchVnode后,还需要将当前真实dom节点移动到oldEndVnode的后面,同时老VNode节点开始索引加 1,新VNode节点的结束索引减 1

当老VNode节点的end和新VNode节点的start相同时,这时候在patchVnode后,还需要将当前真实dom节点移动到oldStartVnode的前面,同时老VNode节点结束索引减 1,新VNode节点的开始索引加 1

如果都不满足以上四种情形,那说明没有相同的节点可以复用,则会分为以下两种情况:

从旧的VNode为key值,对应index序列为value值的哈希表中找到与newStartVnode一致key的旧的VNode节点,再进行patchVnode,同时将这个真实dom移动到oldStartVnode对应的真实dom的前面

调用createElm创建一个新的dom节点放到当前newStartIdx的位置。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容