詳解Angular組件生命周期(一)
概述
組件聲明周期以及angular的變化發(fā)現(xiàn)機(jī)制

紅色方法只執(zhí)行一次。
變更檢測執(zhí)行的綠色方法和和組件初始化階段執(zhí)行的綠色方法是一個方法。
總共9個方法。
每個鉤子都是@angular/core庫里定義的接口。
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-life',
templateUrl: './life.component.html',
styleUrls: ['./life.component.css']
})
export class LifeComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
雖然接口不是必須的,Angular檢測到鉤子方法就會去執(zhí)行它,還是建議把接口寫上。
一、鉤子的調(diào)用順序
import { Component, OnInit, OnChanges, DoCheck, AfterContentInit, AfterContentChecked, AfterViewInit, AfterViewChecked, OnDestroy, Input, SimpleChange, SimpleChanges } from '@angular/core';
let logIndex: number = 1; //計(jì)數(shù)器
@Component({
selector: 'app-life',
templateUrl: './life.component.html',
styleUrls: ['./life.component.css']
})
export class LifeComponent implements OnInit, OnChanges, DoCheck, AfterContentInit
, AfterContentChecked, AfterViewInit, AfterViewChecked, OnDestroy {
@Input()
name: string;
logIt(msg: string) {
console.log(`# ${logIndex++} ${msg}`);
}
constructor() {
this.logIt("name屬性在constructor里的值是: " + this.name);
}
ngOnInit() {
this.logIt("name屬性在OnInit里的值是: " + this.name);
}
ngOnChanges(changes: SimpleChanges): void { // 傳入一個SimpleChanges對象
let name = changes['name'].currentValue;
this.logIt("name屬性在ngOnChanges里的值是: " + this.name);
}
ngDoCheck(): void {
this.logIt("DoCheck");
}
ngAfterContentInit() {
this.logIt("ngAfterContentInit");
}
ngAfterContentChecked() {
this.logIt("ngAfterContentChecked");
}
ngAfterViewInit() {
this.logIt("ngAfterViewInit");
}
ngAfterViewChecked() {
this.logIt("ngAfterViewChecked");
}
ngOnDestroy() {
this.logIt("ngOnDestory");
}
}

初始化邏輯依賴輸入屬性的值時,初始化邏輯一定要寫在ngOnInit里,不能寫在constructor里面。
DoCheck在Angular的每個變更檢測周期中調(diào)用。
ngAfterContentInit和ngAfterContentChecked跟模版,組件的內(nèi)容投影相關(guān)的。
ngAfterViewInit和ngAfterViewChecked跟組件的模版,初始化視圖相關(guān)的。
二、onChanges鉤子
父組件初始化或修改子組件的輸入?yún)?shù)時會被調(diào)用。
需要先理解js中可變對象 和 不可變對象。
//字符串是不可變的
var greeting = "Hello";
greeting = "Hello World";
//對象是可變的
var user = { name: "Tom" };
user.name = "Jerry";
例子:
child組件有3個屬性,其中2個是輸入屬性。
父組件有一個greeting屬性和一個name屬性是Tom的user對象。
父組件要改變輸入屬性,所以greeting和user.name是雙向綁定。
<div class="parent">
<h2>我是父組件</h2>
<div>問候語:<input type="text" [(ngModel)]="greeting"></div>
<div>
姓名:
<input type="text" [(ngModel)]="user.name">
</div>
<app-child [greeting]="greeting" [(user)]="user"> </app-child>
</div>
父組件改變兩個input的值,值變化時候傳入子組件的值也會變化,傳入子組件的輸入屬性的值變化時會觸發(fā)ngOnChanges()。

父組件初始化子組件。初始化的時候調(diào)一次ngOnChanges(),初始化后子組件的greeting變成Hello,也就是父組件上的greeting的值。
user變成一個name屬性為Tom的對象。

改變輸入屬性的值,父組件問候語greeting改為Helloa。
Angular的變更檢測刷新不可變對象,也就是greeting的值,然后調(diào)用ngOnChanges()方法,greeting的值從之前的hello,變?yōu)榱薍elloa。

修改user.name為Tomb,控制臺上沒有打印新的消息。
因?yàn)橛脩糁皇歉淖兞丝勺儗ο髐ser的屬性,user對象的引用自身是沒有改變的,所以onChanges()方法沒有被調(diào)用。
雖然可變對象的屬性改變不會觸發(fā)ngOnChanges()方法調(diào)用,但是子組件的user對象的屬性仍然改變了,由于Angular的變更監(jiān)測機(jī)制仍然捕獲了組件中每個對象的屬性變化。

改變子組件的message屬性也不引起子組件的onChanges()方法調(diào)用。因?yàn)閙essage不是輸入屬性。而ngOnChanges()只有在輸入屬性變化時候被調(diào)用。
三、變更檢測機(jī)制和DoCheck()鉤子
變更檢測由zone.js實(shí)現(xiàn)的。保證組件的屬性變化和頁面的變化同步。瀏覽器中發(fā)生的異步事件(點(diǎn)擊按鈕,輸入數(shù)據(jù),數(shù)據(jù)從服務(wù)器返回,調(diào)用了setTimeout()方法)都會觸發(fā)變更檢測。
變更檢測運(yùn)行時,檢測組件模版上的所有綁定關(guān)系,如果組件屬性被改變,與其綁定的模版相應(yīng)區(qū)域可能需要更新。
注意:變更檢測機(jī)制只是將組件屬性的改變反應(yīng)到模版上,變更檢測機(jī)制本身永遠(yuǎn)不會改變組件屬性的值。
兩種變更檢測策略。
- Default 檢測到變化,檢查整個組件樹。
- OnPush 只有當(dāng)輸入屬性變化時,才去檢測該組件及其子組件。

Angular應(yīng)用是一個以主組件為根的組件樹,每個組件都會生成一個變更檢測器,任何一個變更檢測器檢測到變化,zone.js就根據(jù)組件的變更檢查策略來檢測組件(也就是調(diào)doCheck()鉤子),來判斷組件是否需要更新它的模版。
DoCheck檢查是從根組件開始往下檢查所有的組件樹,不管變更發(fā)生在哪個組件。
例子:
監(jiān)控user.name這種可變對象的屬性的改變。
在child中加一個oldUsername來存變更前的username,加一個changeDetected屬性標(biāo)志username是否發(fā)生變化,默認(rèn)是false。 noChangeCount計(jì)數(shù)器默認(rèn)是0。
import { Component, OnInit, Input, OnChanges, SimpleChanges, DoCheck } from '@angular/core';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit, OnChanges, DoCheck {
@Input()
greeting: string;
@Input()
user: { name: string };
message: string = "初始化消息";
oldUsername: string;
changeDetected: boolean = false;
noChangeCount: number = 0;
constructor() { }
ngOnInit() {
}
ngOnChanges(changes: SimpleChanges): void {
console.log(JSON.stringify(changes, null, 2));
}
ngDoCheck() {
if (this.user.name !== this.oldUsername) {
this.changeDetected = true;
console.log("DoCheck: user.name 從 " + this.oldUsername + "變?yōu)? + this.user.name);
this.oldUsername = this.user.name;
}
if (this.changeDetected) {//變化來計(jì)數(shù)器清0
this.noChangeCount = 0;
} else {//沒變化
this.noChangeCount++;
console.log("DoCheck:user.name沒變化時ngDoCheck方法已經(jīng)被調(diào)用" + this.noChangeCount + "次")
}
this.changeDetected = false;//最后不管變沒變標(biāo)志位復(fù)位
}
}

頁面加載完成:user.name沒變化時DoCheck方法已經(jīng)被調(diào)用1次。

鼠標(biāo)點(diǎn)擊,不改變?nèi)魏沃?,點(diǎn)擊觸發(fā)變更檢測機(jī)制,所有組件的DoCheck就會被調(diào)用。

修改Tom為Tomb,DoCheck捕捉到Tom變?yōu)門omb。
雖然DoCheck()鉤子可以檢測到user.name什么時候發(fā)生變化,但是使用必須小心,ngDoCheck()鉤子被非常頻繁的調(diào)用。每次變更檢測周期后發(fā)生變化的地方都會調(diào)用。
對ngDoCheck()的實(shí)現(xiàn)必須非常高效,非常輕量級,否則容易引起性能問題。
同理:所有帶Check關(guān)鍵字的鉤子方法都要非常小心。 ngDoCheck,ngAfterContentChecked,ngAfterViewChecked.
以上就是詳解Angular組件生命周期(一)的詳細(xì)內(nèi)容,更多關(guān)于Angular組件生命周期的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
使用AngularJS2中的指令實(shí)現(xiàn)按鈕的切換效果
這篇文章主要介紹了使用AngularJS2中的指令實(shí)現(xiàn)按鈕的切換效果,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-03-03
angular4 如何在全局設(shè)置路由跳轉(zhuǎn)動畫的方法
本篇文章主要介紹了angular4 如何在全局設(shè)置路由跳轉(zhuǎn)動畫的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-08-08
angular動態(tài)刪除ng-repaeat添加的dom節(jié)點(diǎn)的方法
本篇文章主要介紹了angular動態(tài)刪除ng-repaeat添加的dom節(jié)點(diǎn)的方法,非常具有實(shí)用價值,需要的朋友可以參考下2017-07-07
強(qiáng)大的 Angular 表單驗(yàn)證功能詳細(xì)介紹
本篇文章主要介紹了強(qiáng)大的 Angular 表單驗(yàn)證功能詳細(xì)介紹,使用 Angular 的內(nèi)置表單校驗(yàn)?zāi)軌蛲瓿山^大多數(shù)的業(yè)務(wù)場景的校驗(yàn)需求,有興趣的可以了解一下2017-05-05
舉例詳解AngularJS中ngShow和ngHide的使用方法
這篇文章主要介紹了舉例詳解AngularJS中ngShow和ngHide的使用方法,AngularJS是一款非常熱門的JavaScript框架,需要的朋友可以參考下2015-06-06
Angular.JS讀取數(shù)據(jù)庫數(shù)據(jù)調(diào)用完整實(shí)例
這篇文章主要介紹了Angular.JS讀取數(shù)據(jù)庫數(shù)據(jù)調(diào)用,結(jié)合完整實(shí)例形式分析了AngularJS使用$http.get方法與后臺php交互讀取數(shù)據(jù)庫數(shù)據(jù)相關(guān)操作技巧,需要的朋友可以參考下2019-07-07

