vue页面更新patch的-亚博电竞手机版
本文将为大家详细介绍“vue页面更新patch的”,内容步骤清晰详细,细节处理妥当,而小编每天都会更新不同的知识点,希望这篇“vue页面更新patch的”能够给你意想不到的收获,请大家跟着小编的思路慢慢深入,具体内容如下,一起去收获新知识吧。
vue的优点
vue具体轻量级框架、简单易学、双向数据绑定、组件化、数据和结构的分离、虚拟dom、运行速度快等优势,vue中页面使用的是局部刷新,不用每次跳转页面都要请求所有数据和dom,可以大大提升访问速度和用户体验。
patch的流程
组件页面渲染时,将render返回的新vnode(新节点)和组件实例保存的vnode(旧节点)作为参数,调用patch方法,更新dom。
判断两个节点是否相同
处理过程中,需要判断节点是否相同。相同节点需要满足以下条件:
key相同
标签类型相同
注释节点标识相同,都是注释节点,或者都不是注释节点
data的值状态相同,或者都有值,或者都没值
functionsamevnode(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。
functionpatch(oldvnode,vnode,hydrating,removeonly){ if(isundef(vnode)){ if(isdef(oldvnode)){invokedestroyhook(oldvnode);} return } ... if(isundef(oldvnode)){ isinitialpatch=true;//组件初始加载 createelm(vnode,insertedvnodequeue); }else{ varisrealelement=isdef(oldvnode.nodetype); if(!isrealelement&&samevnode(oldvnode,vnode)){ patchvnode(oldvnode,vnode,insertedvnodequeue,null,null,removeonly); }else{ ... varoldelm=oldvnode.elm; varparentelm=nodeops.parentnode(oldelm);//获取父元素 //createnewnode createelm( vnode, insertedvnodequeue, oldelm._leavecb?null:parentelm, nodeops.nextsibling(oldelm)//获取紧跟的弟弟元素 ); if(isdef(parentelm)){ removevnodes(parentelm,[oldvnode],0,0);//销毁旧节点以及dom元素 }elseif(isdef(oldvnode.tag)){ invokedestroyhook(oldvnode); } } } invokeinserthook(vnode,insertedvnodequeue,isinitialpatch); returnvnode.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)其他(新节点是文本节点,并且和旧节点相同)
不处理
functionpatchvnode( 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);} }elseif(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); }elseif(isdef(oldch)){ removevnodes(elm,oldch,0,oldch.length-1); }elseif(isdef(oldvnode.text)){ nodeops.settextcontent(elm,''); } }elseif(oldvnode.text!==vnode.text){ nodeops.settextcontent(elm,vnode.text); } ... }
updatechildren方法
updatechildren方法处理相同新旧节点的子节点。方法定义了以下变量(updatechildren的节点都表示的是子节点):
varoldstartidx=0;//表示当前正在处理的旧起始节点序号 varnewstartidx=0;//表示当前正在处理的新起始节点序号 varoldendidx=oldch.length-1;//表示当前正在处理的旧结尾节点序号 varoldstartvnode=oldch[0];//表示当前正在处理的旧起始节点 varoldendvnode=oldch[oldendidx];//表示当前正在处理的旧结尾节点 varnewendidx=newch.length-1;//表示当前正在处理的新结尾节点序号 varnewstartvnode=newch[0];//表示当前正在处理的新起始节点 varnewendvnode=newch[newendidx];//表示当前正在处理的新结尾节点 varoldkeytoidx,//尚未处理的旧节点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相同的节点
创建新节点dom并添加到旧起始节点dom的前面
newstartvnode = newch[ newstartidx]
patchvode
将相同的旧节点dom添加到旧起始节点dom前面
将相同的旧节点置为undefined
oldch[idxinold] = undefined
newstartvnode = newch[ newstartidx]
a)旧节点中存在与新起始节点相同的节点
b)key相同,但标签类型不同的节点
循环结束
a)如果旧节点遍历完(oldstartidx > oldendidx
)
把剩余未处理新节点dom添加到上一个新结尾节点dom前面(从新起始节点到新结尾节点,都未处理过)
b)如果新节点遍历完(newstartidx > newendidx
)
移除旧起始和结尾节点以及他们之间的节点的dom(从旧起始节点到旧结尾节点,可能存在处理过的节点,但处理过已被置为undefined)
functionupdatechildren(parentelm,oldch,newch,insertedvnodequeue,removeonly){ varoldstartidx=0;//表示当前正在处理的旧起始节点序号 varnewstartidx=0;//表示当前正在处理的新起始节点序号 varoldendidx=oldch.length-1;//表示当前正在处理的旧结尾节点序号 varoldstartvnode=oldch[0];//表示当前正在处理的旧起始节点 varoldendvnode=oldch[oldendidx];//表示当前正在处理的旧结尾节点 varnewendidx=newch.length-1;//表示当前正在处理的新结尾节点序号 varnewstartvnode=newch[0];//表示当前正在处理的新起始节点 varnewendvnode=newch[newendidx];//表示当前正在处理的新结尾节点 varoldkeytoidx,idxinold,vnodetomove,refelm; ... while(oldstartidx<=oldendidx&&newstartidx<=newendidx){ if(isundef(oldstartvnode)){ oldstartvnode=oldch[ oldstartidx];//vnodehasbeenmovedleft }elseif(isundef(oldendvnode)){ oldendvnode=oldch[--oldendidx]; }elseif(samevnode(oldstartvnode,newstartvnode)){ patchvnode(oldstartvnode,newstartvnode,insertedvnodequeue,newch,newstartidx); oldstartvnode=oldch[ oldstartidx]; newstartvnode=newch[ newstartidx]; }elseif(samevnode(oldendvnode,newendvnode)){ patchvnode(oldendvnode,newendvnode,insertedvnodequeue,newch,newendidx); oldendvnode=oldch[--oldendidx]; newendvnode=newch[--newendidx]; }elseif(samevnode(oldstartvnode,newendvnode)){//vnodemovedright patchvnode(oldstartvnode,newendvnode,insertedvnodequeue,newch,newendidx); canmove&&nodeops.insertbefore(parentelm,oldstartvnode.elm,nodeops.nextsibling(oldendvnode.elm)); oldstartvnode=oldch[ oldstartidx]; newendvnode=newch[--newendidx]; }elseif(samevnode(oldendvnode,newstartvnode)){//vnodemovedleft 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)){//newelement 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{ //samekeybutdifferentelement.treatasnewelement 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); }elseif(newstartidx>newendidx){ removevnodes(parentelm,oldch,oldstartidx,oldendidx); } }
updatechildren的示例:
1.左边表示新旧节点,节点下面标识起始和结尾节点(即正在处理的节点)。右边表示当前的dom。
2.新节点的起始和结尾节点与旧节点的起始和结尾节点互不相同,并且在旧节点中未找到与新起始节点(新节点f)相同的节点。所以创建节点f的dom并添加到旧起始节点(旧节点a)dom的前面,然后新起始节点序号加1,表示新节点f已处理,当前正在处理新起始节点c。
3.新节点的起始和结尾节点与旧节点的起始和结尾节点互不相同,但在旧节点中找到与新起始节点(节点c)相同的节点。所以将旧节点c的dom添加到旧起始节点(旧节点a)dom的前面,旧节点c置空,然后新起始节点序号加1,表示新节点c已处理,当前正在处理新起始节点e。
4.新起始节点(新节点e)和旧结尾节点(旧节点e)相同。更新旧节点e的dom内容,并将旧节点e的dom移动到旧起始节点(旧节点a)dom的前面,旧结尾节点序号减1,新起始节点加1,表示新旧节点e已处理,当前正在处理的是新起始节点g和旧结尾节点d。
5.新结尾节点(新节点d)和旧结尾节点(旧节点d)相同。仅更新旧节点d的dom内容。新结尾节点序号减1,旧结尾节点序号减1,表示新旧节点d已处理,当前正在处理的是新结尾节点g和旧结尾节点c。由于旧节点c为空,则旧结尾节点为b。
6.新节点的起始和结尾节点与旧节点的起始和结尾节点互不相同,并且在旧节点中未找到与新起始节点(新节点g)相同的节点。所以创建节点g的dom并添加到旧起始节点(旧节点a)dom的前面,然后新起始节点序号加1,表示新节点g已处理,当前正在处理新起始节点d。
7.由于新起始和结尾节点序号重叠,新节点已经处理完毕,存在尚未处理的旧节点,则移除未处理的旧节点dom。
8.结束,最终的dom。
如果你能读到这里,小编希望你对“vue页面更新patch的”这一关键问题有了从实践层面最深刻的体会,具体使用情况还需要大家自己动手实践使用过才能领会,如果想阅读更多相关内容的文章,欢迎关注恰卡编程网行业资讯频道!