前言
使用Vue在日常開(kāi)發(fā)中會(huì)頻繁接觸和使用生命周期,在官方文檔中是這么解釋生命周期的:
每個(gè) Vue 實(shí)例在被創(chuàng)建時(shí)都要經(jīng)過(guò)一系列的初始化過(guò)程——例如,需要設(shè)置數(shù)據(jù)監(jiān)聽(tīng)、編譯模板、將實(shí)例掛載到 DOM 并在數(shù)據(jù)變化時(shí)更新 DOM 等。同時(shí)在這個(gè)過(guò)程中也會(huì)運(yùn)行一些叫做生命周期鉤子的函數(shù),這給了用戶(hù)在不同階段添加自己的代碼的機(jī)會(huì)。
好比人的生老病死的過(guò)程,Vue同樣也有從組建初始化到組件掛載,組件更新,組件銷(xiāo)毀的一系列過(guò)程,而生命周期鉤子,是一個(gè)函數(shù),可以讓開(kāi)發(fā)者在Vue到達(dá)某個(gè)時(shí)間段的時(shí)候做一些事情
最常見(jiàn)的就是在mounted鉤子中發(fā)送ajax請(qǐng)求獲取當(dāng)前的頁(yè)面組件所需要的數(shù)據(jù)
但是對(duì)于Vue.js進(jìn)階來(lái)說(shuō),只知道生命周期的拼寫(xiě)和對(duì)應(yīng)的觸發(fā)時(shí)機(jī)肯定是不夠的,為什么鉤子函數(shù)不能是一個(gè)箭頭函數(shù),為什么在data中有時(shí)候無(wú)法獲取定義的數(shù)據(jù),我們通過(guò)this獲取data中的數(shù)據(jù)真的直接保存在this下了嗎,Vue又是怎么做到無(wú)感知的事件監(jiān)聽(tīng)/事件解綁
在這篇文章中,我將會(huì)帶大家深入Vue的源碼,從源碼中分析Vue的生命周期
文中的源碼截圖只保留核心邏輯 完整源碼地址
Vue版本:2.5.21
源碼概覽
當(dāng)我們?cè)趍ain.js中實(shí)例化Vue的時(shí)候,會(huì)經(jīng)過(guò)一些邏輯,然后進(jìn)入到_init函數(shù)開(kāi)始Vue的生命周期,其實(shí)從這些函數(shù)的命名方式中就能大致看出Vue是如何運(yùn)行的了,接下來(lái)我們逐個(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í)例化的文章)
為了不必要的干涉,這里沒(méi)有引入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)的合并策略
通過(guò)斷點(diǎn)可以看到strats保存了很多合并的策略
我們沒(méi)有必要每個(gè)合并策略都去看一遍,盡量把精力放在整個(gè)流程中,不要撿了芝麻丟了西瓜。第一次的合并中,Vue會(huì)通過(guò)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)和開(kāi)發(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的它需要通過(guò)Vue.extend方法去繼承Vue構(gòu)造函數(shù),我畫(huà)了張圖方便理解
Vue這么做符合面向?qū)ο蟮脑O(shè)計(jì)模式,一個(gè)組件實(shí)質(zhì)上是一個(gè)構(gòu)造器函數(shù)(進(jìn)一步可以認(rèn)為是一個(gè)class),這樣在一個(gè)頁(yè)面中引入多個(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ù)而不是父組件,通過(guò)流程圖可以發(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,這樣就能夠通過(guò)組件實(shí)例的$options屬性訪問(wèn)到當(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í)例來(lái)說(shuō),先會(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í)行不同的合并策略
代理開(kāi)發(fā)環(huán)境的錯(cuò)誤
非生產(chǎn)環(huán)境下會(huì)進(jìn)入initProxy函數(shù),通過(guò)ES6的Proxy給vm實(shí)例做一層攔截,主要作用是給開(kāi)發(fā)環(huán)境下一些不合理的配置做出一些自定義的警告
上面的報(bào)錯(cuò)很多開(kāi)發(fā)者都遇到過(guò),其實(shí)就是在這個(gè)時(shí)候通過(guò)Proxy的has攔截器,當(dāng)某個(gè)屬性不在vm實(shí)例上卻被模版引用的時(shí)候,Vue會(huì)給出一些友好的提示
初始化自定義事件
隨后進(jìn)入initLifecycle,這部分沒(méi)什么好講的,初始化實(shí)例的一些生命周期的狀態(tài)和一些額外屬性,接著會(huì)進(jìn)入初始化組件的自定義事件
initEvents只會(huì)掛載自定義事件,即組件中使用v-on監(jiān)聽(tīng)的非native的事件(原生的DOM事件并非在initEvents中掛載)。Vue會(huì)把這些父組件中聲明的自定義的事件保存在子組件的_parentListeners屬性中(vm是子組件的組件實(shí)例,_parentListeners是在initInternalComponent中定義的)
進(jìn)入updateComponentListeners,發(fā)現(xiàn)Vue會(huì)調(diào)用add函數(shù)注冊(cè)所有的自定義事件,而對(duì)于組件來(lái)說(shuō)add函數(shù)就會(huì)調(diào)用$on來(lái)達(dá)到監(jiān)聽(tīng)自定義事件的效果
//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'),從字面上來(lái)看就能猜出Vue在這個(gè)時(shí)候會(huì)調(diào)用beforeCreate這個(gè)生命周期函數(shù),在之前合并配置項(xiàng)的時(shí)候就提到,生命周期函數(shù)最終會(huì)被包裹成一個(gè)數(shù)組,所以事實(shí)上Vue也支持這么寫(xiě)
callHook函數(shù)會(huì)根據(jù)傳入的參數(shù)拿到$options屬性中對(duì)應(yīng)的生命周期函數(shù)組成的數(shù)組,這里傳入了beforeCreate,所以會(huì)獲得beforeCreate中定義的所有生命周期函數(shù),之后順序遍歷并且用call方法給每個(gè)生命周期函數(shù)綁定了this上下文,這就是為什么生命周期函數(shù)不能使用剪頭函數(shù)書(shū)寫(xiě)的原因
初始化數(shù)據(jù)
接著執(zhí)行initInjections,這部分是用來(lái)初始化inject這個(gè)api,由于日常開(kāi)發(fā)使用頻率較少就不詳細(xì)解釋了(其實(shí)是我懶得研究-.-)
隨后會(huì)進(jìn)入另外一個(gè)關(guān)鍵的函數(shù)initState,它會(huì)依次初始化props,methods,data,computed,watch,我們一個(gè)個(gè)來(lái)講解
props
組件之間通信的時(shí)候,父組件給子組件傳參,子組件需要定義props來(lái)接受父組件傳過(guò)來(lái)的屬性,而Vue規(guī)定,子組件是不能修改父組件傳來(lái)的props,因?yàn)檫@違背了單項(xiàng)數(shù)據(jù)流,會(huì)導(dǎo)致組件之間非常難以管理,如果在子組件修改了props,Vue會(huì)發(fā)出一個(gè)警告
而Vue又是怎么知道開(kāi)發(fā)者修改了props的屬性呢?原因還是利用了訪問(wèn)器描述符setter
了解過(guò)響應(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ì)定義一些開(kāi)發(fā)過(guò)程中的不規(guī)范的警告,隨后會(huì)將所有的method綁定vm實(shí)例,這樣我們就可以直接通過(guò)this獲取當(dāng)前的vm實(shí)例
data
到了最關(guān)鍵的data,data中一般保存的是當(dāng)前組件需要使用的數(shù)據(jù),除了根實(shí)例之外,組件實(shí)例的data一般都是一個(gè)函數(shù),因?yàn)镴S引用類(lèi)型的特點(diǎn),如果使用對(duì)象,當(dāng)存在多個(gè)相同的組件,其中一個(gè)組件修改了data數(shù)據(jù),會(huì)反映到所有的組件。當(dāng)data作為一個(gè)函數(shù)返回一個(gè)對(duì)象時(shí),每次執(zhí)行都會(huì)生成一個(gè)新的對(duì)象,可以有效的解決這個(gè)問(wèn)題
初始化data會(huì)執(zhí)行initData這個(gè)函數(shù),內(nèi)部會(huì)執(zhí)行定義的data函數(shù)并且把當(dāng)前實(shí)例作為this值,并且賦值給_data這個(gè)內(nèi)部屬性,值得注意的是,在執(zhí)行data函數(shù)的過(guò)程中是獲取不到computed中的數(shù)據(jù),因?yàn)閏omputed中的數(shù)據(jù)此時(shí)還沒(méi)初始化
隨后執(zhí)行proxy函數(shù),它的作用是將vm._data的屬性映射到vm屬性上,起到了"代理"的作用,這樣做是為了在開(kāi)發(fā)過(guò)程中直接書(shū)寫(xiě)this[key]的形式,其原理依舊是利用了getter/setter,當(dāng)我們?cè)L問(wèn)this[key]的時(shí)候會(huì)觸發(fā)getter,直接指向this._data[key],setter同理
有人會(huì)問(wèn),那為啥不直接寫(xiě)在vm實(shí)例上呢?因?yàn)槲覀冃枰獙?shù)據(jù)放在一個(gè)統(tǒng)一的對(duì)象上進(jìn)行管理,為的是下一步把_data通過(guò)observe變成一個(gè)響應(yīng)式對(duì)象。而為了在開(kāi)發(fā)的時(shí)候書(shū)寫(xiě)更加簡(jiǎn)潔,Vue采取了這種方法,非常的討巧
computed
到了初始化computed,Vue會(huì)給每個(gè)計(jì)算屬性生成一個(gè)computed watcher,只有當(dāng)這個(gè)計(jì)算屬性的依賴(lài)項(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)聽(tīng)的屬性發(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)還沒(méi)有被渲染出來(lái),一些需要和DOM的交互操作還無(wú)法在created鉤子中執(zhí)行,即無(wú)法在created鉤子中有操作生成視圖的DOM
掛載過(guò)程
回到_init函數(shù),已經(jīng)到了最后一行,會(huì)判斷$options是否有el屬性,在Vue-cli2的時(shí)候,cli會(huì)自動(dòng)在new Vue的時(shí)候傳入el參數(shù),而對(duì)于Vue-cli3并沒(méi)有這么做,而是生成根實(shí)例后主動(dòng)調(diào)用$mount并傳入了掛載的節(jié)點(diǎn),其實(shí)兩者都是一樣的,也可以使用$mount來(lái)實(shí)現(xiàn)組件的手動(dòng)掛載
Vue-cli2:
Vue-cli3:
$mount最終會(huì)執(zhí)行mountComponent這個(gè)函數(shù)
剛剛從_init的長(zhǎng)篇大論中逃出來(lái),又要跳進(jìn)mountComponent這個(gè)坑
組件掛載我這里不會(huì)展開(kāi)詳解,盡量把重心放在生命周期方面,有興趣的朋友可以自行了解,或者看我底下的鏈接
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樹(shù),并掛載到掛載點(diǎn)上
第一次執(zhí)行updateComponent會(huì)渲染出整個(gè)DOM樹(shù),這個(gè)時(shí)候頁(yè)面就完整的被展現(xiàn)了
渲染watcher
然后會(huì)實(shí)例化一個(gè)"渲染watcher",將updateComponent作為回調(diào)函數(shù)傳入,內(nèi)部會(huì)立即執(zhí)行一次updateComponet函數(shù)
watcher顧名思義是用來(lái)觀察的,渲染watcher簡(jiǎn)而言之,就是會(huì)觀察模版中依賴(lài)變量的是否變化來(lái)決定是否需要刷新頁(yè)面,而updateComponet就是一個(gè)用來(lái)更新頁(yè)面的函數(shù),所以將這個(gè)函數(shù)作為回調(diào)傳入。對(duì)于模版中的響應(yīng)式變量(下圖中的變量a)內(nèi)部都會(huì)保存這個(gè)渲染watcher(因?yàn)檫@些變量都有可能修改視圖),一旦變量被修改了就會(huì)觸發(fā)setter,最后都會(huì)再次執(zhí)行updateComponent函數(shù)來(lái)刷新視圖
mounted
實(shí)例化渲染watcher渲染出頁(yè)面后會(huì)進(jìn)入一個(gè)判斷,這里要注意的是,只有根實(shí)例才會(huì)為true并且觸發(fā)mounted鉤子,那組件實(shí)例什么時(shí)候觸發(fā)mounted鉤子呢?
這里先給出答案,在src/core/vdom/create-component.js的insert鉤子(組件專(zhuān)屬的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),接下來(lái)會(huì)介紹組件更新和組件銷(xiāo)毀的過(guò)程
組件更新
回到mountComponent那張圖,在實(shí)例化渲染watcher的時(shí)候,Vue會(huì)給渲染watcher傳入一個(gè)對(duì)象,對(duì)象包含了一個(gè)before方法,執(zhí)行before方法就會(huì)執(zhí)行beforeUpdate鉤子,那什么時(shí)候執(zhí)行這個(gè)方法呢?
一旦模版的依賴(lài)的變量發(fā)生了變化,說(shuō)明即將改變視圖,會(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都遍歷過(guò)之后,代表數(shù)據(jù)已經(jīng)更新完畢,并且視圖也刷新了,此時(shí)會(huì)調(diào)用callUpdatedHooks,執(zhí)行updated鉤子
組件銷(xiāo)毀
組件銷(xiāo)毀的前提是發(fā)生了視圖更新,Vue會(huì)判斷生成新視圖的vnode和舊視圖對(duì)應(yīng)的vnode的區(qū)別,然后刪除那些視圖中不需要渲染的節(jié)點(diǎn),這個(gè)過(guò)程最終會(huì)調(diào)用實(shí)例的$destroy方法,對(duì)應(yīng)源代碼的src/core/instance/lifecycle.js
依次按照順序執(zhí)行:
- 首先會(huì)直接執(zhí)行beforeDestory的鉤子,表示準(zhǔn)備開(kāi)始銷(xiāo)毀節(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)行注銷(xiāo)(vm._watcher存放的是每個(gè)組件唯一的渲染watcher)
- 對(duì)其他的watcher進(jìn)行注銷(xiāo)(user watcher,computed watcher)
- 清除這個(gè)實(shí)例渲染出的DOM節(jié)點(diǎn)
- 執(zhí)行destroyed鉤子
- 注銷(xiāo)所有的監(jiān)聽(tīng)事件($off不傳參數(shù)會(huì)清空所有的監(jiān)聽(tīng)事件)
總結(jié)
至此整個(gè)Vue的生命周期結(jié)束了,最后再總結(jié)一下每個(gè)生命周期主要都做了什么事情,嚴(yán)格按照Vue內(nèi)部的執(zhí)行順序羅列
-
beforeCreate:將開(kāi)發(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)備開(kāi)始渲染頁(yè)面/實(shí)例化渲染watcher -
mounted:頁(yè)面渲染完成 -
beforeUpdate:渲染watcher依賴(lài)的變量發(fā)生變化,準(zhǔn)備更新視圖 -
updated:視圖和數(shù)據(jù)全部更新完畢 -
beforeDestroy:注銷(xiāo)watcher,刪除DOM節(jié)點(diǎn) -
destroyed:注銷(xiāo)所有監(jiān)聽(tīng)事件
事實(shí)上要想完全了解Vue的生命周期,還需要了解其他方面的知識(shí)點(diǎn),例如組件掛載,響應(yīng)式原理,另外可能還需要了解一下Vue的編譯原理,每個(gè)知識(shí)點(diǎn)又可以展開(kāi)十幾個(gè)小的知識(shí)點(diǎn),但是當(dāng)你能夠真正理解Vue.js的核心原理,我相信對(duì)個(gè)人成長(zhǎng)來(lái)說(shuō)是一個(gè)不小的收獲(終于寫(xiě)完了脖子都酸了:(′°ω°`」 ∠):)
砥礪前行 未來(lái)可期