当前位置: 首页 > Web前端 > HTML

Vue源码学习-虚拟DOM+Diff算法

时间:2023-03-29 12:30:46 HTML

Vue浣跨敤铏氭嫙DOM+Diff绠楁硶鍑忓皯浜咲OM鎿嶄綔娆℃暟锛屽ぇ澶ф彁鍗囦簡鎬ц兘锛屾墍浠ヤ粖澶╁氨璇︾粏璇磋Vue杩欓儴鍒嗙殑瀹炵幇閫昏緫锛屽笇鏈涘彲浠ュ府鍔╄繕涓嶄簡瑙h繖閮ㄥ垎鐨勬湅鍙嬩簡瑙h繖閮ㄥ垎锛岀函鎵嬪伐鍒朵綔锛屽笇鏈涘悇浣嶆湅鍙嬬偣璧炴敮鎸侊紒棣栧厛鎴戜滑瑕佹槑纭竴鐐癸紝vnode浠h〃杩欐淇敼鍚庢柊鐢熸垚鐨勮櫄鎷熻妭鐐癸紝oldVnode浠h〃褰撳墠鐪熷疄DOM缁撴瀯瀵瑰簲鐨勮櫄鎷熻妭鐐广€傚洜姝わ紝鎴戜滑鍩轰簬vnode杩涜鏇存柊锛岄€氳繃oldVnode杩欎釜缁撴瀯浣撴潵鎿嶄綔鐪熷疄鐨凞OM銆倂node鍜宱ldVnode閮戒笉浼氭敼鍙橈紝鍙細鏀瑰彉鐪熸鐨凞OM缁撴瀯銆俻atchVue鍦ㄧ涓€娆℃覆鏌撴洿鏂版暟鎹殑鏃跺€欙紝浼氳皟鐢╛update鏂规硶锛岃€宊update鏂规硶鐨勬牳蹇冨氨鏄皟鐢╲m.__patch__鏂规硶锛屾墍浠ユ垜浠厛浠巔atch鏂规硶璇磋捣銆俻atch鏂规硶涓殑閫昏緫姣旇緝澶嶆潅銆傝繖閲屾垜浠彧鐪嬩富杩涚▼閮ㄥ垎銆傚ぇ鑷存祦绋嬪涓嬶細functionpatch(oldVnode,vnode,hydrating,removeOnly,parentElm,refElm){if(isUndef(oldVnode)){/*鍒涘缓鏂拌妭鐐规椂oldVnode鏈畾涔?/isInitialPatch=truecreateElm(vnode,insertedVnodeQueue,parentElm,refElm)}else{/*鏍囪鏃Node鏄惁鏈塶odeType*/constisRealElement=isDef(oldVnode.nodeType)if(!isRealElement&&sameVnode(oldVnode,vnode)){/*鐩稿悓鏃惰妭鐐癸紝鐩存帴淇敼鐜版湁鑺傜偣*/patchVnode(oldVnode,vnode,insertedVnodeQueue,removeOnly)}else{if(isRealElement){oldVnode=emptyNodeAt(oldVnode)}//鍦ㄨ鍥句腑鐨勬棫鑺傜偣鏃佽竟鎻掑叆constoldElm=oldVnode.elmconstparentElm=nodeOps.parentNode(oldElm)createElm(vnode,insertedVnodeQueue,oldElm._leaveCb?null:parentElm,nodeOps.nextSibling(oldElm))if(isDef(parentElm)){/*鍒犻櫎鏃ц妭鐐?/removeVnodes(parentElm,[oldVnode],0,0)}elseif(isDef(oldVnode.tag)){/*Invokedestroyhook*/invokeDestroyHook(oldVnode)}}}returnvnode.elm}杩欓噷鏈変竴涓猧sRealElement鏉ヨ瘑鍒玱ldVnode鏄惁鏈塶odeType,涓€涓猲odeType琛ㄧず杩欐槸涓€涓湡姝g殑dom鑺傜偣銆傚皢emptyNodeAt杞崲涓簐Nodepatch浣跨敤浜嗕袱涓噸瑕佺殑鏂规硶锛屼竴涓槸createElm锛屽彟涓€涓槸patchVnode銆俢reateElmcreateElm鐨勪綔鐢ㄦ槸閫氳繃涓€涓櫄鎷熻妭鐐瑰垱寤轰竴涓湡瀹炵殑DOM锛屽苟鎻掑叆鍒板畠鐨勭埗鑺傜偣涓€備富瑕佹祦绋嬪涓嬶細functioncreateElm(vnode,insertedVnodeQueue,parentElm,refElm,nested){/*鍒涘缓缁勪欢鑺傜偣*/if(createComponent(vnode,insertedVnodeQueue,parentElm,refElm)){return}constdata=vnode.鏁版嵁constchildren=vnode.childrenconsttag=vnode.tagif(isDef(tag)){vnode.elm=vnode.ns?nodeOps.createElementNS(vnode.ns,tag):nodeOps.createElement(tag,vnode)//鍒涘缓dom鑺傜偣setScope(vnode)if(__WEEX__){//...}else{createChildren(vnode,children,insertedVnodeQueue)if(isDef(data)){invokeCreateHooks(vnode,insertedVnodeQueue)}insert(parentElm,vnode.elm,refElm)}}elseif(isTrue(vnode.isComment)){vnode.elm=nodeOps.createComment(vnode.text)鎻掑叆(parentElm,vnode.elm,refElm)}else{vnode.elm=nodeOps.createTextNode(vnode.text)insert(parentElm,vnode.elm,refElm)}}createComponent鍙湁褰搗node鏄竴涓粍浠舵椂鎵嶄細杩斿洖true銆傝繖閮ㄥ垎鍚庨潰浼氬垎鏋愩€俢reateChildren鍏跺疄灏辨槸閬嶅巻瀛愯櫄鑺傜偣锛岄€掑綊璋冪敤createElm銆傞亶鍘嗚繃绋嬩腑锛寁node.elm浼氫綔涓虹埗瀹瑰櫒鐨凞OM鑺傜偣浼犲叆銆傜敱浜庢槸閫掑綊璋冪敤锛屽瓙鍏冪礌浼氬厛璋冪敤insert锛屾墍浠ユ暣涓獀node鏍戣妭鐐圭殑鎻掑叆椤哄簭鏄厛瀛╁瓙锛岀劧鍚庢槸鐖舵瘝銆俻atchVnodepatchVnode鐨勪富瑕佹祦绋嬪拰涓昏浠g爜濡備笅锛歠unctionpatchVnode(oldVnode,vnode,insertedVnodeQueue,removeOnly){/*濡傛灉涓や釜VNode鑺傜偣鐩稿悓锛岀洿鎺ヨ繑鍥?/if(oldVnode===vnode){return}/*濡傛灉鏂版棫VNode閮芥槸闈欐€佺殑锛屽苟涓斿畠浠殑key鐩稿悓锛堜唬琛ㄥ悓涓€涓妭鐐癸級锛屽苟涓旀柊鐨刅Node琚厠闅嗘垨鑰呮爣璁颁簡涓€娆★紙鏍囪涓簐-once灞炴€э紝鍙覆鏌撲竴娆★級锛岄偅涔堝彧闇€瑕佹洿鎹lm鍜宑omponentInstance銆?/if(isTrue(vnode.isStatic)&&isTrue(oldVnode.isStatic)&&vnode.key===oldVnode.key&&(isTrue(vnode.isCloned)||isTrue(vnode.isOnce))){vnode.elm=oldVnode.elmvnode.componentInstance=oldVnode.componentInstancereturn}constelm=vnode.elm=oldVnode.elmconstoldCh=oldVnode.childrenconstch=vnode.children/*濡傛灉杩欎釜VNode鑺傜偣娌℃湁鏂囨湰*/if(isUndef(vnode.text)){if(isDef(oldCh)&&isDef(ch)){/*鏂拌€佽妭鐐归兘鏈塩hildren瀛愯妭鐐癸紝鐒跺悗瀵瑰瓙鑺傜偣杩涜diff鎿嶄綔锛岃皟鐢╱pdateChildren*/if(oldCh!==ch)updateChildren(elm,oldCh,ch,insertedVnodeQueue,removeOnly)}elseif(isDef(ch)){/*濡傛灉鑰佽妭鐐规病鏈夊瓙鑺傜偣锛屾柊鑺傜偣鏈夊瓙鑺傜偣锛屽厛娓呯┖elm鐨勬枃鏈唴瀹癸紝鐒跺悗灏嗗瓙鑺傜偣娣诲姞鍒板綋鍓嶈妭鐐筺ode*/if(isDef(oldVnode.text))nodeOps.setTextContent(elm,'')addVnodes(elm,null,ch,0,ch.length-1,insertedVnodeQueue)}elseif(isDef(oldCh)){/*褰撴柊鑺傜偣娌℃湁瀛愯妭鐐规椂涓旀棫鑺傜偣鏈夊瓙鑺傜偣锛岀Щ闄le鐨勬墍鏈夊瓙鑺傜偣*/removeVnodes(elm,oldCh,0,oldCh.length-1)}elseif(isDef(oldVnode.text)){/*褰撴柊鏃ц妭鐐归兘娌℃湁瀛愯妭鐐规椂锛屽彧鏄枃鏈浛鎹紝鍥犱负鏂拌妭鐐瑰湪杩欎釜閫昏緫鏂囨湰涓嶅瓨鍦紝鎵€浠ョ洿鎺ュ幓鎺塭le鐨勬枃鏈?/nodeOps.setTextContent(elm,'')}}elseif(oldVnode.text!==vnode.text){/*褰撴柊鏃ф枃鏈琻odes涓嶅悓锛岀洿鎺ユ浛鎹histext*/nodeOps.setTextContent(elm,vnode.text)}}鍏跺疄鏈夊嚑绉嶆儏鍐碉細鏂版棫vnodes閮芥湁瀛愯妭鐐癸紝瀛愯妭鐐筪iff鍒版柊vnode,浣嗘棫鐨剉node娌℃湁锛屾墍浠ユ坊鍔犲畠銆傛棫鐨剉node鏈夛紝鏂扮殑vnode娌℃湁锛屽垹鎺夈€傚鏋滄湁鏂囨湰灞炴€э紝鍒欐浛鎹㈡枃鏈€備富瑕佺湅閲岄潰璋冪敤鐨剈pdateChildren鏂规硶銆倁pdateChildren鍦ㄦ暣涓猵atchVnode杩囩▼涓紝鏈€澶嶆潅鐨勬槸updateChildren鏂规硶锛屾瘮杈冩柊鏃ц櫄鎷焠ode瀛愯妭鐐广€傚浣曟瘮杈冩柊鏃у瓙鑺傜偣鍒楄〃锛熷緢绠€鍗曪紝寰幆锛佸惊鐜亶鍘嗘柊瀛愯妭鐐瑰垪琛紝骞跺湪鏃у瓙鑺傜偣鍒楄〃涓煡鎵炬瘡涓€椤癸紝鐒跺悗杩涜澶勭悊銆備絾閫氬父鎯呭喌涓嬶紝骞朵笉鏄墍鏈夌殑瀛愯妭鐐圭殑浣嶇疆閮戒細鏀瑰彉銆備妇涓緥瀛愷煂帮紝鐜板湪鏈変竴涓垪琛紝鎴戜滑瀵瑰畠鐨勫ぇ閮ㄥ垎鎿嶄綔閮芥槸澧炲姞涓€涓」鐩紝鍒犻櫎涓€涓」鐩垨鑰呮敼鍙樺叾涓殑涓€涓€傚ぇ澶氭暟鑺傜偣鐨勪綅缃槸涓嶅彉鐨勶紝鍙互棰勬祴鐨勶紝涓嶉渶瑕佹瘡娆¢兘鍘诲惊鐜悳绱紝鎵€浠ue浣跨敤浜嗘洿蹇殑鎼滅储鏂瑰紡锛屽ぇ澶ф彁楂樹簡鎬ц兘銆傜畝鍗曟潵璇村氨鏄ご灏炬瘮杈冿細newhead锛氭柊瀛愯妭鐐瑰垪琛ㄤ腑鎵€鏈夋湭澶勭悊鐨勭涓€涓妭鐐筼ldhead锛氭棫瀛愯妭鐐瑰垪琛ㄤ腑鎵€鏈夋湭澶勭悊鐨勭涓€涓妭鐐筺ewtail锛氭柊瀛愬垪琛ㄤ腑鎵€鏈夋湭澶勭悊鐨勬渶鍚庝竴涓妭鐐筼ldtail:oldchildlist涓墍鏈夋湭澶勭悊鐨刲ast鑺傜偣Vue浣跨敤鍥涗釜鍙橀噺newStartIdx,newEndIdx,oldStartIdx,oldEndIdx鏉ユ爣璇嗘柊鏃уご灏捐妭鐐广€?.濡傛灉鏂板ご鍜岃€佸ご鏄悓涓€涓妭鐐癸紝浠栦滑鐨勪綅缃篃鏄竴鏍风殑锛屾墍浠ュ彧闇€瑕佹洿鏂拌妭鐐癸紝涓嶇敤绉诲姩鎿嶄綔銆?.鏂板熬宸村拰鏃у熬宸村鏋滄柊灏惧反鍜屾棫灏惧反鏄悓涓€涓妭鐐癸紝瀹冧滑鐨勪綅缃篃鏄竴鏍风殑锛屾墍浠ュ彧闇€瑕佹洿鏂拌妭鐐癸紝涓嶇敤绉诲姩銆?銆佸鏋滄柊灏惧拰鏃уご鏄悓涓€涓妭鐐癸紝鐢变簬浣嶇疆涓嶅悓锛岄櫎浜嗘洿鏂颁箣澶栵紝杩橀渶瑕佽繘琛岀Щ鍔ㄦ搷浣溿€傞鍏堟垜浠鏄庣‘涓€鐐癸紝鏇存柊鏄熀浜巚node鐨勶紝鑰宱ldVnode浠h〃鐨勬槸鐪熷疄鐨凞OM缁撴瀯锛屾墍浠ユ垜浠渶瑕佹洿鏂扮湡瀹炵殑DOM鏉ユ洿鏂皁ldVnode銆傝繖閲岃娉ㄦ剰锛屼竴瀹氳绉诲埌鎵€鏈夋湭澶勭悊鑺傜偣鐨勫悗闈紝鍥犱负鏂板熬鏄柊瀛愯妭鐐瑰垪琛ㄤ腑鏈€鍚庝竴涓湭澶勭悊鐨勮妭鐐广€?.鏂板ご鍜屾棫灏惧鏋滄柊澶村拰鏃у熬鏄悓涓€涓妭鐐癸紝鐢变簬浣嶇疆涓嶅悓锛岄櫎浜嗘洿鏂颁箣澶栵紝杩橀渶瑕佽繘琛岀Щ鍔ㄦ搷浣溿€傜Щ鍔ㄩ€昏緫鍜屼笂闈㈢殑鏂板熬鏃уご澶ц嚧鐩稿悓锛屾棫灏剧Щ鍔ㄥ埌鎵€鏈夋湭澶勭悊鐨勮妭鐐逛箣鍓嶃€傚鏋滅粡杩囪繖鍥涙姣旇緝锛屽湪old瀛愯妭鐐瑰垪琛ㄤ腑浠嶇劧娌℃湁鎵惧埌鐩稿悓鐨勮妭鐐癸紝鍒欏厛鐢╫ldVnode鐢熸垚涓€涓猭ey锛宬ey涓簅ldVnode锛寁alue涓哄搴旂殑hash琛▄key0:0,key1:1}涓嬫爣锛岀劧鍚庝娇鐢ㄦ柊琛ㄥご锛坣ewStartVnode锛夌殑key鍦ㄥ搱甯岃〃涓煡鎵俱€傚鏋滄壘鍒板搴旂殑锛屽垯鍒ゆ柇鏄惁鏄痵ameVnodes锛氬鏋滄槸锛屽垯璇存槑鍦ㄦ棫鐨勫瓙鑺傜偣鍒楄〃涓壘鍒颁簡鐩稿悓鐨勮妭鐐癸紝鏇存柊鑺傜偣鎿嶄綔銆傛渶鍚庤繕闇€瑕佺粰杩欎釜鑰佽妭鐐硅祴鍊紆ndefined锛岄伩鍏嶄互鍚庨噸澶嶆瘮杈冨悓涓€涓猭ey銆傚鏋滀笉鏄紝閭d箞鏈夊彲鑳芥爣绛句笉涓€鏍凤紝鎴栬€呰緭鍏ョ殑绫诲瀷鍙樹簡锛岀洿鎺ユ柊寤轰竴涓妭鐐广€傚鏋滃湪鍝堝笇琛ㄤ腑娌℃湁鎵惧埌瀵瑰簲鐨勶紝寰堢畝鍗曪紝鐩存帴鏂板缓涓€涓妭鐐广€傞亶鍘嗙粨鏉熸椂锛屼細鍑虹幇涓ょ鎯呭喌锛歰ldStartIdx>oldEndIdx锛岃鏄庢棫鑺傜偣閬嶅巻缁撴潫锛屾帴涓嬫潵瑕佹坊鍔犲墿浣欑殑鏂拌妭鐐癸紝鐒跺悗涓€涓€鍒涘缓锛屾坊鍔犲埌鐪熸鐨勫ぇ鏁欏爞銆俷ewStartIdx>newEndIdx锛岃鏄庢柊鑺傜偣閬嶅巻缁撴潫锛岄偅涔堝墿涓嬬殑鏃ц妭鐐硅鍒犻櫎锛屽垹闄ゅ嵆鍙€傞€昏緫寰堟竻鏅帮紝浣犳槸涓嶆槸瑙夊緱涔熷緢绠€鍗曞憿锛佹渶鍚庯紝鎴戞槸鍓嶇鏂颁汉鍛ㄦ檽闃炽€傛垜鍐欐枃绔犺褰曡嚜宸卞湪鏃ュ父宸ヤ綔涓亣鍒扮殑闂鍜屾墍瀛﹀埌鐨勪笢瑗匡紝浠ユ鏉ユ彁楂樿嚜宸便€傚鏋滄偍瑙夊緱鏈枃瀵规偍鏈夌敤锛岃鐐逛釜璧為紦鍔变竴涓嬪惂~