溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

vue怎么實現diff算法

發布時間:2022-03-07 15:29:42 來源:億速云 閱讀:230 作者:iii 欄目:web開發

這篇文章主要介紹“vue怎么實現diff算法”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“vue怎么實現diff算法”文章能幫助大家解決問題。

模塊路徑:src\core\vdom\patch.js

問題:diff算法主要是對相同節點的子節點進行的比較和更新,也就是相同級別節點的比較算法。dom對比更新,本著盡量減少dom的銷毀和重建,所以diff算法盡量先移動,后增刪

過程分析

比較舊VNode節點oldCh和新VNode節點newCh,創建四個索引進行比較:

兩個索引oldStartIdx(舊VNode開始位置)和oldEndIdx(舊VNode結束位置)分別指向oldCh的開始和結束下標

兩個索引newStartIdx(新VNode開始位置)和newEndIdx(新VNode開始位置)分別指向newCh的開始和結束下標

并創建四個索引位置對應的VNode節點oldStartVnode,oldEndVnode,newStartVnode,newEndVnode,代碼如下:

     let oldStartIdx = 0

    let newStartIdx = 0

    let oldEndIdx = oldCh.length - 1

    let oldStartVnode = oldCh[0]

    let oldEndVnode = oldCh[oldEndIdx]

    let newEndIdx = newCh.length - 1

    let newStartVnode = newCh[0]

    let newEndVnode = newCh[newEndIdx]

    let oldKeyToIdx, idxInOld, vnodeToMove, refElm

根據索引遍歷節點   while(oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx):

首先是異常情況判斷,然后根據當前節點情況判斷是否以下四種情況

if (isUndef(oldStartVnode)) {undefined

        oldStartVnode = oldCh[++oldStartIdx] // Vnode has been moved left

      } else if (isUndef(oldEndVnode)) {undefined

        oldEndVnode = oldCh[--oldEndIdx]

 }

遍歷判斷1: 如果oldStartIdx的節點和newStartIdx節點相同,去patchVnode判斷節點內部是否相同,oldStartIdx++,newStartIdx++     (patchVnode是詳細比較兩個節點內容的函數)

else if (sameVnode(oldStartVnode, newStartVnode)) {undefined

   // 兩個節點相同,直接將該VNode節點進行patchVnode

   patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx)

   oldStartVnode = oldCh[++oldStartIdx]

    newStartVnode = newCh[++newStartIdx]

 }

遍歷判斷2: 如果oldEndIdx的節點和newEndIdx節點相同,去patchVnode判斷節點內部是否相同,oldEndIdx--,newEndIdx--

else if (sameVnode(oldEndVnode, newEndVnode)) {undefined

        // 兩個節點相同,直接將該VNode節點進行patchVnode

        patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx)

        oldEndVnode = oldCh[--oldEndIdx]

        newEndVnode = newCh[--newEndIdx]

 }

遍歷判斷3: 如果oldStartIdx的節點和newEndIdx節點相同,去patchVnode判斷節點內部是否相同,oldStartIdx++,newEndIdx--,把oldStartIdx對應節點向右移動

else if (sameVnode(oldStartVnode, newEndVnode)) { // Vnode moved right

        // 進行patchVnode,把oldStartVnode移到最后

       patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx)

       //canMove移動oldStartVnode節點到oldEndVnode后面

        canMove && nodeOps.insertBefore(parentElm, oldStartVnode.elm, nodeOps.nextSibling(oldEndVnode.elm))

        oldStartVnode = oldCh[++oldStartIdx]

        newEndVnode = newCh[--newEndIdx]

      }

遍歷判斷4: 如果oldEndIdx的節點和newStartIdx節點相同,去patchVnode判斷節點內部是否相同,oldEndIdx--,newStartIdx++,把oldEndIdx對應節點向左移動

else if (sameVnode(oldEndVnode, newStartVnode)) { // Vnode moved left

        // oldEndVnode 和 newStartVnode相同,進行patchVnode

        patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx)

        //,把oldEndVnode 移動到最前面

       canMove && nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm)

        oldEndVnode = oldCh[--oldEndIdx]

        newStartVnode = newCh[++newStartIdx]

      }

遍歷判斷5: 如果上述四種情況都不存在,則用新VNode當前的newStartVnode去舊VNode里找(盡量不新建dom,找到了就移動,找不到再新建)

如果找到了,則調用patchVnode去比較詳細內容,并且移動這個節點到newStartIdx位置,

如果沒找到,則創建新節點并插入

else {undefined

        // 以上四種情況都不滿足

        // newStartVnode依次和舊的節點進行比較

        // 從新的節點開通取一個,去老節點中查找相同節點

        // 先找新開始節點的key和老節點相同的索引,如果沒找到再通過sameVnode找

        if (isUndef(oldKeyToIdx)) oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx)

        idxInOld = isDef(newStartVnode.key)

          ? oldKeyToIdx[newStartVnode.key]

          : findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx)

          // 如果沒找到,創建節點并插入到最前面

        if (isUndef(idxInOld)) { // 沒找到 New element

          createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx)

        } else { //找到了  獲取要移動的老節點

          vnodeToMove = oldCh[idxInOld]

          if (sameVnode(vnodeToMove, newStartVnode)) {undefined

            // 兩節點相同,執行patchVnode

            patchVnode(vnodeToMove, newStartVnode, insertedVnodeQueue, newCh, newStartIdx)

            oldCh[idxInOld] = undefined

             //并將找到的舊節點移動到最前面

            canMove && nodeOps.insertBefore(parentElm, vnodeToMove.elm, oldStartVnode.elm)

          } else {// 兩節點不同,創建新元素

            createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx)

          }

        }

        newStartVnode = newCh[++newStartIdx]//移動索引

      }

 遍歷完成(走出while循環時說明肯定有新/舊節點被遍歷完了):

結束判斷1:當結束時 oldStartIdx > oldEndIdx ,說明舊節點遍歷完了,新節點沒遍歷完,則說明新節點比老節點多,把newStartIdx >到newEndIdx直接的節點插入到老節點后面

結束判斷2:當結束時 newStartIdx > newEndIdx ,說明新節點遍歷完了,舊節點沒遍歷完,則說明老節點比新節點多,把的oldStartIdx到oldEndIdx之間的節點刪除

關于“vue怎么實現diff算法”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

vue
AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女