最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

vue頁面更新patch的實現(xiàn)示例

 更新時間:2020年03月25日 10:11:40   作者:阿正  
這篇文章主要介紹了vue頁面更新patch的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

patch的流程

組件頁面渲染時,將render返回的新vnode(新節(jié)點)和組件實例保存的vnode(舊節(jié)點)作為參數(shù),調(diào)用patch方法,更新DOM。

判斷兩個節(jié)點是否相同

處理過程中,需要判斷節(jié)點是否相同。相同節(jié)點需要滿足以下條件:

  • key相同
  • 標簽類型相同
  • 注釋節(jié)點標識相同,都是注釋節(jié)點,或者都不是注釋節(jié)點
  • data的值狀態(tài)相同,或者都有值,或者都沒值
function sameVnode (a, b) {// 判斷兩個VNode節(jié)點是否是同一個節(jié)點
  return (
    a.key === b.key && // key相同
    (
      a.tag === b.tag && // tag相同
      a.isComment === b.isComment && // 注釋節(jié)點標識相同
      isDef(a.data) === isDef(b.data) && // data值狀態(tài)相同
      sameInputType(a, b) // input的type相同
    )
  )
}

patch方法

patch判斷流程如下:

a) 如果新節(jié)點為空,此時舊節(jié)點存在(組件銷毀時),調(diào)用舊節(jié)點destroy生命周期函數(shù)

b) 如果舊節(jié)點為空,根據(jù)新節(jié)點創(chuàng)建DOM

c) 其他(如果新舊節(jié)點都存在)

  • a) 舊節(jié)點不是DOM(組件節(jié)點),且新舊節(jié)點相同
    • 執(zhí)行patchVnode
  • b) 舊節(jié)點是DOM元素或者兩個節(jié)點不相同
    • 創(chuàng)建新節(jié)點DOM,銷毀舊節(jié)點以及DOM。
function patch (oldVnode, vnode, hydrating, removeOnly) {
  if (isUndef(vnode)) {
   if (isDef(oldVnode)) { invokeDestroyHook(oldVnode); }
   return
  }
  ...
  if (isUndef(oldVnode)) {
   isInitialPatch = true;// 組件初始加載
   createElm(vnode, insertedVnodeQueue);
  } else {
   var isRealElement = isDef(oldVnode.nodeType);
   if (!isRealElement && sameVnode(oldVnode, vnode)) {
    patchVnode(oldVnode, vnode, insertedVnodeQueue, null, null, removeOnly);
   } else {
    ...
    var oldElm = oldVnode.elm;
    var parentElm = nodeOps.parentNode(oldElm);// 獲取父元素
    // create new node
    createElm(
     vnode,
     insertedVnodeQueue,
     oldElm._leaveCb ? null : parentElm,
     nodeOps.nextSibling(oldElm)// 獲取緊跟的弟弟元素
    );
    if (isDef(parentElm)) {
     removeVnodes(parentElm, [oldVnode], 0, 0);// 銷毀舊節(jié)點以及DOM元素
    } else if (isDef(oldVnode.tag)) {
     invokeDestroyHook(oldVnode);
    }
   }
  }
  invokeInsertHook(vnode, insertedVnodeQueue, isInitialPatch);
  return vnode.elm
 }
}

patchVnode方法

當兩個節(jié)點相同時,執(zhí)行patchVnode方法。在處理各種情況之前,會將舊節(jié)點elm屬性值賦值給新節(jié)點的elm屬性,保持elm保持一致。

具體流程如下:

a)如果新舊節(jié)點完全相同(引用相同 oldVnode === vnode)

  • 直接返回不處理

b) 如果新節(jié)點不是文本節(jié)點

  • a)都存在子節(jié)點,新舊節(jié)點的子節(jié)點數(shù)組引用不同(oldCh !== ch)
    • updateChildren
  • b)新節(jié)點有子節(jié)點,舊節(jié)點沒有
    • 1)查重子節(jié)點(key)
    • 2)如果舊節(jié)點是文本節(jié)點,先清空文本
    • 3)創(chuàng)建子節(jié)點DOM元素
  • c)舊節(jié)點有子節(jié)點,新節(jié)點沒有
    • 移除子節(jié)點以及DOM
  • d)舊節(jié)點是文本節(jié)點
    • 清除文本
  • c)如果新節(jié)點是文本節(jié)點,并且和舊節(jié)點文本不相同
    • 則直接替換文本內(nèi)容。
  • d)其他(新節(jié)點是文本節(jié)點,并且和舊節(jié)點相同)
    • 不處理
 function patchVnode (
  oldVnode,
  vnode,
  insertedVnodeQueue,
  ownerArray,
  index,
  removeOnly
 ) {
  if (oldVnode === vnode) {
   return
  }
  ...
  if (isUndef(vnode.text)) {
   if (isDef(oldCh) && isDef(ch)) {
    if (oldCh !== ch) { updateChildren(elm, oldCh, ch, insertedVnodeQueue, removeOnly); }
   } else if (isDef(ch)) {
    if (process.env.NODE_ENV !== 'production') {
     checkDuplicateKeys(ch);
    }
    if (isDef(oldVnode.text)) { nodeOps.setTextContent(elm, ''); }
    addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue);
   } else if (isDef(oldCh)) {
    removeVnodes(elm, oldCh, 0, oldCh.length - 1);
   } else if (isDef(oldVnode.text)) {
    nodeOps.setTextContent(elm, '');
   }
  } else if (oldVnode.text !== vnode.text) {
   nodeOps.setTextContent(elm, vnode.text);
  }
  ...
 }

updateChildren方法

updateChildren方法處理相同新舊節(jié)點的子節(jié)點。方法定義了以下變量(updateChildren的節(jié)點都表示的是子節(jié)點):

  var oldStartIdx = 0;// 表示當前正在處理的舊起始節(jié)點序號
  var newStartIdx = 0;// 表示當前正在處理的新起始節(jié)點序號
  var oldEndIdx = oldCh.length - 1;// 表示當前正在處理的舊結(jié)尾節(jié)點序號
  var oldStartVnode = oldCh[0];// 表示當前正在處理的舊起始節(jié)點
  var oldEndVnode = oldCh[oldEndIdx];// 表示當前正在處理的舊結(jié)尾節(jié)點
  var newEndIdx = newCh.length - 1;// 表示當前正在處理的新結(jié)尾節(jié)點序號
  var newStartVnode = newCh[0];// 表示當前正在處理的新起始節(jié)點
  var newEndVnode = newCh[newEndIdx];// 表示當前正在處理的新結(jié)尾節(jié)點
  var oldKeyToIdx, // 尚未處理的舊節(jié)點key值映射
    idxInOld, // 與新節(jié)點key值相同的舊節(jié)點序號
    vnodeToMove, // 與新節(jié)點key值相同的舊節(jié)點
    refElm;// 指向當前正在處理的新結(jié)尾節(jié)點的后一個節(jié)點(已處理)的DOM元素

根據(jù)新舊節(jié)點的對比結(jié)果,更新DOM元素,此過程并不改變新舊節(jié)點的排序。序號指向正在處理的節(jié)點,分別是新舊節(jié)點的起始和結(jié)尾節(jié)點。對比過程以新起始節(jié)點為主導,對比方向是由兩側(cè)向中間。優(yōu)先比對新舊節(jié)點的起始節(jié)點和結(jié)尾節(jié)點,再查找與新起始節(jié)點相同的且未處理的舊節(jié)點。當舊節(jié)點全部處理完(舊起始和結(jié)尾序號重疊),此時新節(jié)點可能未處理完,就添加新節(jié)點DOM元素。當新節(jié)點全部處理完(新起始和結(jié)尾序號重疊),可能存在舊節(jié)點,就刪除舊節(jié)點DOM元素。

具體流程如下:

新舊子節(jié)點的起始序號不大于結(jié)尾序號時,執(zhí)行以下流程:

a)如果舊子節(jié)點兩側(cè)存在undefined節(jié)點

  • 舊起始節(jié)點undefined,oldStartVnode = oldCh[++oldStartIdx]
  • 舊結(jié)尾節(jié)點undefined,oldEndVnode = oldCh[--oldEndIdx]

b)新舊子節(jié)點的起始節(jié)點相同(前后比較)

  • patchVNode更新DOM內(nèi)容
  • oldStartVnode = oldCh[++oldStartIdx]
  • newStartVnode = newCh[++newStartIdx]

c)新舊子節(jié)點的結(jié)尾節(jié)點相同(前后比較)

  • patchVNode更新DOM內(nèi)容
  • oldEndVnode = oldCh[--oldEndIdx]
  • newEndVnode = newCh[--newEndIdx]

d)舊起始節(jié)點和新結(jié)尾節(jié)點相同(前后比較)

  • patchVNode更新DOM內(nèi)容
  • 將舊起始節(jié)點DOM添加到舊結(jié)尾節(jié)點DOM前面
  • oldStartVnode = oldCh[++oldStartIdx]
  • newEndVnode = newCh[--newEndIdx]

e)舊結(jié)尾節(jié)點和新起始節(jié)點相同(前后比較)

  • patchVNode更新DOM內(nèi)容
  • 將舊結(jié)尾節(jié)點DOM添加到舊起始節(jié)點DOM前面
  • oldEndVnode = oldCh[--oldEndIdx]
  • newStartVnode = newCh[++newStartIdx]

f)其他(緩存尚未處理的舊節(jié)點key值,依此判斷舊節(jié)點中是否存在和新起始節(jié)點相同的節(jié)點)

  • a)尚未處理的舊節(jié)點中不存在與新起始節(jié)點相同的節(jié)點
    • 創(chuàng)建新節(jié)點DOM并添加到舊起始節(jié)點DOM的前面
    • newStartVnode = newCh[++newStartIdx]
  • b)舊節(jié)點中存在與新起始節(jié)點key相同的節(jié)點
    • a)舊節(jié)點中存在與新起始節(jié)點相同的節(jié)點
      • patchVode
      • 將相同的舊節(jié)點DOM添加到舊起始節(jié)點DOM前面
      • 將相同的舊節(jié)點置為undefinedoldCh[idxInOld] = undefined
      • newStartVnode = newCh[++newStartIdx]
    • b)key相同,但標簽類型不同的節(jié)點
      • 創(chuàng)建新節(jié)點DOM并添加到舊起始節(jié)點DOM的前面
      • newStartVnode = newCh[++newStartIdx]

循環(huán)結(jié)束

a)如果舊節(jié)點遍歷完(oldStartIdx > oldEndIdx

  • 把剩余未處理新節(jié)點DOM添加到上一個新結(jié)尾節(jié)點DOM前面(從新起始節(jié)點到新結(jié)尾節(jié)點,都未處理過)

b)如果新節(jié)點遍歷完(newStartIdx > newEndIdx

  • 移除舊起始和結(jié)尾節(jié)點以及他們之間的節(jié)點的DOM(從舊起始節(jié)點到舊結(jié)尾節(jié)點,可能存在處理過的節(jié)點,但處理過已被置為undefined)
function updateChildren (parentElm, oldCh, newCh, insertedVnodeQueue, removeOnly) {
  var oldStartIdx = 0;// 表示當前正在處理的舊起始節(jié)點序號
  var newStartIdx = 0;// 表示當前正在處理的新起始節(jié)點序號
  var oldEndIdx = oldCh.length - 1;// 表示當前正在處理的舊結(jié)尾節(jié)點序號
  var oldStartVnode = oldCh[0];// 表示當前正在處理的舊起始節(jié)點
  var oldEndVnode = oldCh[oldEndIdx];// 表示當前正在處理的舊結(jié)尾節(jié)點
  var newEndIdx = newCh.length - 1;// 表示當前正在處理的新結(jié)尾節(jié)點序號
  var newStartVnode = newCh[0];// 表示當前正在處理的新起始節(jié)點
  var newEndVnode = newCh[newEndIdx];// 表示當前正在處理的新結(jié)尾節(jié)點
  var oldKeyToIdx, idxInOld, vnodeToMove, refElm;
  ...
  while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
   if (isUndef(oldStartVnode)) {
    oldStartVnode = oldCh[++oldStartIdx]; // Vnode has been moved left
   } else if (isUndef(oldEndVnode)) {
    oldEndVnode = oldCh[--oldEndIdx];
   } else if (sameVnode(oldStartVnode, newStartVnode)) {
    patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx);
    oldStartVnode = oldCh[++oldStartIdx];
    newStartVnode = newCh[++newStartIdx];
   } else if (sameVnode(oldEndVnode, newEndVnode)) {
    patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx);
    oldEndVnode = oldCh[--oldEndIdx];
    newEndVnode = newCh[--newEndIdx];
   } else if (sameVnode(oldStartVnode, newEndVnode)) { // Vnode moved right
    patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx);
    canMove && nodeOps.insertBefore(parentElm, oldStartVnode.elm, nodeOps.nextSibling(oldEndVnode.elm));
    oldStartVnode = oldCh[++oldStartIdx];
    newEndVnode = newCh[--newEndIdx];
   } else if (sameVnode(oldEndVnode, newStartVnode)) { // Vnode moved left
    patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx);
    canMove && nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm);
    oldEndVnode = oldCh[--oldEndIdx];
    newStartVnode = newCh[++newStartIdx];
   } else {
    if (isUndef(oldKeyToIdx)) { oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx); }// 緩存尚未處理的舊節(jié)點key值
    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)) {
      patchVnode(vnodeToMove, newStartVnode, insertedVnodeQueue, newCh, newStartIdx);
      oldCh[idxInOld] = undefined;
      canMove && nodeOps.insertBefore(parentElm, vnodeToMove.elm, oldStartVnode.elm);
     } else {
      // same key but different element. treat as new element
      createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx);
     }
    }
    newStartVnode = newCh[++newStartIdx];
   }
  }
  if (oldStartIdx > oldEndIdx) {
   refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm;
   addVnodes(parentElm, refElm, newCh, newStartIdx, newEndIdx, insertedVnodeQueue);
  } else if (newStartIdx > newEndIdx) {
   removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx);
  }
 }

updateChildren的示例:

1.左邊表示新舊節(jié)點,節(jié)點下面標識起始和結(jié)尾節(jié)點(即正在處理的節(jié)點)。右邊表示當前的DOM。

2.新節(jié)點的起始和結(jié)尾節(jié)點與舊節(jié)點的起始和結(jié)尾節(jié)點互不相同,并且在舊節(jié)點中未找到與新起始節(jié)點(新節(jié)點f)相同的節(jié)點。
所以創(chuàng)建節(jié)點f的DOM并添加到舊起始節(jié)點(舊節(jié)點a)DOM的前面,然后新起始節(jié)點序號加1,表示新節(jié)點f已處理,當前正在處理新起始節(jié)點c。

3.新節(jié)點的起始和結(jié)尾節(jié)點與舊節(jié)點的起始和結(jié)尾節(jié)點互不相同,但在舊節(jié)點中找到與新起始節(jié)點(節(jié)點c)相同的節(jié)點。
所以將舊節(jié)點c的DOM添加到舊起始節(jié)點(舊節(jié)點a)DOM的前面,舊節(jié)點c置空,然后新起始節(jié)點序號加1,表示新節(jié)點c已處理,當前正在處理新起始節(jié)點e。

4.新起始節(jié)點(新節(jié)點e)和舊結(jié)尾節(jié)點(舊節(jié)點e)相同。更新舊節(jié)點e的DOM內(nèi)容,并將舊節(jié)點e的DOM移動到舊起始節(jié)點(舊節(jié)點a)DOM的前面,舊結(jié)尾節(jié)點序號減1,新起始節(jié)點加1,表示新舊節(jié)點e已處理,當前正在處理的是新起始節(jié)點g和舊結(jié)尾節(jié)點d。

5.新結(jié)尾節(jié)點(新節(jié)點d)和舊結(jié)尾節(jié)點(舊節(jié)點d)相同。僅更新舊節(jié)點d的DOM內(nèi)容。新結(jié)尾節(jié)點序號減1,舊結(jié)尾節(jié)點序號減1,表示新舊節(jié)點d已處理,當前正在處理的是新結(jié)尾節(jié)點g和舊結(jié)尾節(jié)點c。由于舊節(jié)點c為空,則舊結(jié)尾節(jié)點為b。

6.新節(jié)點的起始和結(jié)尾節(jié)點與舊節(jié)點的起始和結(jié)尾節(jié)點互不相同,并且在舊節(jié)點中未找到與新起始節(jié)點(新節(jié)點g)相同的節(jié)點。
所以創(chuàng)建節(jié)點g的DOM并添加到舊起始節(jié)點(舊節(jié)點a)DOM的前面,然后新起始節(jié)點序號加1,表示新節(jié)點g已處理,當前正在處理新起始節(jié)點d。

7.由于新起始和結(jié)尾節(jié)點序號重疊,新節(jié)點已經(jīng)處理完畢,存在尚未處理的舊節(jié)點,則移除未處理的舊節(jié)點DOM。

8.結(jié)束,最終的DOM。

到此這篇關(guān)于vue頁面更新patch的實現(xiàn)示例的文章就介紹到這了,更多相關(guān)vue 更新patch內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • vue.js學習筆記之v-bind和v-on解析

    vue.js學習筆記之v-bind和v-on解析

    這篇文章主要介紹了vue.js學習筆記之v-bind和v-on解析,v-bind 指令用于響應(yīng)地更新 HTML 特征,v-on 指令用于監(jiān)聽DOM事件,文中還給大家提到了v-bind,v-on的縮寫,感興趣的朋友參考下吧
    2018-05-05
  • vue項目中添加單元測試的方法

    vue項目中添加單元測試的方法

    這篇文章主要介紹了vue項目中添加單元測試的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-07-07
  • vue @ ~ 相對路徑 路徑別名設(shè)置方式

    vue @ ~ 相對路徑 路徑別名設(shè)置方式

    這篇文章主要介紹了vue @ ~ 相對路徑 路徑別名設(shè)置方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Vue2面試考點之$nextTick原理解析

    Vue2面試考點之$nextTick原理解析

    平時在獲取真實DOM的時候獲取不到最新的DOM元素,使用$nextTick就可以,那為什么$nextTick就可以獲取到最新的DOM元素呢,本文就來帶著這兩個問題來解析一下nextTick的原理
    2023-05-05
  • 關(guān)于Less在Vue中的使用方法介紹

    關(guān)于Less在Vue中的使用方法介紹

    最近發(fā)現(xiàn)好多小伙伴在面試的過程中會問到vue如何使用less和scss,所以下面這篇文章主要給大家介紹了關(guān)于Less在Vue中的使用方法,需要的朋友可以參考下
    2023-10-10
  • Vue使用el-tree 懶加載進行增刪改查功能的實現(xiàn)

    Vue使用el-tree 懶加載進行增刪改查功能的實現(xiàn)

    這篇文章主要介紹了Vue使用el-tree 懶加載進行增刪改查,以懶加載的形式展示,目錄根據(jù)需求需要有新增 編輯 刪除 操作以及操作后的刷新樹結(jié)構(gòu),具體實現(xiàn)代碼跟隨小編一起看看吧
    2021-08-08
  • vue文件樹組件使用詳解

    vue文件樹組件使用詳解

    這篇文章主要為大家詳細介紹了vue文件樹組件的使用方法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • vue3.0 上手體驗

    vue3.0 上手體驗

    vue3.0 beta 版本已經(jīng)發(fā)布有一段時間了,今天這篇文章就帶大家體驗一下,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-09-09
  • 淺談nuxtjs校驗登錄中間件和混入(mixin)

    淺談nuxtjs校驗登錄中間件和混入(mixin)

    這篇文章主要介紹了淺談nuxtjs校驗登錄中間件和混入(mixin),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • vue3中不支持.sync語法糖的解決方法

    vue3中不支持.sync語法糖的解決方法

    在 Vue 3 中,.sync 修飾符已經(jīng)被移除,在 Vue 2 中,.sync 修飾符是一個語法糖,用于簡化子組件和父組件之間的雙向數(shù)據(jù)綁定,那么本文將給大家介紹一下vue3中不支持.sync語法糖的解決方法,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-01-01

最新評論

苍溪县| 象山县| 翼城县| 饶平县| 本溪| 永嘉县| 九江县| 武定县| 称多县| 连南| 丹凤县| 大荔县| 富平县| 富民县| 云林县| 抚松县| 阿拉善盟| 白山市| 南陵县| 博野县| 丁青县| 安宁市| 涞源县| 镇平县| 方山县| 阳西县| 闽侯县| 关岭| 文昌市| 怀安县| 龙口市| SHOW| 耒阳市| 体育| 台南市| 安阳县| 财经| 牡丹江市| 冀州市| 东平县| 华容县|