美文网首页Js让前端飞Web 前端开发
写一个自己的虚拟DOM(三)

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

作者: 蚊子爸爸 | 来源:发表于2017-12-04 12:51 被阅读105次

    如何检测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是一种典型的数据结构+算法的实现。
    我最近也是感触颇深,其实就目前的前端框架而言,就是成熟的数据结构+算法的一种实现,另外加上一些软件工程学。这也是我最近的瓶颈,所以我打算去认真学一学数据结构和算法。
    欢迎讨论。

    相关文章

      网友评论

      • Katherine的小世界:学习学习了
      • 明天的天明:思路清晰,不错
        蚊子爸爸:谢谢老哥~
      • 小文文呀:还好我不叫蚊子了
        蚊子爸爸:我刚才以为你是路人,看了你主页才知道原来是你,哈哈,你怎么找到这里的?
      • 阡陌夕殇:文中代码 updateElement 方法少了 index 参数
        蚊子爸爸:@阡陌夕殇 可以啊,这个代码还是少考虑了一种情况,不过这几篇文章主要目的不是实现一个完善的虚拟DOM,而是想用最简单的方式说明虚拟DOM的实质。随便转随便转。
        阡陌夕殇:@蚊子爸爸 这段代码确实比较坳,不过慢慢想还是能想清楚的,思路确实很清晰。我打算把你这三篇文章整理为一篇文档可以吗?会在上面注明 【原文链接】
        蚊子爸爸:哇,真的是,我粘贴代码的时候给弄错了。赶紧加上。

      本文标题:写一个自己的虚拟DOM(三)

      本文链接:https://www.haomeiwen.com/subject/dnkobxtx.html