組件基礎(chǔ)
組件用來包裝特定的功能,應(yīng)用程序的有序運行依賴于組件之間的協(xié)同工作。
組件是angular應(yīng)用的最小邏輯單元,模塊則是在組件之上的一層抽象。所有angular組件都可以獨立存在,也意味著任何組件都可以作為根組件被引導(dǎo),也可以被路由加載,或在其他組件中使用。不過一個組件不能單獨被啟動,它必須被包裝到模塊里,然后通過Bootstrap模塊接口引導(dǎo)入口模塊來啟動angular應(yīng)用。
創(chuàng)建組件的步驟
創(chuàng)建angular組件三步驟:
- 從
@angular/core中引入Component裝飾器 - 建立一個普通的類,并用
@Component修飾它 - 在
@Component中,設(shè)置selector自定義標(biāo)簽和template模板
//contactItem.component.ts
import { Component } from '@angular/core';
@Component({
selector:'contact-item',
template:`
<div>
<p>張三</p>
<p>13800000</p>
</div>
`
})
export class ContactItemComponent {}
以上代碼創(chuàng)建了一個最簡單的組件。使用這個組件需要在HTML中添加<contact-item>自定義標(biāo)簽,然后angular便會在此標(biāo)簽中插入ContactItemComponent組件中指定的模板。
<div>
<contact-item></contact-item>
</div>
最終會被渲染成:
<div>
<contact-item>
<div>
<p>張三</p>
<p>13800000</p>
</div>
</contact-item>
</div>
組件基礎(chǔ)構(gòu)成
組件裝飾器
@Component是TypeScript的語法,它是一個裝飾器,任何一個angular的組件類都會用這個裝飾器修飾,如果移除了這個裝飾器,它將不再是angular的組件。
組件元數(shù)據(jù)
在ContactItemComponent這個組件中的@Component裝飾器部分,使用到了大部分組件需要的元數(shù)據(jù):用于定義組件標(biāo)簽名的selector;用于定義組件宿主元素模板的template。
1.selector
selector是用于定義組件在HTML代碼中匹配的標(biāo)簽,它將成為組件的命名標(biāo)記。通常情況下都需要設(shè)置selector,特殊情況下也可以忽略,不指定時默認(rèn)為匹配div元素,但不建議這樣做。selector的命名方式建議用“烤肉串式”命名,即采用小寫字母并以“-”分隔。
2.template
template是為組件指定一個內(nèi)聯(lián)模板。使用ES6的多行字符串``語法能夠創(chuàng)建多行模板。
3.templateUrl
templateUrl是為組件指定一個外部模板的URL地址。
@Component({
templateUrl:'app/component/contact-item.html'
})
每個組件只能指定一個模板,可以使用template或templateUrl的引入方式。
4.styles
styles是為組件指定內(nèi)聯(lián)樣式。
@Component({
styles:[
`
li:last-child{
border-bottom:none;
}
`
]
})
5.styleUrls
styleUrls是為組件指定一系列用于該組件的外聯(lián)樣式表文件。
@Component({
styleUrls:['app/list/item.component.css']
})
styles和styleUrls允許同時指定。如果同時指定,styles中的樣式會先被解析,然后才會解析styleUrls中的樣式,換句話說,styles的樣式會被styleUrls的樣式覆蓋。另外,也可以在模板的DOM節(jié)點上直接寫樣式,它的優(yōu)先級最高。
模板
每個組件都必須設(shè)置一個模板,angular才能將組件內(nèi)容渲染到DOM上,這個DOM元素叫做宿主元素。組件可以與宿主元素交互,交互的形式包括:
- 顯示數(shù)據(jù):在模板中可以使用
{{}}來顯示組件的數(shù)據(jù)。
//contactItem.component.ts
import { Component } from '@angular/core';
@Component({
selector:'contact-item',
template:`
<div>
<p>{{name}}</p>
<p>{{phone}}</p>
</div>
`
})
export class ContactItemComponent{
name:string='張三';
phone:string='13800000';
}
- 雙向數(shù)據(jù)綁定:
[(ngModel)]="property" - 監(jiān)聽宿主元素事件以及調(diào)用組件方法:
(click)="addContact()"
組件與模塊
組件通過與其他組件協(xié)作,完成一個完整的功能特性。這樣的功能特性通常會封裝到一個模塊里。
模塊是在組建之上的一層抽象,組件以及指令、管道、服務(wù)、路由等都能通過模塊去組織。
模塊的構(gòu)成
angular提供了@NgModule裝飾器來創(chuàng)建模塊,一個應(yīng)用可以有多個模塊,但有且只有一個根模塊,其他模塊叫做特性模塊。根模塊是啟動應(yīng)用的入口模塊,根模塊必須通過bootstrap元數(shù)據(jù)來指定應(yīng)用的根組件,然后通過bootstrapModule()方法來啟動應(yīng)用。
//app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-brower';
import { ContactItemComponent } from './contactItem.component';
@NgModule({
imports:[BrowserModule],
declarations:[ContactItemComponent],
bootstrap:[ContactItemComponent]
})
export class AppModule {}
//app.ts
import { platformBrowseerDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);
bootstrap這個元數(shù)據(jù)用于指定應(yīng)用的根組件,NgModule主要的元數(shù)據(jù)如下。
- declarations:用于指定屬于這個模塊的視圖類,即指定哪些部件組成了這個模塊。angular有組件、指令和管道三種視圖類,這些視圖類只能屬于一個模塊,不能再次聲明屬于其他模塊的類。
- exports:導(dǎo)出視圖類。當(dāng)該模塊被引入到外部模塊時,這個屬性指定了外部模塊可以使用該模塊的哪些視圖類,所以它的值類型跟
declarations一致(組件、指令和管道)。 - imports:引入該模塊依賴的其他模塊或路由,引入后模塊里的組件模板才能引用外部對應(yīng)的組件、指令和管道。
- providers:指定模塊依賴的服務(wù),引入后該模塊中的所有組件都可以使用這些服務(wù)。
視圖類引入
NgModule提供了declarations這個元數(shù)據(jù)來將指令、組件或管道等視圖類引入到當(dāng)前模塊。
在上面的AppModule中,通過declarations將ContactItemComponent組件引入到了AppModule模塊中,使得所有屬于AppModule模塊的其它組件的模板都可以使用<contact-item>。
//app.module.ts
@NgModule({
declarations:[
AppComponent,
ListComponent,
ListItemComponent,
DetailComponent,
CollectionComponent,
EditComponent,
HeaderComponent,
FooterComponent,
PhonePipe,
BtnClickDirective
]
//...
})
export class AppModule {}
如果在ListComponent組件的模板代碼list.component.html中,使用到了HeaderComponent、FooterComponent和ListItemComponent這三個組件,這個時候必須在ListComponent所屬的模塊(即AppModule)中,通過declarations引入這三個組件和ListItemComponent組件后才能在模板中使用他們。
<!--list.component.html-->
<!--組件中制定了HeaderComponent,才能使用my-header標(biāo)簽-->
<my-header title="所有聯(lián)系" [isShowCreateButton]="true"></my-header>
<ul class="list">
<li *ngFor="let contact of contacts">
<list-item [contact]="contact" (routerNavigate)="routerNavigate($event)"></list-item>
</li>
</ul>
<my-footer></my-footer>
ngFor是angular的內(nèi)置指令,在引入BrowserModule的時候就已經(jīng)引入了常用的內(nèi)置指令。
導(dǎo)出視圖類以及導(dǎo)入依賴模塊
有時候模塊中的組件、指令或管道,可能也會在其他模塊中使用??梢允褂?code>export元數(shù)據(jù)對外暴露這些組件、指令或管道。
//contact.module.ts
import { NgModule } from '@angular/core';
import { ContactItemComponent } from './contactItem.component';
@NgModule({
declarations:[ContactItemComponent],
exports:[ContactItemComponent] //導(dǎo)出組件
})
export class ContactModule {}
//message.module.ts
import { NgModule } from '@angular/core';
import { ContactModule } from './contact.module';
import { SomeOtherComponent } from './someother.component';
@NgModule({
//在SomeOtherComponent組件的模板中可以使用到<contact-item>組件了
declarations:[SomeOtherComponent],
imports:[ContactModule] //導(dǎo)入模塊
})
export class MessageModule {}
服務(wù)引入
服務(wù)通常用于處理業(yè)務(wù)邏輯及相關(guān)的數(shù)據(jù)。引入服務(wù)有兩種方式:一種是通過@NgModule的providers,另一種是通過@Component的providers。
//app.module.ts
import { ContactService } from './shared';
//...
@NgModule({
//...
providers:[ContactService],
bootstrap:[AppComponent]
})
export class AppModule {}
所有被包含在AppModule中的組件,都可以使用到這些服務(wù)。同樣,在組件中也可以用providers來引入服務(wù),該組件及其子組件都可以公用這些引入的服務(wù)。
組件交互
組件交互就是組件通過一定的方式來訪問其他組件的屬性或方法,從而實現(xiàn)數(shù)據(jù)雙向流動。組件交互包括父子組件交互和一些非父子關(guān)系組件的交互。組件交互有很多方式,非父子關(guān)系的組件可以通過服務(wù)來實現(xiàn)數(shù)據(jù)交互通信。
組件的輸入輸出屬性
angular提供了輸入(@Input)和輸出(@Output)語法來處理組件數(shù)據(jù)的流入流出。
//item.component.ts
export class ListItemComponent implements OnInit {
@Input() contact:any={};
@Output() routerNavigate=new EventEmitter<number>();
}
<!--list.component.html-->
<li *ngFor="let contact of contacts">
<list-item [contact]="contact" (routerNavigate)="routerNavigate($event)">
</list-item>
</li>
ListItemComponent組件的作用是顯示單個聯(lián)系人的信息。由于聯(lián)系人列表數(shù)據(jù)是在ListCommponent組建中維護的,在顯示單個聯(lián)系人時,需要給ListItemComponent傳入單個聯(lián)系人數(shù)據(jù)。另外在單擊單個聯(lián)系人時,需要跳轉(zhuǎn)到此聯(lián)系人的明細信息,需要子組件通知父組件進行跳轉(zhuǎn),[contact]和(routerNavigate)的輸入輸出變量,用于滿足上述功能。
這里的輸入輸出是以當(dāng)前組件角度去說的,contact和routerNavigate分別是ListItemComponent組件的輸入和輸出屬性。輸出屬性一般是以事件的形式,將數(shù)據(jù)通過EventEmitter拋出去。
除了使用@Input和@Output修飾外,還可以在組件的元數(shù)據(jù)中使用inputs、output來設(shè)置輸入輸出屬性,設(shè)置的值必須為字符串?dāng)?shù)組,元素的名稱需要和成員變量相對應(yīng)。
@Component({
inputs:['contact'],
outputs:['routerNavigate']
})
export class ListItemComponent implements OnInit {
contact:any={};
routerNavigate=new EventEmitter<number>();
}
父組件向子組件傳遞數(shù)據(jù)
父組件的數(shù)據(jù)通過子組件的輸入屬性流入子組件,在子組件完成接收或攔截,以此實現(xiàn)了數(shù)據(jù)由上而下的傳遞。
父到子組件間的數(shù)據(jù)傳遞
父組件LIstComponent將獲取到聯(lián)系人的數(shù)據(jù),通過屬性綁定的方式流向子組件ListItemComponent。
//list.component.ts
import { Component,OnInit } from '@angular/core';
@Component({
selector:'list',
template:`
<ul class="list">
<li *ngFor="let contact of contacts">
<list-item [contact]="contact"></list-item>
</li>
</ul>
`
})
export class ListComponent implements OnInit {
this.contacts=data;//data為獲取到的聯(lián)系人數(shù)據(jù)
}
//item.component.ts
import { Component,OnInit,Input } from '@angular/core';
@Component({
selector:'list-item',
template:`
<div class="contact-info">
<label class="contact-name">{{contact.name}}</label>
<span class="contact-tel">{{contact.telNum}}</span>
</div>
`
})
export class ListItemComponent implements OnInit {
@Input() contact:any={};
}
在之前的例子中,app.module.ts中已經(jīng)通過@NgModule的元數(shù)據(jù)declarations將子組件ListItemComponent的實例引入到AppModule中,使得所有屬于AppModule中的其他組件都可以使用ListItemComponent組件,因此在父組件ListComponent中可直接引用該子組件。將每個聯(lián)系人對象通過屬性綁定的方式綁定到屬性contact中來供子組件來引用,數(shù)據(jù)由上而下流入子組件,在子組件中通過@Input裝飾器進行數(shù)據(jù)的接收。
攔截輸入屬性
子組件可以攔截輸入屬性的數(shù)據(jù)并進行相應(yīng)的處理。有兩種攔截處理方式。
1.setter攔截輸入屬性
getter和setter通常配套使用,用來對屬性進行相關(guān)約束。他們提供了一些屬性讀寫的封裝。setter可以對屬性進行再封裝處理,對復(fù)雜的內(nèi)部邏輯通過訪問權(quán)限控制來隔絕外部調(diào)用,以避免外部的錯誤調(diào)用影響到內(nèi)部的狀態(tài)。同時也把內(nèi)部復(fù)雜的邏輯結(jié)構(gòu)封裝成高度抽象可被簡單調(diào)用的屬性,再通過getter返回要設(shè)置的屬性值。
通過輸入輸出屬性可以實現(xiàn)父子組件的數(shù)據(jù)交互,還可以通過setter來攔截來自父組件的數(shù)據(jù)源,并進行處理,使數(shù)據(jù)的輸出更合理。
//ListComponent.ts使用前面的例子
//ListItem.component.ts
@Component({
selector:'list-item',
template:`
<div>
<label class="contact-name">{{contactObj.name}}</label>
<span class="contact-tel">{{contactObj.telNum}}</span>
</div>
`
})
export class ListItemComponent implements OnInit{
_contact:object={};
@Input()
set contactObj(contact:object){
this._contact.name=(contact.name&&contact.name.trim())||'no name seet';
this._contact.telNum=contact.telNum||'000-000';
}
get contactObj(){ return this._contact; }
}
這里通過setter的方式設(shè)置一個contactObj屬性對象,其作用是對通過@Input修飾符獲取的數(shù)據(jù)contact進行二次處理,再通過getter返回這個contactObj對象。這樣處理的作用是使得聯(lián)系人不會出現(xiàn)null或undefined的情況。getter和setter其實是在組件類的原型對象上設(shè)置了一個contactObj屬性。
Object.defineProperty(ListItemComponent.prototype,"contactObj",{
//...
})
2.ngOnChanges監(jiān)聽數(shù)據(jù)變化
ngOnChanges用于及時響應(yīng)angular在屬性綁定中發(fā)生的數(shù)據(jù)變化,該方法接收一個對象參數(shù),包含當(dāng)前值和變化前的值。在ngOnInit之前,或者當(dāng)數(shù)據(jù)綁定的輸入屬性的值發(fā)生變化時會觸發(fā)。ngOnChanges是組件的生命周期鉤子之一。
//父組件detail.component.ts
import { Component } from '@angular/core';
@Component({
selector:'detail',
template:`
<a class="edit" (click)="editContact()">編輯</a>
<change-log [contact]="detail"></change-log>
`
})
export class DetailComponent implements OnInit{
detail:any={};
//完成聯(lián)系人編輯修改
editContact(){
//...
this.detail=data;//修改后的數(shù)據(jù)
}
}
//子組件changelog.component.ts
import { Component,Input,OnChanges,SimpleChanges } from '@angular/core';
@Component({
selector:'change-log',
template:`
<h4>Change log:</h4>
<ul>
<li *ngFor="let change of changes">{{change}}</li>
</ul>
`
})
export class ChangeLogComponent implements OnChanges{
@Input() contact:any={};
changes:string[]=[];
ngOnChanges(changes:{[propKey:string]:SimpleChanges}){
let log:string[]=[];
for(let propName in changes){
let changedProp=changes[propName],
from=JSON.stringify(changedProp.previousValue),
to=JSON.stringify(changedProp.currentValue);
log.push(`${propName} changed from ${from} to ${to}`);
}
this.changes.push(log.join(', '));
}
}
SimpleChanges類是angular的一個基礎(chǔ)類,用于處理數(shù)據(jù)的前后變化,其包含兩個重要成員變量,分別是previousValue和currentValue,previousValue是獲取變化前的數(shù)據(jù),currentValue是獲取變化后的數(shù)據(jù)。
ngOnChanges當(dāng)且僅當(dāng)組件輸入數(shù)據(jù)變化時被調(diào)用,“輸入數(shù)據(jù)”指的是通過@Input裝飾器顯式指定的那些數(shù)據(jù)。
子組件向父組件傳遞數(shù)據(jù)
使用事件傳遞是子組件向父組件傳遞數(shù)據(jù)的最常用方式。子組件需要實例化一個用來訂閱和觸發(fā)自定義事件的EventEmitter類,這個實例對象是一個由裝飾器@Output修飾的輸出屬性,當(dāng)有用戶操作行為發(fā)生時該事件會被觸發(fā),父組件則通過事件綁定的方式來訂閱來自子組件觸發(fā)的事件。
//collection.component.ts 父組件
import { Component } from '@angular/core';
@Component({
selector:'collection',
template:`
<contact-collect [contact]="detail" (onCollect)="collectTheContact($event)">
</contact-collect>
`
})
export class CollectionComponent implements OnInit{
detail:any={};
collectTheContact(){
this.detail.collection==0?this.detail.collection=1:this.detail.collection=0;
}
}
父組件CollectionComponent通過綁定自定義事件onCollect訂閱來自子組件觸發(fā)的事件。當(dāng)有來自子組件對應(yīng)的事件被觸發(fā),在父組件中能夠監(jiān)聽到該事件。
//contactCollect.component.ts 子組件
import { Component,EventEmitter,Input,Output } from '@angular/core';
@Component({
selector:'contact-collect',
template:`
<i [ngClass]="{collected:contact.collection}" (click)="collectTheContact()"收藏</i>
`
})
export class ContactCollectComponent {
@Input() contact:any={};
@Output() onCollect=new EventEmitter<boolean>();
collectTheContact(){
this.onCollect.emit();
}
}
其他組件交互方式
父子組件間數(shù)據(jù)傳遞的實現(xiàn)還有兩種方式:
- 父組件通過局部變量獲取子組件引用
- 父組件使用
@ViewChild獲取子組件的引用
通過局部變量實現(xiàn)數(shù)據(jù)交互
模板局部變量可以獲取子組件的實例引用。通過創(chuàng)建模板局部變量的方式,來實現(xiàn)父組件與子組件數(shù)據(jù)交互,即在父組件的模板中為子組件創(chuàng)建一個局部變量,這個父組件可以通過這個局部變量來獲得讀取子組件公共成員變量和函數(shù)的權(quán)限。模板局部變量的作用域范圍僅存在于定義該模板局部變量的子組件。
//父組件collection.component.ts
import { Component } from '@angular/core';
@Component({
selector:'collection',
template:`
<contact-collect (click)="collectTheContact()" #collect></contact-collect>
`
})
export class CollectionComponent {}
//子組件contactcollect.component.ts
import { Component } from '@angular/core';
@Component({
selector:'contact-collect',
template:`
<i [ngClass]="{collect:detail.collection}">收藏</i>
`
})
export class ContactCollectComponent{
detail:any={};
collectTheContact() {
this.deetail.collection==0?this.detail.collection=1:this.detail.collection=0;
}
}
這里通過在標(biāo)簽元素<contact-collect>中放置一個局部變量collect,用來獲取子組件的實例引用,來訪問子組件中的成員變量和方法。
使用@ViewChild實現(xiàn)數(shù)據(jù)交互
當(dāng)父組件需要獲取到子組件中變量或方法的讀寫權(quán)限時,可以通過@ViewChild注入的方式來實現(xiàn)。組件中元數(shù)據(jù)ViewChild的作用是聲明對子組件元素的實例引用,它提供了一個參數(shù)來選擇將要引用的組件元素,這個參數(shù)可以是一個類的實例,也可以是一個字符串。
- 參數(shù)為類實例,表示父組件將綁定一個指令或子組件實例
- 參數(shù)為字符串類型,表示將起到選擇器的作用,即相當(dāng)于在父組件中綁定一個模板局部變量,獲取到子組件的一份實例對象的引用
組件中元數(shù)據(jù)ViewChild的參數(shù)為字符串的實現(xiàn)方式和綁定模板局部變量是一樣的。
import { Component,AfterViewInit,ViewChild } from '@angular/core';
@Component({
selector:'collection',
template:`
<contact-collect (click)="collectTheContact()"></contact-collect>
`
})
export class CollectionComponent{
@ViewChild(ContactCollectComponent) contactCollect:CotactCollectComponent;
ngAfterViewInit(){
//...
}
collectTheContact(){
this.contactCollect.collectTheContact();
}
}
組件內(nèi)容嵌入
內(nèi)容嵌入通常用來創(chuàng)建可復(fù)用組件。
import { Component } from '@angular/core';
@Component({
selector:'example-content',
template:`
<div>
<h4>ng-content 示例</h4>
<div style="background-color:gray;padding:5px;margin:2px">
<ng-content select="header"></ng-content>
</div>
</div>
`
})
class NgContentExampleComponent {}
接著再定義一個根組件來使用它。
import { Component } from 'angular/core';
@Component({
selector:'app',
template:`
<example-content>
<header>Header content</header>
<!--將自定義的內(nèi)容放到 example-content標(biāo)簽之間-->
</example-content>
`
})
export class NgContentAppComponent {}
最后組件的DOM樹會被渲染成:
<app>
<example-content>
<div>
<h4>ng-content示例</h4>
<div style="background-color:gray;padding:5px;margin:2px">
<ng-content select="header"></ng-content>
</div>
</div>
<example-content>
</app>
<example-content>標(biāo)簽之間的內(nèi)容,也就是<header>Header content</header>,被填充到ng-content,而NgContentExampleComponent組件模板中的其他元素沒有受到影響。select="header"表示匹配<example-content>標(biāo)簽之間的第一個header標(biāo)簽,并將其填充到相應(yīng)的ng-content中。
還可以同時使用多個嵌入內(nèi)容。
import { Component } from '@angular/core';
@Component({
selector:'example-content',
template:`
<div>
<h4>component with ng-content</h4>
<div style="background-color:green;padding:5px;margin:2px">
<ng-content select="header"></ng-content>
</div>
<div style="background-color:gray;padding:5px;margin:2px">
<ng-content select=".class-select"></ng-content>
</div>
<div style="background-color:blue;padding:5px;margin:2px">
<ng-content select="[name=footer]"></ng-content>
</div>
</div>
`
})
class NgContentExampleComponent {}
//NgContemtAppComponent.ts
import { Component } from 'angular/core';
@Component({
selector:'app',
template:`
<example-content>
<header>Header content</header>
<div class="class-select">div with .class-content</div>
<div name="footer">Footer content</div>
</example-content>
`
})
export class NgContentAppComponent {}
組件生命周期
組件的生命周期由angular內(nèi)部管理,從組件的創(chuàng)建、創(chuàng)建,到數(shù)據(jù)變動事件的觸發(fā),再到組件從DOM中移除,angular都提供了一系列鉤子。這些鉤子可以在這些事件觸發(fā)時,執(zhí)行相應(yīng)的回調(diào)函數(shù)。
生命周期鉤子
鉤子的接口包含@angular/core中。每個接口都對應(yīng)一個名為ng+接口名的方法。
class ExampleInitHook implements OnInit {
constructor() {}
ngOnInit() {
console.log('OnInit');
}
}
以下是組件常用的生命周期鉤子方法,angular會按以下的順序依次調(diào)用鉤子方法:
- ngOnChanges
- ngOnInit
- ngDoCheck
- ngAfterContentInit
- ngAfterContentChecked
- ngAfterViewInit
- ngAfterViewChecked
- ngOnDestroy
除此之外,有的組件還提供了自己特有的生命周期鉤子,例如路由有routerOnActivate鉤子。
ngOnChanges
ngOnChanges鉤子用來響應(yīng)組件輸入值發(fā)生變化時觸發(fā)的事件。該方法接收一個SimpleChanges對象,包含當(dāng)前值和變化前的值。該方法在ngOnInit之前,或者當(dāng)數(shù)據(jù)綁定輸入屬性的值發(fā)生變化時觸發(fā)。
只要在組件里定義了ngOnChanges方法,在輸入數(shù)據(jù)發(fā)生變化時該方法就會被自動調(diào)用。這里的“輸入數(shù)據(jù)”指的是通過@Input裝飾器顯示指定的變量。
ngOnInit
ngOnInit鉤子用于數(shù)據(jù)綁定輸入屬性之后初始化組件。該鉤子方法會在第一次ngOnChanges之后被調(diào)用。
使用ngOnInit有兩個重要原因:
- 組件構(gòu)造后不久就要進行復(fù)雜的初始化
- 需要在輸入屬性設(shè)置完成之后才構(gòu)建組件
在組件中,經(jīng)常會使用ngOnInit獲取數(shù)據(jù)。
ngDoCheck
用于變化監(jiān)測,該鉤子方法會在每次變化監(jiān)測發(fā)生時被調(diào)用。
每一個變化監(jiān)測周期內(nèi),不管數(shù)據(jù)值是否發(fā)生了變化,ngDoCheck都會被調(diào)用。但要慎用,例如鼠標(biāo)移動時會觸發(fā)mousemove事件,此時變化監(jiān)測會被頻繁觸發(fā),隨之ngDoCheck也會被頻繁調(diào)用。因此,ngDoCheck方法中不能寫復(fù)雜的代碼,否則性能會受影響。
絕大多數(shù)情況下,ngDoCheck和ngOnChanges不應(yīng)該一起使用。ngOnChanges能做的事,ngDoCheck也能做到,而ngDoCheck監(jiān)測的力度更小,可完成更靈活的變化監(jiān)測邏輯。
ngAfterContentInit
在組件中使用<ng-content>將外部內(nèi)容嵌入到組件視圖后就會調(diào)用ngAfterContentInit,它在第一次ngDoCheck執(zhí)行后調(diào)用,且只執(zhí)行一次。
ngAfterContentChecked
在組件使用了<ng-content>自定義內(nèi)容的情況下,angular在這些外部內(nèi)容嵌入到組件視圖后,或每次變化監(jiān)測的時候都會調(diào)用ngAfterContentChecked。
ngAfterViewInit
ngAfterViewInit會在angular創(chuàng)建了組件的視圖及其子視圖之后被調(diào)用。
ngAfterViewChecked
ngAfterViewChecked在angular創(chuàng)建了組件的視圖及其子組件視圖之后被調(diào)用一次,并且在每次子組件變化監(jiān)測時也會被調(diào)用。
ngOnDestroy
ngOnDestroy在銷毀指令/組件之前觸發(fā)。那些不會被垃圾回收器自動回收的資源(如已訂閱的觀察者事件、綁定過的DOM事件、通過setTimeout或setInterval設(shè)置過的計時器等)都應(yīng)當(dāng)在ngOnDestroy中手動銷毀掉,從而避免發(fā)生內(nèi)存泄漏等問題。