概述
Angular2+(后面就直接用Angular代替了)中的每個(gè)組件都存在一個(gè)生命周期,從創(chuàng)建,變更到銷毀。Angular提供組件生命周期鉤子,把這些關(guān)鍵時(shí)刻暴露出來,賦予在這些關(guān)鍵結(jié)點(diǎn)和組件進(jìn)行交互的能力。熟悉這些生命鉤子的實(shí)現(xiàn),對(duì)于我們處理組件交互邏輯將會(huì)有很大幫助。
生命周期類型有:ngOnInit、ngOnChanges、ngDoCheck、ngContentInit、ngContentChecked、ngAfterViewInit、ngAfterViewChecked、ngOnDestory。
其實(shí)現(xiàn)方法如下:
export class ExampleComponent implements OnChanges, OnInit, DoCheck, AfterContentInit,
AfterContentChecked, AfterViewInit, AfterViewChecked, OnDestroy {
ngOnChanges() {
}
ngOnInit() {
}
ngDoCheck() {
}
ngAfterContentInit() {
}
ngAfterContentChecked() {
}
ngAfterViewInit() {
}
ngAfterViewChecked() {
}
ngOnDestroy() {
}
}
執(zhí)行順序
一個(gè)組件的最小完整生命周期執(zhí)行順序如下:

注:angular中的每個(gè)組件都是typescript中一個(gè)加了@Component裝飾器的class,所以在組件實(shí)例化時(shí)最先執(zhí)行constructor()
下面著重選擇了幾個(gè)常用的生命鉤子進(jìn)行說明。
詳細(xì)說明
ngOnChanges
ngOnChanges()在組件設(shè)置的綁定輸入屬性(如通過@Input、[(ngModel)]綁定)發(fā)生變化時(shí)執(zhí)行,默認(rèn)在組件初始化時(shí)于ngOnInit()前調(diào)用一次。
ngOnChanges()有一個(gè)默認(rèn)的參數(shù),它是一個(gè)SimpleChange對(duì)象,這個(gè)對(duì)象中記錄了發(fā)生變化屬性的前一個(gè)值和當(dāng)前值。一般用法如下:
export class ExampleComponent implements OnChanges {
@Input() value: any;
ngOnChanges(simpleChanges: SimpleChanges) {
if (simpleChanges.hasOwnProperty('value')) {
// do something
}
}
}
ngOnInit
ngOnInit()在組件初始化時(shí)執(zhí)行,并且整個(gè)生命周期只會(huì)執(zhí)行一次。主要用于設(shè)置完輸入屬性后對(duì)組件進(jìn)行準(zhǔn)備,以及處理一些復(fù)雜的初始化邏輯。
這里需要注意一點(diǎn),constructor()和ngOnInit()同樣用于組件初始化時(shí)處理一些邏輯,但是我們應(yīng)該避免復(fù)雜的構(gòu)造函數(shù)邏輯。具體原因,Misko Hevery在他這篇文章中詳細(xì)解釋過。主要由于以下幾點(diǎn):
復(fù)雜的構(gòu)造函數(shù)邏輯,尤其是依賴其他組件、服務(wù)的邏輯會(huì)違背單一職責(zé)原則,并且不符合我們?cè)O(shè)計(jì)組件的理念,對(duì)于實(shí)現(xiàn)組件的靈活性與解耦不利;
由于實(shí)例化一個(gè)對(duì)象時(shí),constructor()必須執(zhí)行,那么復(fù)雜的構(gòu)造函數(shù)邏輯將會(huì)對(duì)于我們測(cè)試這個(gè)組件產(chǎn)生很大的麻煩;
基于上一條,angular中每個(gè)組件實(shí)際上就是一個(gè)class,從面向?qū)ο蟮慕嵌?,它是可以被繼承、重載的,所以,同理,測(cè)試復(fù)雜的構(gòu)造函數(shù)的繼承和重載對(duì)測(cè)試將無(wú)疑是一種災(zāi)難。
ngDoCheck、ngAfterContentChecked、ngAfterViewChecked
ngDoCheck主要用于檢測(cè)Angular無(wú)法捕獲的變更并進(jìn)行處理,但是我覺得實(shí)際應(yīng)用中應(yīng)該避免使用這個(gè)鉤子。因?yàn)檫@個(gè)鉤子十分消耗性能,每次調(diào)用都會(huì)檢測(cè)所有的屬性和方法,并且觸發(fā)機(jī)制十分敏感。實(shí)測(cè)中,輕輕劃動(dòng)下鼠標(biāo),這個(gè)方法就能觸發(fā)幾十次。
當(dāng)然,如果非要用到這個(gè)鉤子,建議在組件內(nèi)設(shè)置個(gè)變量,保證ngDoCheck()內(nèi)的邏輯在有限次內(nèi)運(yùn)行,從而避免性能的巨大消耗。
ngAfterContentChecked和ngAfterViewChecked,分別會(huì)在ngAfterContentInit和ngAfterViewInit后運(yùn)行一次,主要用于組件內(nèi)容檢測(cè)和視圖檢測(cè)。但是我之所以放在這里和ngDoCheck一起介紹,是因?yàn)閚gAfterContentChecked會(huì)在ngDoCheck每次調(diào)用后調(diào)用一次,而ngAfterViewChecked會(huì)在ngAfterContentChecked每次調(diào)用后調(diào)用一次。所以,鑒于ngDoCheck糟糕的性能,這兩個(gè)也少用吧。
ngOnDestroy
ngOnDestroy在組件銷毀前的最后一個(gè)節(jié)點(diǎn)運(yùn)行,主要用于處理一些清理邏輯。我在使用過程中主要用來做兩件事,一是用來釋放一些gc不會(huì)自動(dòng)回收的資源,二是用來釋放一些業(yè)務(wù)邏輯中沒有必要再使用的資源(如對(duì)一些Observable對(duì)象、DOM事件的訂閱,全局服務(wù)的回調(diào),以及l(fā)ocalstorage中的數(shù)據(jù))。這個(gè)對(duì)于我們防止內(nèi)存泄露還是很有幫助的。
最后說兩句,最近項(xiàng)目框架在從angularjs轉(zhuǎn)向angular2+,已經(jīng)初步進(jìn)行了一段時(shí)間,這過程中也踩了不少坑。目前正在嘗試著總結(jié),先寫了點(diǎn)自己認(rèn)為比較重要的東西。總得來說,還是個(gè)搬運(yùn)工吧。如果有對(duì)angular2+ 感興趣的同學(xué),也可以去這個(gè)網(wǎng)站(翻譯得很良心)上學(xué)習(xí),或者與我一起討論,歡迎大家=。=