zoukankan      html  css  js  c++  java
  • vue更新dom的diff算法

    diff算法使只更新我们修改的那一小块dom而不要更新整个dom: 

    在采取diff算法比较新旧节点的时候,比较只会在同层级进行, 不会跨层级比较:

     判断是否是相同节点:

    function sameVnode (a, b) {
      return (
        a.key === b.key &&  // key值
        a.tag === b.tag &&  // 标签名
        a.isComment === b.isComment &&  // 是否为注释节点
        // 是否都定义了data,data包含一些具体信息,例如onclick , style
        isDef(a.data) === isDef(b.data) &&  
        sameInputType(a, b) // 当标签是<input>的时候,type必须相同
      )
    }

    如果两个节点是一样的,那么就深入检查他们的子节点。如果两个节点不一样那就可以直接替换oldVnode

    function patch (oldVnode, vnode) {
        // some code
        if (sameVnode(oldVnode, vnode)) {
            patchVnode(oldVnode, vnode)   // 相同节点打补丁
        } else {
            const oEl = oldVnode.el // 当前oldVnode对应的真实元素节点
            let parentEle = api.parentNode(oEl)  // 父元素
            createEle(vnode)  // 根据Vnode生成新元素
            if (parentEle !== null) {
                api.insertBefore(parentEle, vnode.el, api.nextSibling(oEl)) // 将新元素添加进父元素
                api.removeChild(parentEle, oldVnode.el)  // 移除以前的旧元素节点
                oldVnode = null
            }
        }
        // some code 
        return vnode
    }

    当我们确定两个节点相同之后我们会对两个节点执行patchVnode方法:

    patchVnode (oldVnode, vnode) {
        const el = vnode.el = oldVnode.el
        let i, oldCh = oldVnode.children, ch = vnode.children
        if (oldVnode === vnode) return
        if (oldVnode.text !== null && vnode.text !== null && oldVnode.text !== vnode.text) {
            api.setTextContent(el, vnode.text)
        }else {
            updateEle(el, vnode, oldVnode)
            if (oldCh && ch && oldCh !== ch) {
                updateChildren(el, oldCh, ch)
            }else if (ch){
                createEle(vnode) //create el's children dom
            }else if (oldCh){
                api.removeChildren(el)
            }
        }
    }

    这个函数做了以下事情:

    • 找到对应的真实dom,称为el
    • 判断VnodeoldVnode是否指向同一个对象,如果是,那么直接return
    • 如果他们都有文本节点并且不相等,那么将el的文本节点设置为Vnode的文本节点。
    • 如果oldVnode有子节点而Vnode没有,则删除el的子节点
    • 如果oldVnode没有子节点而Vnode有,则将Vnode的子节点真实化之后添加到el
    • 如果两者都有子节点,则执行updateChildren函数比较子节点,这一步很重要

    updateChildren

    不设key,newCh和oldCh只会进行头尾两端的相互比较,设key后,除了头尾两端的比较外,还会从用key生成的对象oldKeyToIdx中查找匹配的节点,所以为节点设置key可以更高效的利用dom。

    先进行4种比较:

    如果是oldS和E相同,那么真实dom中的第一个节点会移到最后;

    如果是oldE和S相同,那么真实dom中的最后一个节点会移到最前;

    如果oldS和S相同,会调用patchVnode方法,继续判断这两个节点的子节点,oldStartIndex,newStartIndex指向下个节点;

    如果oldE和E相同,会调用patchVnode方法,继续判断这两个节点的子节点,oldStartIndex,newStartIndex指向上个节点;

    如果以上都不匹配,就尝试在oldChildren中寻找跟newStartVnode具有相同key的节点,如果找不到相同key的节点,说明newStartVnode是一个新节点,就创建一个,然后把newStartVnode设置为下一个节点

    我们需要使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点,找到正确的位置区插入新的节点 

    如果以上都不行会依次比较如下:

    即把C更新成F,D更新成C,E更新成D,最后再插入E 

    原文:https://www.cnblogs.com/wind-lanyan/p/9061684.html

  • 相关阅读:
    WCF – System.ServiceModel.FaultException
    SSB – Connection handshake failed
    JQuery语法总结和注意事项
    删除指定目录及其子目录和文件
    Windows 7中还不能通过“HyperV管理器”连接HyperV Server 2008 R2服务器解决
    tomcat虚拟目录映射网络共享目录的问题
    Creating a Virtual Directory with a UNC Path (IIS 6.0)
    百度地图api根据地区名称反查其经纬度的实例
    远程管理server core上的hyperv
    ios5中使用Reachability的问题
  • 原文地址:https://www.cnblogs.com/xjy20170907/p/12802224.html
Copyright © 2011-2022 走看看