vue源碼解讀-組件Vnode的patch過程

目錄導(dǎo)航

在分析之前,先將例子進(jìn)行小小的改動旬迹,改動后的文件如下

? ? ? ? ? ? main.js文件


? ? ? ? app.vue文件


? ? ? ? 在components文件下新增child.vue俘闯,并在app.vue中引入


通過之前幾篇的分析我們知道炮捧,import vue執(zhí)行初始化構(gòu)建了vue類贫奠,new vue調(diào)用init方法判斷el存在執(zhí)行mount他膳,在mount過程中調(diào)用mountComponent并在該函數(shù)中定義渲染watcher,而在渲染watcher內(nèi)又調(diào)用了updateComponent函數(shù)绒窑,該函數(shù)首先拿到vue的渲染vnode棕孙,后調(diào)用update執(zhí)行patch,patch的過程其實(shí)就是遞歸調(diào)用原生dom方法去create和insert些膨,而在createElement過程中將根據(jù)類型生成不同的vnode蟀俊,也就是在new vue時指定的'el:#app'調(diào)用的是create-element,在子組件app patch時調(diào)用的create-component。通過上一節(jié)(組件的vnode)分析我們拿到了組件的Vnode订雾,它將作為_render函數(shù)的返回值肢预,也就是_update的入?yún)ⅲ虼舜a定位到src\core\instance\lifecycle.js下的


進(jìn)入update洼哎,該函數(shù)的入?yún)榻M件Vnode和false烫映,變量緩存的值如下


? ? ? ? ? ? a-vm即Vue沼本,因?yàn)閠his在es5中指向的是其調(diào)用者

? ? ? ? ? ? b-prevEl:如果當(dāng)前組件是子組件的話,那么其指向的父組件所對應(yīng)的dom锭沟,因?yàn)樵诖嬖诟附M件的時候抽兆,父組件的patch過程的返回值將被vm.$el緩存,而vm.$el同時又作為patch的參數(shù)傳入族淮,也就是說辫红,在patch之前vm.$el是有值的,換句話說祝辣,在update之前是有值的贴妻。因此我們向前查找mount過程,在mountComponent中向vm.$el掛載了值


而el則是在調(diào)用時傳入的蝙斜,因此繼續(xù)向上查找名惩,找到$mount


這里的el又是從上一級傳入的,因此繼續(xù)向前查找到init方法


我們發(fā)現(xiàn)乍炉,在調(diào)用mount方法時傳入了el參數(shù)绢片,而在app.vue中并未指定,因此為undefined岛琼,即prevEl=undefined

? ??????????c-prevVnode取得是vm._vnode底循,而vm._vnode在后邊保存的是vnode,因此我們需要找到new vue過程中的vnode是什么槐瑞,我們發(fā)現(xiàn)在組件init的過程中調(diào)用了


而在initRender中又執(zhí)行了


因此prevVnode=null

? ??????????d-restoreActiveInstance調(diào)用setActiveInstance


該函數(shù)首先保存了上一次的instance熙涤,而上一次是vue,接著又向activeInstance緩存了一份當(dāng)前組件的vm困檩,因此祠挫,prevActiveInstance 和 activeInstance實(shí)際上是父子關(guān)系,因此prevActiveInstance=vue悼沿,activeInstance=vm等舔,并返回一個函數(shù)

? ? ? ? ? ? e-vm._vnode=當(dāng)前的組件Vnode

代碼向下


由于prevVnode=null,因此走進(jìn)if判斷糟趾,執(zhí)行patch方法慌植,該方法入?yún)?/p>

(undefined,'組件Vnode'义郑,false蝶柿,false)

查找patch方法,該方法在src\platforms\web\runtime\index.js文件中被掛載到vue原型非驮,根據(jù)import引入路徑查找到patch


? ? a-isUndef(vnode)=false,跳過

? ? b-isUndef(oldVnode)交汤,由于oldVnode是undefined,故為true劫笙,進(jìn)入if判斷芙扎,調(diào)用createElm星岗,該方法入?yún)?/p>

(‘組件vnode’,[])


? ? ? ? a-vnode.elm=undefined,跳過

? ? ? ? b-調(diào)用createComponent方法,該方法入?yún)?/p>

('組件vnode',[],undefined,undefined)



從代碼可以看出纵顾,該函數(shù)會返回兩個值伍茄,一個是true,一個是undefined施逾。從注釋可以看出敷矫,返回true的前提是執(zhí)行了i,也就是i=i.hook汉额,因此核心是vnode.data是什么

我們在上一節(jié)(組件的vnode化)分析中得知曹仗,在構(gòu)建vue的vnode過程中,對app.vue進(jìn)行構(gòu)建并生成了一個組件對象蠕搜,該組件對象上掛載了data.hook

組件的vnode如下

因此i的值如下


i

? ? ? ? a-isDef(i)值為true怎茫,進(jìn)入判斷

? ? ? ? b-i?=?i.hook為true,i.hook.init為true妓灌,進(jìn)入判斷執(zhí)行init方法轨蛤;該方法在組件vnode化的過程中,在createComponent中調(diào)用installComponentHooks被添加到組件的hook上虫埂,因此調(diào)用的實(shí)際上是


? ? 該方法的入?yún)?/p>

('組件vnode',false)

a-vnode.data.keepAlive=false,代碼走向else祥山,調(diào)用createComponentInstanceForVnode方法


該方法入?yún)?/p>

('組件vnode',vm)

a-inlineTemplate為false,跳過

b-new?vnode.componentOptions.Ctor:打開vnode類定義


componentOptions是在生成vnode時傳入的參數(shù)掉伏,對應(yīng)的參數(shù)即在生成vnode時傳遞的如下


而Ctor則是調(diào)用vue.extend的返回值缝呕,我們在上一節(jié)分析過,它實(shí)際上是定義了一個Sub構(gòu)造函數(shù)斧散,并通過原型鏈繼承了vue的方法供常,因此new?vnode.componentOptions.Ctor調(diào)用的實(shí)際是

這里的this指向的是vue,因此調(diào)用的實(shí)際上是vue.init方法


該方法的入?yún)閚ew?vnode.componentOptions.Ctor時傳遞的object

代碼向下

? ? ? ? a-vm指向vue

? ? ? ? b-vm._uid鸡捐;在new vue的時候也調(diào)用了init方法栈暇,因此這里至少一級遞增一次,由于++在后是先使用后遞增箍镜,故為1

? ? ? ? c-options?&&?options._isComponent=true瞻鹏,進(jìn)入if判斷,調(diào)用initInternalComponent方法


該方法的入?yún)?/p>

(vue,'new?vnode.componentOptions.Ctor時傳遞的object')

? ? ? ? i-opts鹿寨;Object.create方法將創(chuàng)建一個新對象,并將該對象的__proto__指向參數(shù)對象

? ? ? ? ii-parentVnode薪夕;取自options._parentVnode脚草,該鍵保存著vnode的引用

? ? ? ? iii-opts.parent是vue;當(dāng)我們調(diào)用data.hook.init時傳遞的是app.vue的組件vnode原献,在該init方法下調(diào)用了createComponentInstanceForVnode馏慨,傳遞了當(dāng)前的組件vnode和activeInstance埂淮,并將activeInstance作為parent合并到options上


因此写隶,查找activeInstance的值倔撞,該值在update過程中調(diào)用setActiveInstance設(shè)置為vue,是一個全局的值





????????iv-opts._parentVnode='組件vnode'

回到組件app.vue過程的init方法慕趴,調(diào)用initLifecycle



? ? ? ? ? ? a-parent?&&?!options.abstract=true痪蝇;進(jìn)入判斷,向options掛載$children冕房,成員為當(dāng)前組件vnode

? ? ? ? ? ? b-vm.$parent=vue躏啰;故組件的$parent指向vue,vue的$children指向vnode耙册,兩者是父子關(guān)系

回到組件的init過程给僵,el不存在,init方法結(jié)束详拙,回到組件的hook的init方法中帝际,調(diào)用child.$mount方法


? ?拿到的el為undefined,調(diào)用mountComponent饶辙,在mountComponent方法中再一次實(shí)例化Watcher蹲诀,在Watcher中又再一次update和render,此時的render構(gòu)建的是app.vue內(nèi)部的元素畸悬,拿到的vm就是app.vue的組件對象侧甫,該對象中使用parent指向vue,$options中存在parent指向vue蹋宦,_parentVnode代表在vue組件對象中的占位符披粟,然后render之后再一次update走patch過程,由于app.vue中存在組件child冷冗,因此又會生成子組件的vnode守屉,并調(diào)用子組件的init-mount-render-update,依次類推蒿辙。當(dāng)最后一次嵌套的組件為普通節(jié)點(diǎn)時拇泛,將執(zhí)行掛載。因此定位代碼至createElm函數(shù)中


createComponent返回undefined思灌,表示不存在更多的子組件俺叭,代碼向下,調(diào)用createChildren遞歸調(diào)用createElm一個一個生成dom節(jié)點(diǎn)泰偿,最后執(zhí)行insert插入到dom文檔當(dāng)中

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末熄守,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌裕照,老刑警劉巖攒发,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異晋南,居然都是意外死亡惠猿,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進(jìn)店門负间,熙熙樓的掌柜王于貴愁眉苦臉地迎上來偶妖,“玉大人,你說我怎么就攤上這事唉擂〔褪海” “怎么了?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵玩祟,是天一觀的道長腹缩。 經(jīng)常有香客問我,道長空扎,這世上最難降的妖魔是什么藏鹊? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮转锈,結(jié)果婚禮上盘寡,老公的妹妹穿的比我還像新娘。我一直安慰自己撮慨,他們只是感情好竿痰,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著砌溺,像睡著了一般影涉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上规伐,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天蟹倾,我揣著相機(jī)與錄音,去河邊找鬼猖闪。 笑死鲜棠,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的培慌。 我是一名探鬼主播豁陆,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼吵护!你這毒婦竟也來了盒音?” 一聲冷哼從身側(cè)響起竖配,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎里逆,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體用爪,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡原押,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了偎血。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片诸衔。...
    茶點(diǎn)故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖颇玷,靈堂內(nèi)的尸體忽然破棺而出笨农,到底是詐尸還是另有隱情,我是刑警寧澤帖渠,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布谒亦,位于F島的核電站,受9級特大地震影響空郊,放射性物質(zhì)發(fā)生泄漏份招。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一狞甚、第九天 我趴在偏房一處隱蔽的房頂上張望锁摔。 院中可真熱鬧,春花似錦哼审、人聲如沸谐腰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽十气。三九已至,卻和暖如春旁赊,著一層夾襖步出監(jiān)牢的瞬間桦踊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工终畅, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留籍胯,地道東北人。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓离福,卻偏偏與公主長得像杖狼,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子妖爷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評論 2 348

推薦閱讀更多精彩內(nèi)容

  • patch 當(dāng)我們通過createComponent創(chuàng)建了組件VNode蝶涩,接下來會走到vm._update理朋,執(zhí)行v...
    oWSQo閱讀 519評論 0 2
  • 當(dāng)通過 crateComponent 創(chuàng)建了組件 VNode,接下來會走到 vm._update绿聘,執(zhí)行 vm._u...
    阿暢_閱讀 2,135評論 0 0
  • 回憶 首先嗽上,render函數(shù)中手寫h=>h(app),new Vue()實(shí)例初始化init()和原來一樣熄攘。$mou...
    LoveBugs_King閱讀 2,274評論 1 2
  • 異步組件 在我們平時的開發(fā)工作中兽愤,為了減少首屏代碼體積,往往會把一些非首屏的組件設(shè)計(jì)成異步組件挪圾,按需加載浅萧。Vue也...
    oWSQo閱讀 226評論 0 0
  • 前言 在工作中經(jīng)常會用到Vue,包括也會用到很多重要的點(diǎn)例如組件化等等哲思,現(xiàn)在也想對于之前的應(yīng)用和學(xué)習(xí)做一個小小的總...
    羊駝駝駝駝閱讀 433評論 0 2