vue页面更新patch的-mile米乐体育

本文将为大家详细介绍“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前面

    • 将相同的旧节点置为undefinedoldch[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的”这一关键问题有了从实践层面最深刻的体会,具体使用情况还需要大家自己动手实践使用过才能领会,如果想阅读更多相关内容的文章,欢迎关注恰卡编程网行业资讯频道!

展开全文

vue

内容来源于互联网和用户投稿,文章中一旦含有米乐app官网登录的联系方式务必识别真假,本站仅做信息展示不承担任何相关责任,如有侵权或涉及法律问题请联系米乐app官网登录删除

最新文章

网站地图