写一个自己的虚拟DOM(三)

如何检测DOM变化

现在已经可以把一个虚拟DOM产生一个真实DOM了,是时候想一下如何比较两个虚拟DOM了。我们需要一个算法,用来比较两个虚拟DOM树,然后根据需要来将新旧不同反映到真实DOM上。

  1. 首先要做的是,写一changed个函数来检测两个node是否是一样的(是否有变化),有变化返回true,没变化返回false。
function changed(node1,node2){
    return typeof node1 !== typeof node2 || typeof node1 ==='string' && node1!==node2 || node1.type !==node2.type;
}
  1. 假设有这样两个虚拟DOM:
const a = (
  <ul class="list">
    <li>item 1</li>
    <li>item 2</li>
  </ul>
);

const b =(
  <ul class="list">
    <li>item 1</li>
    <button>click me</button>
  </ul>
)

这两个虚拟DOM如果经过changed()方法来判断的话,肯定是不同的,那么现在的目标是找出哪里有不同

对照着上面的两个虚拟DOM,先理一下人脑的思路:

a. 先比较ul节点,两个节点相同。
b. 比较children元素,第一个children元素是li元素
c. 比较这个li元素,li元素的元素类型相同(type都是li,还记得第一篇文章里面提到的虚拟DOM数据结构是什么样子吗?)
d. 比较li节点的children属性,两个都是string, item1 ,相同,然后跳出来。
e. 比较ul的children第二个元素,发现a是li,b是button,发现不同。

这是一个人脑的思路,如果把这个流程转变至程序代码的话,很显然,又是需要递归思想。不过找不同只是第一步,第二步要做的是,找到不同以后,把不相同的地方给做出相应的改变

于是我写一个updateElement()方法,这个方法会拿着两个虚拟DOM进行处理,首先它会寻找两个虚拟DOM不同的地方,然后会确定位置,进行真实DOM的生成和替换。

function updateElement($parent,newNode,oldNode,index=0){
    if(changed(newNode,oldNode)){//如果两个node的根节点就不同,那就直接替换
        $parent.replaceChild(createElement(newNode),$parent.childNodes[index]);
    }else if(newNode.type){//确认一下这个节点有没有type属性,如果没有,代表是textNode,直接略过
        for(let i=0;i<newNode.children.length||i<oldNode.children.length;i++){
            updateElement($parent.childNodes[index],newNode.children[i],oldNode.children[i],i)
        }
    }
}

上面这段代码逻辑上比较不好理解,如果可以的话,各位请务必自己深入去思考一下,这段代码我可是写了一个多小时才写出来的。

现在就可以顺利运行了,虽然还有缺陷,可是最简单的虚拟DOM原理可以略知一二了,请看我的在线代码

总结

这一套流程中,最值得学习的地方是虚拟DOM的实质以及整个思路,不知道各位会不会有这种感觉,其实虚拟DOM是一种典型的数据结构+算法的实现。
我最近也是感触颇深,其实就目前的前端框架而言,就是成熟的数据结构+算法的一种实现,另外加上一些软件工程学。这也是我最近的瓶颈,所以我打算去认真学一学数据结构和算法。
欢迎讨论。

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

推荐阅读更多精彩内容

  • 第1章 简介 第2章 DOM节点的创建 2-1 DOM创建节点及节点属性 通过JavaScript可以很方便的获...
    mo默22阅读 804评论 0 8
  • DOM创建节点及节点属性 通过JavaScript可以很方便的获取DOM节点,从而进行一系列的DOM操作。但实际上...
    阿r阿r阅读 1,007评论 0 9
  • 参考文章:深度剖析:如何实现一个Virtual DOM 算法 作者:戴嘉华React中一个没人能解释清楚的问题——...
    waka阅读 5,956评论 0 21
  • 简介网络浏览器很可能是使用最广的软件。在这篇入门文章中,我将会介绍它们的幕后工作原理。我们会了解到,从您在地址栏输...
    wengjq阅读 2,015评论 2 15
  • 1.今天有一客户两夫妻老婆老是说贵,犹豫不决一直在说便宜点便宜点,而他老公了没说什么看她老婆这要买不买的,最后发脾...
    cf89阅读 1,516评论 0 0