亚洲免费在线视频-亚洲啊v-久久免费精品视频-国产精品va-看片地址-成人在线视频网

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

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

瀏覽:126日期:2023-01-30 08:38:24

patch的流程

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

判斷兩個(gè)節(jié)點(diǎn)是否相同

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

key相同 標(biāo)簽類型相同 注釋節(jié)點(diǎn)標(biāo)識(shí)相同,都是注釋節(jié)點(diǎn),或者都不是注釋節(jié)點(diǎn) data的值狀態(tài)相同,或者都有值,或者都沒值

function sameVnode (a, b) {// 判斷兩個(gè)VNode節(jié)點(diǎn)是否是同一個(gè)節(jié)點(diǎn) return ( a.key === b.key && // key相同 ( a.tag === b.tag && // tag相同 a.isComment === b.isComment && // 注釋節(jié)點(diǎn)標(biāo)識(shí)相同 isDef(a.data) === isDef(b.data) && // data值狀態(tài)相同 sameInputType(a, b) // input的type相同 ) )}

patch方法

patch判斷流程如下:

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

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

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

a) 舊節(jié)點(diǎn)不是DOM(組件節(jié)點(diǎn)),且新舊節(jié)點(diǎn)相同 執(zhí)行patchVnode b) 舊節(jié)點(diǎn)是DOM元素或者兩個(gè)節(jié)點(diǎn)不相同 創(chuàng)建新節(jié)點(diǎn)DOM,銷毀舊節(jié)點(diǎn)以及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é)點(diǎn)以及DOM元素 } else if (isDef(oldVnode.tag)) { invokeDestroyHook(oldVnode); } } } invokeInsertHook(vnode, insertedVnodeQueue, isInitialPatch); return vnode.elm }}

patchVnode方法

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

具體流程如下:

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

直接返回不處理

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

a)都存在子節(jié)點(diǎn),新舊節(jié)點(diǎn)的子節(jié)點(diǎn)數(shù)組引用不同(oldCh !== ch) updateChildren b)新節(jié)點(diǎn)有子節(jié)點(diǎn),舊節(jié)點(diǎn)沒有 1)查重子節(jié)點(diǎn)(key) 2)如果舊節(jié)點(diǎn)是文本節(jié)點(diǎn),先清空文本 3)創(chuàng)建子節(jié)點(diǎn)DOM元素 c)舊節(jié)點(diǎn)有子節(jié)點(diǎn),新節(jié)點(diǎn)沒有 移除子節(jié)點(diǎn)以及DOM d)舊節(jié)點(diǎn)是文本節(jié)點(diǎn) 清除文本 c)如果新節(jié)點(diǎn)是文本節(jié)點(diǎn),并且和舊節(jié)點(diǎn)文本不相同 則直接替換文本內(nèi)容。 d)其他(新節(jié)點(diǎn)是文本節(jié)點(diǎn),并且和舊節(jié)點(diǎn)相同) 不處理

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é)點(diǎn)的子節(jié)點(diǎn)。方法定義了以下變量(updateChildren的節(jié)點(diǎn)都表示的是子節(jié)點(diǎn)):

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

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

具體流程如下:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

移除舊起始和結(jié)尾節(jié)點(diǎn)以及他們之間的節(jié)點(diǎn)的DOM(從舊起始節(jié)點(diǎn)到舊結(jié)尾節(jié)點(diǎn),可能存在處理過的節(jié)點(diǎn),但處理過已被置為undefined)

function updateChildren (parentElm, oldCh, newCh, insertedVnodeQueue, removeOnly) { var oldStartIdx = 0;// 表示當(dāng)前正在處理的舊起始節(jié)點(diǎn)序號(hào) var newStartIdx = 0;// 表示當(dāng)前正在處理的新起始節(jié)點(diǎn)序號(hào) var oldEndIdx = oldCh.length - 1;// 表示當(dāng)前正在處理的舊結(jié)尾節(jié)點(diǎn)序號(hào) var oldStartVnode = oldCh[0];// 表示當(dāng)前正在處理的舊起始節(jié)點(diǎn) var oldEndVnode = oldCh[oldEndIdx];// 表示當(dāng)前正在處理的舊結(jié)尾節(jié)點(diǎn) var newEndIdx = newCh.length - 1;// 表示當(dāng)前正在處理的新結(jié)尾節(jié)點(diǎn)序號(hào) var newStartVnode = newCh[0];// 表示當(dāng)前正在處理的新起始節(jié)點(diǎn) var newEndVnode = newCh[newEndIdx];// 表示當(dāng)前正在處理的新結(jié)尾節(jié)點(diǎn) 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é)點(diǎn)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é)點(diǎn),節(jié)點(diǎn)下面標(biāo)識(shí)起始和結(jié)尾節(jié)點(diǎn)(即正在處理的節(jié)點(diǎn))。右邊表示當(dāng)前的DOM。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

到此這篇關(guān)于vue頁(yè)面更新patch的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)vue 更新patch內(nèi)容請(qǐng)搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: Vue
相關(guān)文章:
主站蜘蛛池模板: 男人天堂视频在线观看 | 日本不卡一区二区三区在线观看 | 免费播放美女一级毛片 | 成年女人免费看片 | 国内一级特黄女人精品片 | 国产99视频在线观看 | 欧美一级久久久久久久大片 | 国产午夜精品理论片免费观看 | 欧美一区二区日韩一区二区 | 一级女性黄 色生活片 | 韩国免费毛片在线看 | 日本一区二区三区四区无限 | 美国一级毛片免费看 | 久久亚洲一级毛片 | 国产91无套剧情在线播放 | 久久久久久久国产a∨ | 99在线视频免费观看 | 99热碰| 德国女人一级毛片免费 | 特级a欧美做爰片毛片 | 久久久久国产精品免费 | 久久99国产精一区二区三区! | 国产一区亚洲二区三区 | 欧美在线观看www | 黄色一级网址 | 97在线观看 | 我要看欧美精品一级毛片 | 久久九九爱 | 日韩国产在线观看 | 玖玖啪| 日本特黄特色 | 91在线一区二区三区 | 男人干女人的视频 | 中文字幕视频网 | 欧美一区永久视频免费观看 | 日本高清视频在线观看 | 亚洲经典在线中文字幕 | 欧美巨乳在线观看 | 9久久免费国产精品特黄 | 99re在线精品视频 | 久久久久久福利 |