前言
使用Vue在日常開發(fā)中會(huì)頻繁接觸和使用生命周期,在官方文檔中是這么解釋生命周期的:
每個(gè) Vue 實(shí)例在被創(chuàng)建時(shí)都要經(jīng)過一系列的初始化過程——例如,需要設(shè)置數(shù)據(jù)監(jiān)聽、編譯模板、將實(shí)例掛載到 DOM 并在數(shù)據(jù)變化時(shí)更新 DOM 等蟀悦。同時(shí)在這個(gè)過程中也會(huì)運(yùn)行一些叫做生命周期鉤子的函數(shù)浙炼,這給了用戶在不同階段添加自己的代碼的機(jī)會(huì)季俩。
好比人的生老病死的過程,Vue同樣也有從組建初始化到組件掛載,組件更新,組件銷毀的一系列過程,而生命周期鉤子,是一個(gè)函數(shù),可以讓開發(fā)者在Vue到達(dá)某個(gè)時(shí)間段的時(shí)候做一些事情
最常見的就是在mounted鉤子中發(fā)送ajax請(qǐng)求獲取當(dāng)前的頁面組件所需要的數(shù)據(jù)
但是對(duì)于Vue.js進(jìn)階來說,只知道生命周期的拼寫和對(duì)應(yīng)的觸發(fā)時(shí)機(jī)肯定是不夠的,為什么鉤子函數(shù)不能是一個(gè)箭頭函數(shù),為什么在data中有時(shí)候無法獲取定義的數(shù)據(jù),我們通過this獲取data中的數(shù)據(jù)真的直接保存在this下了嗎酪我,Vue又是怎么做到無感知的事件監(jiān)聽/事件解綁
在這篇文章中,我將會(huì)帶大家深入Vue的源碼,從源碼中分析Vue的生命周期
文中的源碼截圖只保留核心邏輯 完整源碼地址
Vue版本:2.5.21
源碼概覽
當(dāng)我們?cè)趍ain.js中實(shí)例化Vue的時(shí)候欺矫,會(huì)經(jīng)過一些邏輯,然后進(jìn)入到_init函數(shù)開始Vue的生命周期,其實(shí)從這些函數(shù)的命名方式中就能大致看出Vue是如何運(yùn)行的了,接下來我們逐個(gè)分析每個(gè)函數(shù)具體做了什么
合并配置項(xiàng)
從上面的圖中能看到,在生命周期中第一件事就是合并配置項(xiàng),而對(duì)于根實(shí)例和組件實(shí)例,Vue的處理方式是不同的(在main.js中new Vue生成的是根實(shí)例,其余全部都是組件實(shí)例),根實(shí)例傳入的options參數(shù)里不會(huì)有_isComponent屬性,反之為true(實(shí)例化的時(shí)機(jī)不同,傳入的參數(shù)也不同,感興趣的朋友可以查看相關(guān)實(shí)例化的文章)
為了不必要的干涉络它,這里沒有引入vue-router,vuex
根實(shí)例合并配置項(xiàng)
對(duì)于根實(shí)例會(huì)走false的邏輯,進(jìn)入mergeOptions
函數(shù)迂烁,合并Vue的各個(gè)配置項(xiàng)options,比如mixins,props,methods,watch,computed,生命周期鉤子等等,這是整個(gè)項(xiàng)目中第一次的合并配置。Vue會(huì)將所有的合并策略都保存在一個(gè)strats對(duì)象中,然后依次遍歷當(dāng)前實(shí)例和parent的同一個(gè)屬性,再去starts找那個(gè)屬性對(duì)應(yīng)的合并策略
通過斷點(diǎn)可以看到strats保存了很多合并的策略
我們沒有必要每個(gè)合并策略都去看一遍椰于,盡量把精力放在整個(gè)流程中怠益,不要撿了芝麻丟了西瓜。第一次的合并中瘾婿,Vue會(huì)通過resolveConstructorOptions(vm.constructor)
獲取Vue構(gòu)造器的靜態(tài)屬性options作為parent蜻牢,這個(gè)options包含了一些預(yù)先設(shè)置好的配置項(xiàng),而child就是我們給根實(shí)例實(shí)例化的時(shí)候傳入的一些參數(shù)憋他,對(duì)應(yīng)例子中上圖的render函數(shù)
Vue預(yù)先設(shè)置的配置項(xiàng)作為第一次的parent:
根實(shí)例實(shí)例化傳入的參數(shù):
根實(shí)例的合并策略其實(shí)很簡(jiǎn)單孩饼,主要就是把Vue框架內(nèi)置的一些配置項(xiàng)和開發(fā)者在main.js中實(shí)例化Vue構(gòu)造器傳入的參數(shù)進(jìn)行一次簡(jiǎn)單的合并,作為根實(shí)例的$options屬性
組件實(shí)例合并配置項(xiàng)
組件實(shí)例合并配置項(xiàng)并不在_init
函數(shù)中竹挡,因?yàn)榻M件實(shí)例和根實(shí)例不同镀娶,組件實(shí)例是由組件構(gòu)造器實(shí)例化的,而根實(shí)例是由Vue構(gòu)造器實(shí)例化的揪罕,而組件構(gòu)造器又是繼承自Vue的它需要通過Vue.extend方法去繼承Vue構(gòu)造函數(shù)梯码,我畫了張圖方便理解
Vue這么做符合面向?qū)ο蟮脑O(shè)計(jì)模式宝泵,一個(gè)組件實(shí)質(zhì)上是一個(gè)構(gòu)造器函數(shù)(進(jìn)一步可以認(rèn)為是一個(gè)class),這樣在一個(gè)頁面中引入多個(gè)相同的組件只需要多次實(shí)例化組件構(gòu)造器就可以了轩娶,并且可以做到實(shí)例之間互相獨(dú)立
而面向?qū)ο罅硗庖粋€(gè)好處就是可以實(shí)現(xiàn)繼承儿奶,體現(xiàn)在Vue框架中則是將組件構(gòu)造器繼承Vue構(gòu)造器,從而組件構(gòu)造器能夠獲得Vue構(gòu)造器內(nèi)置的一些配置項(xiàng)
組件實(shí)例合并配置項(xiàng)在src/core/global-api/extend.js
,同樣會(huì)調(diào)用mergeOptions
組件實(shí)例合并配置項(xiàng)會(huì)將Vue框架內(nèi)置的配置項(xiàng)和當(dāng)前組件配置項(xiàng)進(jìn)行合并并賦值給組件構(gòu)造器的靜態(tài)屬性options
再次回到mergeOptions中,這里就只例舉一個(gè)生命周期的合并策略鳄抒,直接貼上源碼并附上流程圖方便理解
這里我用了父級(jí)而不是父組件闯捎,因?yàn)閂ue的組件一般繼承自Vue構(gòu)造函數(shù)而不是父組件,通過流程圖可以發(fā)現(xiàn)许溅,Vue會(huì)保證生命周期函數(shù)始終是一個(gè)數(shù)組瓤鼻,并且以父=>子的順序排列的,Vue在執(zhí)行某個(gè)生命周期的時(shí)候會(huì)遍歷這個(gè)數(shù)組依次執(zhí)行函數(shù)贤重,所以當(dāng)我們?cè)赩ue構(gòu)造器和組件構(gòu)造器中的同一個(gè)生命周期里都定義了生命周期函數(shù)茬祷,會(huì)先執(zhí)行Vue構(gòu)造器中的那個(gè)
繼承了Vue構(gòu)造器后才會(huì)實(shí)例化子組件生成組件實(shí)例,再進(jìn)入到_init函數(shù)并蝗,這個(gè)時(shí)候_isComponent為true會(huì)執(zhí)行initInternalComponent
祭犯,它會(huì)給組件實(shí)例創(chuàng)建$options屬性,指向子組件構(gòu)造器的靜態(tài)屬性options滚停,這樣就能夠通過組件實(shí)例的$options屬性訪問到當(dāng)前組件的配置項(xiàng)以及Vue框架內(nèi)置的配置項(xiàng)(包括全局組件沃粗,全局混入)
小結(jié)
- 生命周期中第一件事就是合并配置項(xiàng),對(duì)于根實(shí)例和組件實(shí)例合并的時(shí)機(jī)不同
- 根實(shí)例是在new Vue的時(shí)候進(jìn)行合并键畴,將Vue內(nèi)置的配置項(xiàng)和new Vue傳入的配置項(xiàng)進(jìn)行合并
- 對(duì)于組件實(shí)例來說陪每,先會(huì)創(chuàng)建子組件的構(gòu)造器,并且調(diào)用Vue.extend繼承Vue構(gòu)造器镰吵,繼承的時(shí)候?qū)ue內(nèi)置的配置項(xiàng)和組件配置項(xiàng)進(jìn)行合并,并將結(jié)果保存在構(gòu)造器的options屬性中挂签,之后在創(chuàng)建組件實(shí)例的時(shí)候進(jìn)入initInternalComponent方法會(huì)將組件實(shí)例的$options指向組件構(gòu)造器的options屬性
- Vue框架會(huì)根據(jù)不同的配置執(zhí)行不同的合并策略
代理開發(fā)環(huán)境的錯(cuò)誤
非生產(chǎn)環(huán)境下會(huì)進(jìn)入initProxy
函數(shù)疤祭,通過ES6的Proxy給vm實(shí)例做一層攔截,主要作用是給開發(fā)環(huán)境下一些不合理的配置做出一些自定義的警告
上面的報(bào)錯(cuò)很多開發(fā)者都遇到過饵婆,其實(shí)就是在這個(gè)時(shí)候通過Proxy的has攔截器勺馆,當(dāng)某個(gè)屬性不在vm實(shí)例上卻被模版引用的時(shí)候,Vue會(huì)給出一些友好的提示
初始化自定義事件
隨后進(jìn)入initLifecycle
侨核,這部分沒什么好講的草穆,初始化實(shí)例的一些生命周期的狀態(tài)和一些額外屬性,接著會(huì)進(jìn)入初始化組件的自定義事件
initEvents
只會(huì)掛載自定義事件搓译,即組件中使用v-on監(jiān)聽的非native的事件(原生的DOM事件并非在initEvents
中掛載)悲柱。Vue會(huì)把這些父組件中聲明的自定義的事件保存在子組件的_parentListeners屬性中(vm是子組件的組件實(shí)例,_parentListeners是在initInternalComponent
中定義的)
進(jìn)入updateComponentListeners,發(fā)現(xiàn)Vue會(huì)調(diào)用add函數(shù)注冊(cè)所有的自定義事件些己,而對(duì)于組件來說add函數(shù)就會(huì)調(diào)用$on來達(dá)到監(jiān)聽自定義事件的效果
//https://github.com/vuejs/vue/blob/dev/src/core/instance/events.js#L24
function add (event, fn) {
target.$on(event, fn)
}
//https://github.com/vuejs/vue/blob/dev/src/core/vdom/helpers/update-listeners.js#L83
//調(diào)用add注冊(cè)自定義事件(后面3個(gè)參數(shù)可忽略)
add(event.name, cur, event.capture, event.passive, event.params)
beforeCreate
添加完自定義事件后豌鸡,進(jìn)入initRender
嘿般,定義插槽和給render函數(shù)的參數(shù)createElement,另外會(huì)將Vue的$attrs,$listeners變成響應(yīng)式的屬性
接著會(huì)執(zhí)行callHook(vm, 'beforeCreate')
涯冠,從字面上來看就能猜出Vue在這個(gè)時(shí)候會(huì)調(diào)用beforeCreate這個(gè)生命周期函數(shù)炉奴,在之前合并配置項(xiàng)的時(shí)候就提到,生命周期函數(shù)最終會(huì)被包裹成一個(gè)數(shù)組蛇更,所以事實(shí)上Vue也支持這么寫
callHook函數(shù)會(huì)根據(jù)傳入的參數(shù)拿到$options屬性中對(duì)應(yīng)的生命周期函數(shù)組成的數(shù)組瞻赶,這里傳入了beforeCreate,所以會(huì)獲得beforeCreate中定義的所有生命周期函數(shù)派任,之后順序遍歷并且用call方法給每個(gè)生命周期函數(shù)綁定了this上下文砸逊,這就是為什么生命周期函數(shù)不能使用剪頭函數(shù)書寫的原因
初始化數(shù)據(jù)
接著執(zhí)行initInjections
,這部分是用來初始化inject這個(gè)api吨瞎,由于日常開發(fā)使用頻率較少就不詳細(xì)解釋了(其實(shí)是我懶得研究-.-)
隨后會(huì)進(jìn)入另外一個(gè)關(guān)鍵的函數(shù)initState
痹兜,它會(huì)依次初始化props,methods,data,computed,watch,我們一個(gè)個(gè)來講解
props
組件之間通信的時(shí)候颤诀,父組件給子組件傳參字旭,子組件需要定義props來接受父組件傳過來的屬性,而Vue規(guī)定崖叫,子組件是不能修改父組件傳來的props遗淳,因?yàn)檫@違背了單項(xiàng)數(shù)據(jù)流,會(huì)導(dǎo)致組件之間非常難以管理心傀,如果在子組件修改了props屈暗,Vue會(huì)發(fā)出一個(gè)警告
而Vue又是怎么知道開發(fā)者修改了props的屬性呢?原因還是利用了訪問器描述符setter
了解過響應(yīng)式原理的朋友應(yīng)該對(duì)這個(gè)有所熟悉脂男,Vue會(huì)將props對(duì)象變成一個(gè)響應(yīng)式對(duì)象养叛,并且第四個(gè)參數(shù)是一個(gè)自定義的setter,當(dāng)props被修改了會(huì)觸發(fā)這個(gè)setter宰翅,一單違背了單項(xiàng)數(shù)據(jù)流時(shí)就會(huì)報(bào)出這個(gè)警告
methods
對(duì)于methods弃甥,Vue會(huì)定義一些開發(fā)過程中的不規(guī)范的警告,隨后會(huì)將所有的method綁定vm實(shí)例汁讼,這樣我們就可以直接通過this獲取當(dāng)前的vm實(shí)例
data
到了最關(guān)鍵的data淆攻,data中一般保存的是當(dāng)前組件需要使用的數(shù)據(jù),除了根實(shí)例之外嘿架,組件實(shí)例的data一般都是一個(gè)函數(shù)瓶珊,因?yàn)镴S引用類型的特點(diǎn),如果使用對(duì)象耸彪,當(dāng)存在多個(gè)相同的組件伞芹,其中一個(gè)組件修改了data數(shù)據(jù),會(huì)反映到所有的組件蝉娜。當(dāng)data作為一個(gè)函數(shù)返回一個(gè)對(duì)象時(shí)丑瞧,每次執(zhí)行都會(huì)生成一個(gè)新的對(duì)象柑土,可以有效的解決這個(gè)問題
初始化data會(huì)執(zhí)行initData這個(gè)函數(shù),內(nèi)部會(huì)執(zhí)行定義的data函數(shù)并且把當(dāng)前實(shí)例作為this值绊汹,并且賦值給_data這個(gè)內(nèi)部屬性,值得注意的是稽屏,在執(zhí)行data函數(shù)的過程中是獲取不到computed中的數(shù)據(jù),因?yàn)閏omputed中的數(shù)據(jù)此時(shí)還沒初始化
隨后執(zhí)行proxy函數(shù)西乖,它的作用是將vm._data的屬性映射到vm屬性上狐榔,起到了"代理"的作用,這樣做是為了在開發(fā)過程中直接書寫this[key]的形式获雕,其原理依舊是利用了getter/setter薄腻,當(dāng)我們?cè)L問this[key]的時(shí)候會(huì)觸發(fā)getter,直接指向this._data[key]届案,setter同理
有人會(huì)問庵楷,那為啥不直接寫在vm實(shí)例上呢?因?yàn)槲覀冃枰獙?shù)據(jù)放在一個(gè)統(tǒng)一的對(duì)象上進(jìn)行管理楣颠,為的是下一步把_data通過observe變成一個(gè)響應(yīng)式對(duì)象尽纽。而為了在開發(fā)的時(shí)候書寫更加簡(jiǎn)潔,Vue采取了這種方法童漩,非常的討巧
computed
到了初始化computed弄贿,Vue會(huì)給每個(gè)計(jì)算屬性生成一個(gè)computed watcher,只有當(dāng)這個(gè)計(jì)算屬性的依賴項(xiàng)改變了才會(huì)去通知computed watcher更新這個(gè)計(jì)算屬性矫膨,從而既能達(dá)到實(shí)時(shí)更新數(shù)據(jù)差凹,又不會(huì)浪費(fèi)性能,也是Vue非常棒的功能
watch
初始化watch的時(shí)候最終會(huì)調(diào)用$watch方法侧馅,生成一個(gè)user watcher危尿,當(dāng)監(jiān)聽的屬性發(fā)生改變就會(huì)立即通知user watcher執(zhí)行回調(diào)
created
再調(diào)用initProvide
初始化provide后就會(huì)執(zhí)行callHook(vm, 'beforeCreate')
,和beforeCreate一樣,依次遍歷定義在$options上的created數(shù)組馁痴,執(zhí)行生命周期函數(shù)
至此整個(gè)組件創(chuàng)建完畢脚线,其實(shí)這個(gè)時(shí)候就可以和后端進(jìn)行交互獲取數(shù)據(jù)了,但是對(duì)于真正的DOM節(jié)點(diǎn)還沒有被渲染出來弥搞,一些需要和DOM的交互操作還無法在created鉤子中執(zhí)行,即無法在created鉤子中有操作生成視圖的DOM
掛載過程
回到_init
函數(shù)渠旁,已經(jīng)到了最后一行攀例,會(huì)判斷$options是否有el屬性,在Vue-cli2的時(shí)候顾腊,cli會(huì)自動(dòng)在new Vue的時(shí)候傳入el參數(shù)粤铭,而對(duì)于Vue-cli3并沒有這么做,而是生成根實(shí)例后主動(dòng)調(diào)用$mount并傳入了掛載的節(jié)點(diǎn)杂靶,其實(shí)兩者都是一樣的梆惯,也可以使用$mount來實(shí)現(xiàn)組件的手動(dòng)掛載
Vue-cli2:
Vue-cli3:
$mount最終會(huì)執(zhí)行mountComponent
這個(gè)函數(shù)
剛剛從_init
的長(zhǎng)篇大論中逃出來酱鸭,又要跳進(jìn)mountComponent
這個(gè)坑
組件掛載我這里不會(huì)展開詳解,盡量把重心放在生命周期方面垛吗,有興趣的朋友可以自行了解凹髓,或者看我底下的鏈接
beforeMount
當(dāng)組件執(zhí)行$mount并且擁有掛載點(diǎn)和渲染函數(shù)的時(shí)候,就會(huì)觸發(fā)beforeMount的鉤子怯屉,準(zhǔn)備組件的掛載
渲染視圖的函數(shù)updateComponent
之后Vue會(huì)定義一個(gè)updateComponent函數(shù)蔚舀,這個(gè)函數(shù)是整個(gè)掛載的核心,它由2部分組成锨络,_render函數(shù)和_update函數(shù)
- render函數(shù)最終會(huì)執(zhí)行之前在
initRender
定義的createElement函數(shù)赌躺,作用是創(chuàng)建vnode - update函數(shù)會(huì)將上面的render函數(shù)生成的vnode渲染成一個(gè)真實(shí)的DOM樹,并掛載到掛載點(diǎn)上
第一次執(zhí)行updateComponent會(huì)渲染出整個(gè)DOM樹羡儿,這個(gè)時(shí)候頁面就完整的被展現(xiàn)了
渲染watcher
然后會(huì)實(shí)例化一個(gè)"渲染watcher"礼患,將updateComponent作為回調(diào)函數(shù)傳入,內(nèi)部會(huì)立即執(zhí)行一次updateComponet函數(shù)
watcher顧名思義是用來觀察的掠归,渲染watcher簡(jiǎn)而言之缅叠,就是會(huì)觀察模版中依賴變量的是否變化來決定是否需要刷新頁面,而updateComponet就是一個(gè)用來更新頁面的函數(shù)拂到,所以將這個(gè)函數(shù)作為回調(diào)傳入痪署。對(duì)于模版中的響應(yīng)式變量(下圖中的變量a)內(nèi)部都會(huì)保存這個(gè)渲染watcher(因?yàn)檫@些變量都有可能修改視圖),一旦變量被修改了就會(huì)觸發(fā)setter兄旬,最后都會(huì)再次執(zhí)行updateComponent函數(shù)來刷新視圖
mounted
實(shí)例化渲染watcher渲染出頁面后會(huì)進(jìn)入一個(gè)判斷丧叽,這里要注意的是,只有根實(shí)例才會(huì)為true并且觸發(fā)mounted鉤子永罚,那組件實(shí)例什么時(shí)候觸發(fā)mounted鉤子呢荐糜?
這里先給出答案,在src/core/vdom/create-component.js
的insert鉤子(組件專屬的vnode鉤子),同時(shí)Vue會(huì)聲明一個(gè)insertedVnodeQueue數(shù)組绪撵,保存所有的組件vnode瓢姻,每當(dāng)一個(gè)組件vnode被渲染成DOM節(jié)點(diǎn)就會(huì)往這個(gè)數(shù)組里添加一個(gè)vnode元素,當(dāng)組件全部渲染完畢后音诈,會(huì)以子=>父的順序依次觸發(fā)mounted鉤子(最先觸發(fā)最里層組件的mounted鉤子)幻碱。隨后再回到_init
方法,最后觸發(fā)根實(shí)例的mounted鉤子细溅,具體為什么會(huì)這么做有興趣的同學(xué)可以再深入研究
至此所有的數(shù)據(jù)都被初始化褥傍,并且渲染出了DOM節(jié)點(diǎn),接下來會(huì)介紹組件更新和組件銷毀的過程
組件更新
回到mountComponent那張圖喇聊,在實(shí)例化渲染watcher的時(shí)候恍风,Vue會(huì)給渲染watcher傳入一個(gè)對(duì)象,對(duì)象包含了一個(gè)before方法,執(zhí)行before方法就會(huì)執(zhí)行beforeUpdate鉤子朋贬,那什么時(shí)候執(zhí)行這個(gè)方法呢凯楔?
一旦模版的依賴的變量發(fā)生了變化,說明即將改變視圖锦募,會(huì)觸發(fā)setter然后執(zhí)行渲染watcher的回調(diào)摆屯,即updateComponent刷新視圖,在執(zhí)行這個(gè)回調(diào)前御滩,Vue會(huì)查看是否有before這個(gè)方法鸥拧,如果有則會(huì)優(yōu)先執(zhí)行before,然后再執(zhí)行updateCompont刷新視圖
Vue會(huì)將所有的watcher放入一個(gè)隊(duì)列削解,flushSchedulerQueue會(huì)依次遍歷這些watcer富弦,而渲染watcher會(huì)有一個(gè)before方法,從而觸發(fā)beforeUpdate鉤子
然后當(dāng)所有的watcher都遍歷過之后氛驮,代表數(shù)據(jù)已經(jīng)更新完畢腕柜,并且視圖也刷新了,此時(shí)會(huì)調(diào)用callUpdatedHooks
矫废,執(zhí)行updated鉤子
組件銷毀
組件銷毀的前提是發(fā)生了視圖更新盏缤,Vue會(huì)判斷生成新視圖的vnode和舊視圖對(duì)應(yīng)的vnode的區(qū)別,然后刪除那些視圖中不需要渲染的節(jié)點(diǎn)蓖扑,這個(gè)過程最終會(huì)調(diào)用實(shí)例的$destroy方法唉铜,對(duì)應(yīng)源代碼的src/core/instance/lifecycle.js
依次按照順序執(zhí)行:
- 首先會(huì)直接執(zhí)行beforeDestory的鉤子,表示準(zhǔn)備開始銷毀節(jié)點(diǎn)律杠,此時(shí)是可以和當(dāng)前組件實(shí)例交互的最后時(shí)機(jī)
- 隨后會(huì)找到當(dāng)前組件的父節(jié)點(diǎn)潭流,從父節(jié)點(diǎn)的children屬性中刪除當(dāng)前的節(jié)點(diǎn)
- 對(duì)渲染watcher進(jìn)行注銷(vm._watcher存放的是每個(gè)組件唯一的渲染watcher)
- 對(duì)其他的watcher進(jìn)行注銷(user watcher,computed watcher)
- 清除這個(gè)實(shí)例渲染出的DOM節(jié)點(diǎn)
- 執(zhí)行destroyed鉤子
- 注銷所有的監(jiān)聽事件($off不傳參數(shù)會(huì)清空所有的監(jiān)聽事件)
總結(jié)
至此整個(gè)Vue的生命周期結(jié)束了,最后再總結(jié)一下每個(gè)生命周期主要都做了什么事情柜去,嚴(yán)格按照Vue內(nèi)部的執(zhí)行順序羅列
-
beforeCreate
:將開發(fā)者定義的配置項(xiàng)和Vue內(nèi)部的配置項(xiàng)進(jìn)行合并灰嫉,初始化組件的自定義事件,定義createElement函數(shù)/初始化插槽 -
created
:初始化inject嗓奢,初始化所有數(shù)據(jù)(props -> methods -> data -> computed -> watch)讼撒,初始化provide -
beforeMount
:尋找是否有掛載的節(jié)點(diǎn),根據(jù)render函數(shù)準(zhǔn)備開始渲染頁面/實(shí)例化渲染watcher -
mounted
:頁面渲染完成 -
beforeUpdate
:渲染watcher依賴的變量發(fā)生變化股耽,準(zhǔn)備更新視圖 -
updated
:視圖和數(shù)據(jù)全部更新完畢 -
beforeDestroy
:注銷watcher根盒,刪除DOM節(jié)點(diǎn) -
destroyed
:注銷所有監(jiān)聽事件
事實(shí)上要想完全了解Vue的生命周期,還需要了解其他方面的知識(shí)點(diǎn)物蝙,例如組件掛載炎滞,響應(yīng)式原理,另外可能還需要了解一下Vue的編譯原理茬末,每個(gè)知識(shí)點(diǎn)又可以展開十幾個(gè)小的知識(shí)點(diǎn),但是當(dāng)你能夠真正理解Vue.js的核心原理,我相信對(duì)個(gè)人成長(zhǎng)來說是一個(gè)不小的收獲(終于寫完了脖子都酸了:(′°ω°`」 ∠):)
砥礪前行 未來可期