电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

vue頁面更新patch的實現示例

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

patch的流程

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

判斷兩個節點是否相同

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

key相同 標簽類型相同 注釋節點標識相同,都是注釋節點,或者都不是注釋節點 data的值狀態相同,或者都有值,或者都沒值

function sameVnode (a, b) {// 判斷兩個VNode節點是否是同一個節點 return ( a.key === b.key && // key相同 ( a.tag === b.tag && // tag相同 a.isComment === b.isComment && // 注釋節點標識相同 isDef(a.data) === isDef(b.data) && // data值狀態相同 sameInputType(a, b) // input的type相同 ) )}

patch方法

patch判斷流程如下:

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

b) 如果舊節點為空,根據新節點創建DOM

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

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

patchVnode方法

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

具體流程如下:

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

直接返回不處理

b) 如果新節點不是文本節點

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

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方法處理相同新舊節點的子節點。方法定義了以下變量(updateChildren的節點都表示的是子節點):

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

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

具體流程如下:

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

a)如果舊子節點兩側存在undefined節點

舊起始節點undefined,oldStartVnode = oldCh[++oldStartIdx] 舊結尾節點undefined,oldEndVnode = oldCh[--oldEndIdx]

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

patchVNode更新DOM內容 oldStartVnode = oldCh[++oldStartIdx] newStartVnode = newCh[++newStartIdx]

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

patchVNode更新DOM內容 oldEndVnode = oldCh[--oldEndIdx] newEndVnode = newCh[--newEndIdx]

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

patchVNode更新DOM內容 將舊起始節點DOM添加到舊結尾節點DOM前面 oldStartVnode = oldCh[++oldStartIdx] newEndVnode = newCh[--newEndIdx]

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

patchVNode更新DOM內容 將舊結尾節點DOM添加到舊起始節點DOM前面 oldEndVnode = oldCh[--oldEndIdx] newStartVnode = newCh[++newStartIdx]

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

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

循環結束

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

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

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

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

function updateChildren (parentElm, oldCh, newCh, insertedVnodeQueue, removeOnly) { var oldStartIdx = 0;// 表示當前正在處理的舊起始節點序號 var newStartIdx = 0;// 表示當前正在處理的新起始節點序號 var oldEndIdx = oldCh.length - 1;// 表示當前正在處理的舊結尾節點序號 var oldStartVnode = oldCh[0];// 表示當前正在處理的舊起始節點 var oldEndVnode = oldCh[oldEndIdx];// 表示當前正在處理的舊結尾節點 var newEndIdx = newCh.length - 1;// 表示當前正在處理的新結尾節點序號 var newStartVnode = newCh[0];// 表示當前正在處理的新起始節點 var newEndVnode = newCh[newEndIdx];// 表示當前正在處理的新結尾節點 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); }// 緩存尚未處理的舊節點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.左邊表示新舊節點,節點下面標識起始和結尾節點(即正在處理的節點)。右邊表示當前的DOM。

vue頁面更新patch的實現示例

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

vue頁面更新patch的實現示例

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

vue頁面更新patch的實現示例

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

vue頁面更新patch的實現示例

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

vue頁面更新patch的實現示例

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

vue頁面更新patch的實現示例

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

vue頁面更新patch的實現示例

8.結束,最終的DOM。

vue頁面更新patch的實現示例

到此這篇關于vue頁面更新patch的實現示例的文章就介紹到這了,更多相關vue 更新patch內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: Vue
相關文章:
主站蜘蛛池模板: 污水/卧式/潜水/钻井/矿用/大型/小型/泥浆泵,价格,参数,型号,厂家 - 安平县鼎千泵业制造厂 | 拉力机-万能试验机-材料拉伸试验机-电子拉力机-拉力试验机厂家-冲击试验机-苏州皖仪实验仪器有限公司 | Trimos测长机_测高仪_TESA_mahr,WYLER水平仪,PWB对刀仪-德瑞华测量技术(苏州)有限公司 | 食品机械专用传感器-落料放大器-低价接近开关-菲德自控技术(天津)有限公司 | 焊接烟尘净化器__焊烟除尘设备_打磨工作台_喷漆废气治理设备 -催化燃烧设备 _天津路博蓝天环保科技有限公司 | 喷码机,激光喷码打码机,鸡蛋打码机,手持打码机,自动喷码机,一物一码防伪溯源-恒欣瑞达有限公司 | 细沙回收机-尾矿干排脱水筛设备-泥石分离机-建筑垃圾分拣机厂家-青州冠诚重工机械有限公司 | 板式换热器_板式换热器价格_管式换热器厂家-青岛康景辉 | 丹佛斯压力传感器,WISE温度传感器,WISE压力开关,丹佛斯温度开关-上海力笙工业设备有限公司 | 福兰德PVC地板|PVC塑胶地板|PVC运动地板|PVC商用地板-中国弹性地板系统专业解决方案领先供应商! 福建成考网-福建成人高考网 | 除湿机|工业除湿机|抽湿器|大型地下室车间仓库吊顶防爆除湿机|抽湿烘干房|新风除湿机|调温/降温除湿机|恒温恒湿机|加湿机-杭州川田电器有限公司 | 长沙中央空调维修,中央空调清洗维保,空气能热水工程,价格,公司就找维小保-湖南维小保环保科技有限公司 | 强效碱性清洗剂-实验室中性清洗剂-食品级高纯氮气发生器-上海润榕科学器材有限公司 | 玻璃钢格栅盖板|玻璃钢盖板|玻璃钢格栅板|树篦子-长沙川皖玻璃钢制品有限公司 | 东莞压铸厂_精密压铸_锌合金压铸_铝合金压铸_压铸件加工_东莞祥宇金属制品 | 杜甫仪器官网|实验室平行反应器|升降水浴锅|台式低温循环泵 | 箱式破碎机_移动方箱式破碎机/价格/厂家_【华盛铭重工】 | 滑石粉,滑石粉厂家,超细滑石粉-莱州圣凯滑石有限公司 | 全温度恒温培养摇床-大容量-立式-远红外二氧化碳培养箱|南荣百科 | 分轨 | 上传文件,即刻分离人声和伴奏 | 物流公司电话|附近物流公司电话上门取货 | 超声骨密度仪-骨密度检测仪-经颅多普勒-tcd仪_南京科进实业有限公司 | 影合社-影视人的内容合作平台 | 重庆磨床过滤机,重庆纸带过滤机,机床伸缩钣金,重庆机床钣金护罩-重庆达鸿兴精密机械制造有限公司 | 安徽净化工程设计_无尘净化车间工程_合肥净化实验室_安徽创世环境科技有限公司 | 专业甜品培训学校_广东糖水培训_奶茶培训_特色小吃培训_广州烘趣甜品培训机构 | 海南在线 海南一家| 食品级焦亚硫酸钠_工业级焦亚硫酸钠_焦亚硫酸钠-潍坊邦华化工有限公司 | 意大利Frascold/富士豪压缩机_富士豪半封闭压缩机_富士豪活塞压缩机_富士豪螺杆压缩机 | 泰来华顿液氮罐,美国MVE液氮罐,自增压液氮罐,定制液氮生物容器,进口杜瓦瓶-上海京灿精密机械有限公司 | 武汉宣传片制作-视频拍摄-企业宣传片公司-武汉红年影视 | 定制液氮罐_小型气相液氮罐_自增压液氮罐_班德液氮罐厂家 | 环氧树脂地坪漆_济宁市新天地漆业有限公司 | 工业机械三维动画制作 环保设备原理三维演示动画 自动化装配产线三维动画制作公司-南京燃动数字 聚合氯化铝_喷雾聚氯化铝_聚合氯化铝铁厂家_郑州亿升化工有限公司 | 净化板-洁净板-净化板价格-净化板生产厂家-山东鸿星新材料科技股份有限公司 | 质构仪_鱼糜弹性仪-上海腾拔仪器科技有限公司 | 污水处理设备,一体化泵站,一体化净水设备-「梦之洁环保设备厂家」 | 厌氧工作站-通用型厌氧工作站-上海胜秋科学仪器有限公司 | 压滤机-洗沙泥浆处理-压泥机-山东创新华一环境工程有限公司 | [品牌官网]贵州遵义双宁口腔连锁_贵州遵义牙科医院哪家好_种植牙_牙齿矫正_原华美口腔 | 吸污车_吸粪车_抽粪车_电动三轮吸粪车_真空吸污车_高压清洗吸污车-远大汽车制造有限公司 |