微信小程序生命周期學(xué)習(xí)筆記-組件

生命周期包含應(yīng)用生命周期、頁(yè)面生命周期和組件生命周期。現(xiàn)在我們來(lái)學(xué)習(xí)組件的生命周期。
學(xué)習(xí)這一章節(jié)之前,需要先學(xué)習(xí)以下內(nèi)容:
1.小程序的組件、自定義組件
2.頁(yè)面節(jié)點(diǎn)樹
3.應(yīng)用生命周期、頁(yè)面生命周期(重點(diǎn)是探索的方法)
微信開放文檔:組件的生命周期,指的是組件自身的一些函數(shù),這些函數(shù)在特殊的時(shí)間點(diǎn)或遇到一些特殊的框架事件時(shí)被自動(dòng)觸發(fā)。
和應(yīng)用(小程序)和頁(yè)面一樣,小程序的組件也同樣擁有生命周期。如果你能夠理解上文所介紹的頁(yè)面生命周期,那么組件生命周期對(duì)你而言便不成問(wèn)題。
現(xiàn)在我們來(lái)介紹兩種與組件有關(guān)的生命周期:一種是組件自身的生命周期,一種是組件所在頁(yè)面的生命周期。
我們先來(lái)新建一個(gè)自定義組件,然后打開這個(gè)組件的js文件。不同于我們?cè)趯W(xué)習(xí)應(yīng)用生命周期和頁(yè)面生命周期時(shí)所看到的全局js文件和頁(yè)面的js文件,新建組件時(shí)的js文件中沒(méi)有對(duì)組件生命周期函數(shù)進(jìn)行定義。我們需要自己來(lái)寫生命周期函數(shù)并進(jìn)行相應(yīng)的測(cè)試。
組件自身的生命周期
我們先來(lái)看看組件自身有哪些生命周期函數(shù):
| 生命周期 | 參數(shù) | 描述 |
|---|---|---|
| created | 無(wú) | 在組件實(shí)例剛剛被創(chuàng)建時(shí)執(zhí)行 |
| attached | 無(wú) | 在組件實(shí)例進(jìn)入頁(yè)面節(jié)點(diǎn)樹時(shí)執(zhí)行 |
| ready | 無(wú) | 在組件在視圖層布局完成后執(zhí)行 |
| moved | 無(wú) | 在組件實(shí)例被移動(dòng)到節(jié)點(diǎn)樹另一個(gè)位置時(shí)執(zhí)行 |
| detached | 無(wú) | 在組件實(shí)例被從頁(yè)面節(jié)點(diǎn)樹移除時(shí)執(zhí)行 |
| error | Object Error | 每當(dāng)組件方法拋出錯(cuò)誤時(shí)執(zhí)行 |
其中moved涉及到組件間關(guān)系的相關(guān)內(nèi)容,難度較高,與前兩個(gè)生命周期的關(guān)聯(lián)程度也較少,這里暫時(shí)不做詳細(xì)介紹。
在介紹各個(gè)生命周期函數(shù)之前,我們先要對(duì)生命周期函數(shù)的定義做一點(diǎn)說(shuō)明:
在新建的js文件當(dāng)中,我們能夠看到開發(fā)者工具為我們創(chuàng)建好的框架如下:

根據(jù)微信開放文檔給我們的建議,我們最好不要把組件自身的這些生命周期函數(shù)直接在與properties、data、methods同層級(jí)下聲明,而是在這一層級(jí)下的lifetimes里聲明,例如:
properties: {
},
lifetimes: {
//在這里定義組件自身的生命周期函數(shù)
},
created
組件何時(shí)被小程序創(chuàng)造出來(lái)?當(dāng)組件所在頁(yè)面被調(diào)出來(lái)時(shí),由于組件在頁(yè)面wxml中被調(diào)用,此時(shí)組件必須被創(chuàng)造出來(lái),否則無(wú)法在這個(gè)頁(yè)面當(dāng)中使用。
和之前一樣的測(cè)試方法,給出測(cè)試代碼(放在lifetimes中):
lifetimes:{
created: function() {
console.log("created");
}
}
有了前面的學(xué)習(xí)和練習(xí),那么這段代碼在做什么樣的事情我們就不必再說(shuō)明了。當(dāng)我們打開一個(gè)含有這個(gè)組件的頁(yè)面時(shí),我們就可以看到console中有“created”字符串輸出。
那么它和頁(yè)面的一些生命周期函數(shù)的調(diào)用順序如何呢?
我們接下來(lái)把之前學(xué)習(xí)的頁(yè)面周期函數(shù)中的輸出全部加在頁(yè)面的js文件中,來(lái)看一下效果:

也就是說(shuō),created的調(diào)用時(shí)間點(diǎn)在page.onLoad之前,即組件的創(chuàng)建在頁(yè)面的加載(初始化)之前。
attached
根據(jù)我們剛剛看到的表格,attached函數(shù)是在組件實(shí)例進(jìn)入頁(yè)面節(jié)點(diǎn)樹時(shí)執(zhí)行。組件實(shí)例需要先被創(chuàng)建,然后才能進(jìn)入頁(yè)面節(jié)點(diǎn)樹(有關(guān)頁(yè)面節(jié)點(diǎn)樹相關(guān)問(wèn)題在這里不作詳細(xì)說(shuō)明)。所以我們可以得出,attached函數(shù)是在created函數(shù)之后執(zhí)行。
用代碼測(cè)試一下:
lifetimes:{
attached: function() {
console.log("attached");
}
}
事實(shí)與我們的推斷相符。
那么attached和頁(yè)面生命周期執(zhí)行的先后順序如何?大家可以自行嘗試。
結(jié)果是attached執(zhí)行時(shí)間點(diǎn)晚于created,早于page.onLoad。說(shuō)明頁(yè)面加載的過(guò)程中包含組件實(shí)例進(jìn)入頁(yè)面節(jié)點(diǎn)樹,也就是說(shuō)組件是頁(yè)面的必要成分(如果這個(gè)頁(yè)面有組件的話),組件不先安置好,是沒(méi)有辦法完整加載頁(yè)面的。
ready
ready函數(shù)是在組件在視圖層布局完成后執(zhí)行。你可能會(huì)有些迷惑,視圖層布局完成是什么意思?是在手機(jī)頁(yè)面渲染的過(guò)程?還是在構(gòu)建頁(yè)面視圖、也就是在頁(yè)面加載的過(guò)程中完成的?解決問(wèn)題的辦法,還是測(cè)試。
代碼如下:
lifetimes:{
ready: function() {
console.log("ready");
}
}
具體是在什么時(shí)候,大家可以同樣把用頁(yè)面生命周期的輸出做比對(duì),你會(huì)發(fā)現(xiàn):

(這里面有兩個(gè)ready,其中ready是組件生命周期ready函數(shù)中輸出的,Ready是頁(yè)面生命周期onReady函數(shù)輸出的)
在學(xué)習(xí)頁(yè)面生命周期時(shí),我們就學(xué)習(xí)過(guò),onLoad是在頁(yè)面加載結(jié)束后執(zhí)行,而這個(gè)時(shí)間點(diǎn)也是onShow的執(zhí)行時(shí)間點(diǎn),只是前者先于后者執(zhí)行。這里面我們會(huì)發(fā)現(xiàn),ready是晚于Show的,說(shuō)明這個(gè)組件渲染結(jié)束是在頁(yè)面加載結(jié)束后,在手機(jī)端進(jìn)行頁(yè)面渲染時(shí),頁(yè)面中的組件渲染結(jié)束后執(zhí)行的。頁(yè)面基本都不止含有組件,所以頁(yè)面渲染完成的時(shí)間點(diǎn)一般情況下都會(huì)在組件渲染結(jié)束之后。
detached
detached這個(gè)詞和attached長(zhǎng)得很像,我們也知道,英文單詞中的前綴de-有時(shí)表示反義。那么說(shuō)明detached和attached是反義詞。
attached是在組件實(shí)例進(jìn)入頁(yè)面節(jié)點(diǎn)樹時(shí)執(zhí)行,那顯而易見(jiàn),detached就是在組件實(shí)例被從頁(yè)面節(jié)點(diǎn)樹移除時(shí)執(zhí)行。怎么移除?一個(gè)有組件的頁(yè)面被卸載的過(guò)程中,必然要經(jīng)過(guò)組件被移除的過(guò)程。
我們先來(lái)測(cè)試一下detached函數(shù)執(zhí)行的時(shí)間點(diǎn)。
lifetimes:{
detached: function() {
console.log("detached");
}
}
在測(cè)試前我們可以回想一下,當(dāng)一個(gè)頁(yè)面被卸載時(shí),頁(yè)面生命周期函數(shù)onUnload會(huì)被執(zhí)行。那么究竟是onUnload函數(shù)先執(zhí)行,還是detached函數(shù)先執(zhí)行?在測(cè)試之前,我們可以先猜一猜最后結(jié)果是什么。
接下來(lái)要公布結(jié)果了:

和你猜的結(jié)果是否一樣呢?
對(duì)于這個(gè)結(jié)果,我們有一個(gè)簡(jiǎn)單的理解方法:我們?cè)趯W(xué)習(xí)onUnload時(shí),學(xué)到他是監(jiān)聽(tīng)頁(yè)面卸載時(shí)執(zhí)行的。那它是卸載之前執(zhí)行還是卸載之后執(zhí)行呢?我們可以這樣去想,如果頁(yè)面被卸載后再執(zhí)行,而頁(yè)面已經(jīng)被卸載了,理論上這個(gè)頁(yè)面不會(huì)再跑代碼了。那么這個(gè)onUnload該如何執(zhí)行?或者從它的作用出發(fā)思考,onUnload是我們?cè)陧?yè)面被卸載時(shí)實(shí)現(xiàn)一些我們想做的功能,說(shuō)明這個(gè)功能只能在這個(gè)即將被卸載的頁(yè)面上執(zhí)行。頁(yè)面被卸載了,那又該如何執(zhí)行呢?
所以我們也就可以理解為什么onUnload是在卸載之前執(zhí)行了。既然如此,我們又知道,卸載組件一定是在卸載頁(yè)面的過(guò)程當(dāng)中,也就是說(shuō),在卸載過(guò)程之前執(zhí)行的onUnload一定會(huì)早于在卸載頁(yè)面過(guò)程當(dāng)中、在卸載組件之前(思考方式和onUnload一樣)執(zhí)行的detached。
error
error可是一個(gè)熟面孔了。我們?cè)趹?yīng)用生命周期就學(xué)過(guò)onError,其實(shí)組件自身生命周期的error和onError沒(méi)什么兩樣,同樣要傳遞一個(gè)參數(shù),這個(gè)參數(shù)是一個(gè)Object,用來(lái)記錄錯(cuò)誤信息的。
那么就給出測(cè)試代碼,大家用學(xué)習(xí)onError時(shí)我們使用的方法,試一試這個(gè)error函數(shù)吧!打印一個(gè)字符串“error”,并輸出錯(cuò)誤信息。
代碼如下:
lifetimes:{
error: function(err) {
console.log("error");
console.log(err);
}
}
如何引發(fā)錯(cuò)誤呢?大家在編寫組件時(shí)可以試著做一個(gè)事件綁定,在js中寫函數(shù)時(shí)加入一行錯(cuò)誤代碼即可。這樣在觸發(fā)綁定的事件時(shí)就會(huì)彈錯(cuò),console就會(huì)輸出“error”和字符串,以及和紅框中完全相同的錯(cuò)誤信息(一樣的錯(cuò)誤信息會(huì)看到兩個(gè),一個(gè)是紅底的,是工具自帶的,一個(gè)是我們代碼里輸出的)。
理論上“error”字符串和我們輸出的灰底的錯(cuò)誤信息是挨在一起的,并且在紅底的錯(cuò)誤信息的上方。(其實(shí)這也說(shuō)明工具提供錯(cuò)誤信息的時(shí)間點(diǎn)在組件生命周期之后)。
組件所在頁(yè)面的生命周期
微信開放文檔:還有一些特殊的生命周期,它們并非與組件有很強(qiáng)的關(guān)聯(lián),但有時(shí)組件需要獲知,以便組件內(nèi)部處理。這樣的生命周期稱為“組件所在頁(yè)面的生命周期”。
可用的組件所在頁(yè)面的生命周期有以下三種:
| 生命周期 | 參數(shù) | 描述 |
|---|---|---|
| show | 無(wú) | 組件所在的頁(yè)面被展示時(shí)執(zhí)行 |
| hide | 無(wú) | 組件所在的頁(yè)面被隱藏時(shí)執(zhí)行 |
| resize | 無(wú) | 組件所在的頁(yè)面尺寸變化時(shí)執(zhí)行 |
學(xué)習(xí)過(guò)頁(yè)面生命周期,這些函數(shù)對(duì)我們來(lái)說(shuō)都很好理解。
在學(xué)習(xí)之前我們要說(shuō)明這三個(gè)組件所在頁(yè)面的生命周期的聲明位置。和組件自身的生命周期相似,在小程序中不建議將這些生命周期直接命名在Components之中,也就是不建議與上文的lifetimes同層級(jí)。我們的定義方法是該層級(jí)中的pageLifetimes(L是大寫!)里面聲明。
有了頁(yè)面生命周期和組件自身的生命周期的學(xué)習(xí),這些函數(shù)的測(cè)試方法相信大家已經(jīng)能夠掌握。我們這里就不再過(guò)多敘述,只將測(cè)試代碼一起給出,希望大家自己嘗試測(cè)試。
其中resize函數(shù)的測(cè)試較為特殊,需要啟用屏幕旋轉(zhuǎn)支持。本節(jié)不對(duì)此進(jìn)行詳細(xì)描述,詳見(jiàn)微信開放文檔:響應(yīng)顯示區(qū)域變化
https://developers.weixin.qq.com/miniprogram/dev/framework/view/resizable.html#在手機(jī)上啟用屏幕旋轉(zhuǎn)支持
pageLifetimes: {
show: function() {
console.log("page-show");
},
hide: function() {
console.log("page-hide");
},
resize: function() {
console.log("page-resize")
}
}
小結(jié)
到這里小程序的三種生命周期就全部介紹完了。這三種生命周期的理解,對(duì)自己想實(shí)現(xiàn)的許多功能都有很大的幫助。假如我們?cè)谥疤岬降模涸趯⑿〕绦蚯腥牒笈_(tái)時(shí),一些計(jì)時(shí)器不應(yīng)該繼續(xù)計(jì)時(shí);如何判斷使用小程序的人是否分享了這個(gè)小程序;使用的這個(gè)組件與頁(yè)面相關(guān),當(dāng)這個(gè)頁(yè)面被打開時(shí),組件有這樣的功能,關(guān)閉時(shí)又有那樣的效果……通過(guò)學(xué)習(xí),這些情況的實(shí)現(xiàn)方法,相信大家心中已經(jīng)有答案了。
我們?cè)趯W(xué)習(xí)過(guò)程中,也提到了輸出探索的方法,這也是學(xué)習(xí)這方面內(nèi)容的一個(gè)比較重要的學(xué)習(xí)方法。其實(shí)通過(guò)生命周期的學(xué)習(xí),我們也在著重培養(yǎng)一個(gè)學(xué)習(xí)方式,有一部分的測(cè)試是讓讀者自己來(lái)完成的。如果這些任務(wù)讀者都可以自己完成,并得出結(jié)論,那么這一部分的內(nèi)容便是真正掌握了。
事實(shí)上這三種生命周期有很多地方都是共通的,學(xué)會(huì)了應(yīng)用生命周期,我們就可以舉一反三,在學(xué)習(xí)之前就可以想象出頁(yè)面和組件的生命周期是什么樣子的,是什么樣的原理。在學(xué)習(xí)微信小程序、乃至整個(gè)信息技術(shù)的各個(gè)領(lǐng)域都是一樣,我們?cè)趯W(xué)習(xí)新知識(shí)時(shí),或許都能找到一些我們之前學(xué)到過(guò)的知識(shí)的影子,與那些知識(shí)聯(lián)系起來(lái),構(gòu)建新知識(shí)的架構(gòu),對(duì)這些新知識(shí)的理解會(huì)更進(jìn)一步。
希望對(duì)生命周期的這些介紹與講解對(duì)大家有幫助!
新書介紹
以下是本人3月份出版的新書,拜托多多關(guān)注!

本書利用Python 的標(biāo)準(zhǔn)GUI 工具包tkinter,通過(guò)可執(zhí)行的示例對(duì)23 個(gè)設(shè)計(jì)模式逐個(gè)進(jìn)行說(shuō)明。這樣一方面可以使讀者了解真實(shí)的軟件開發(fā)工作中每個(gè)設(shè)計(jì)模式的運(yùn)用場(chǎng)景和想要解決的問(wèn)題;另一方面通過(guò)對(duì)這些問(wèn)題的解決過(guò)程進(jìn)行說(shuō)明,讓讀者明白在編寫代碼時(shí)如何判斷使用設(shè)計(jì)模式的利弊,并合理運(yùn)用設(shè)計(jì)模式。
對(duì)設(shè)計(jì)模式感興趣而且希望隨學(xué)隨用的讀者通過(guò)本書可以快速跨越從理解到運(yùn)用的門檻;希望學(xué)習(xí)Python GUI 編程的讀者可以將本書中的示例作為設(shè)計(jì)和開發(fā)的參考;使用Python 語(yǔ)言進(jìn)行圖像分析、數(shù)據(jù)處理工作的讀者可以直接以本書中的示例為基礎(chǔ),迅速構(gòu)建自己的系統(tǒng)架構(gòu)。
覺(jué)得本文有幫助?請(qǐng)分享給更多人。
關(guān)注微信公眾號(hào)【面向?qū)ο笏伎肌枯p松學(xué)習(xí)每一天!
面向?qū)ο箝_發(fā),面向?qū)ο笏伎迹?/span>
