組件控制屏幕上被稱為視圖的一小片區(qū)域。比如,教程中的下列視圖都是由一個個組件所定義和控制的:
你在類中定義組件的應(yīng)用邏輯,為視圖提供支持。 組件通過一些由屬性和方法組成的 API 與視圖交互。
比如,HeroListComponent 中有一個 名為 heroes
的屬性,它儲存著一個數(shù)組的英雄數(shù)據(jù)。 HeroListComponent 還有一個 selectHero()
方法,當(dāng)用戶從列表中選擇一個英雄時,它會設(shè)置 selectedHero
屬性的值。 該組件會從服務(wù)獲取英雄列表,它是一個 TypeScript 的構(gòu)造器參數(shù)型屬性。本服務(wù)通過依賴注入系統(tǒng)提供給該組件。
export class HeroListComponent implements OnInit {
heroes: Hero[];
selectedHero: Hero;
constructor(private service: HeroService) { }
ngOnInit() {
this.heroes = this.service.getHeroes();
}
selectHero(hero: Hero) { this.selectedHero = hero; }
}
當(dāng)用戶在應(yīng)用中穿行時,Angular 就會創(chuàng)建、更新、銷毀一些組件。 你的應(yīng)用可以通過一些可選的生命周期鉤子(比如 ngOnInit()
)來在每個特定的時機采取行動。
@Component 裝飾器會指出緊隨其后的那個類是個組件類,并為其指定元數(shù)據(jù)。 在下面的范例代碼中,你可以看到 HeroListComponent 只是一個普通類,完全沒有 Angular 特有的標記或語法。 直到給它加上了 @Component 裝飾器,它才變成了組件。
組件的元數(shù)據(jù)告訴 Angular 到哪里獲取它需要的主要構(gòu)造塊,以創(chuàng)建和展示這個組件及其視圖。 具體來說,它把一個模板(無論是直接內(nèi)聯(lián)在代碼中還是引用的外部文件)和該組件關(guān)聯(lián)起來。 該組件及其模板,共同描述了一個視圖。
除了包含或指向模板之外,@Component 的元數(shù)據(jù)還會配置要如何在 HTML 中引用該組件,以及該組件需要哪些服務(wù)等等。
下面的例子中就是 HeroListComponent 的基礎(chǔ)元數(shù)據(jù):
@Component({
selector: 'app-hero-list',
templateUrl: './hero-list.component.html',
providers: [ HeroService ]
})
export class HeroListComponent implements OnInit {
/* . . . */
}
這個例子展示了一些最常用的 @Component 配置選項:
你要通過組件的配套模板來定義其視圖。模板就是一種 HTML,它會告訴 Angular 如何渲染該組件。
視圖通常會分層次進行組織,讓你能以 UI 分區(qū)或頁面為單位進行修改、顯示或隱藏。 與組件直接關(guān)聯(lián)的模板會定義該組件的宿主視圖。該組件還可以定義一個帶層次結(jié)構(gòu)的視圖,它包含一些內(nèi)嵌的視圖作為其它組件的宿主。
帶層次結(jié)構(gòu)的視圖可以包含同一模塊(NgModule)中組件的視圖,也可以(而且經(jīng)常會)包含其它模塊中定義的組件的視圖。
模板很像標準的 HTML,但是它還包含 Angular 的模板語法,這些模板語法可以根據(jù)你的應(yīng)用邏輯、應(yīng)用狀態(tài)和 DOM 數(shù)據(jù)來修改這些 HTML。 你的模板可以使用數(shù)據(jù)綁定來協(xié)調(diào)應(yīng)用和 DOM 中的數(shù)據(jù),使用管道在顯示出來之前對其進行轉(zhuǎn)換,使用指令來把程序邏輯應(yīng)用到要顯示的內(nèi)容上。
比如,下面是本教程中 HeroListComponent 的模板:
<h2>Hero List</h2>
<p><i>Pick a hero from the list</i></p>
<ul>
<li *ngFor="let hero of heroes" (click)="selectHero(hero)">
{{hero.name}}
</li>
</ul>
<app-hero-detail *ngIf="selectedHero" [hero]="selectedHero"></app-hero-detail>
這個模板使用了典型的 HTML 元素,比如 <h2>
和 <p>
,還包括一些 Angular 的模板語法元素,如 *ngFor
,{{hero.name}}
,click
、[hero]
和 <app-hero-detail>
。這些模板語法元素告訴 Angular 該如何根據(jù)程序邏輯和數(shù)據(jù)在屏幕上渲染 HTML。
*ngFor
指令告訴 Angular 在一個列表上進行迭代。{{hero.name}}
、(click)
和 [hero]
把程序數(shù)據(jù)綁定到及綁定回 DOM,以響應(yīng)用戶的輸入。更多內(nèi)容參見稍后的數(shù)據(jù)綁定部分。<app-hero-detail>
標簽是一個代表新組件 HeroDetailComponent 的元素。 HeroDetailComponent(代碼略)定義了 HeroListComponent 的英雄詳情子視圖。 注意觀察像這樣的自定義組件是如何與原生 HTML 元素?zé)o縫的混合在一起的。如果沒有框架,你就要自己負責(zé)把數(shù)據(jù)值推送到 HTML 控件中,并把來自用戶的響應(yīng)轉(zhuǎn)換成動作和對值的更新。 手動寫這種數(shù)據(jù)推拉邏輯會很枯燥、容易出錯,難以閱讀 —— 有前端 JavaScript 開發(fā)經(jīng)驗的程序員一定深有體會。
Angular 支持雙向數(shù)據(jù)綁定,這是一種對模板中的各個部件與組件中的各個部件進行協(xié)調(diào)的機制。 往模板 HTML 中添加綁定標記可以告訴 Angular 該如何連接它們。
下圖顯示了數(shù)據(jù)綁定標記的四種形式。每種形式都有一個方向 —— 從組件到 DOM、從 DOM 到組件或雙向。
這個來自 HeroListComponent 模板中的例子展示了其中的三種形式:
<li>{{hero.name}}</li>
<app-hero-detail [hero]="selectedHero"></app-hero-detail>
<li (click)="selectHero(hero)"></li>
雙向數(shù)據(jù)綁定(主要用于模板驅(qū)動表單中),它會把屬性綁定和事件綁定組合成一種單獨的寫法。下面這個來自 HeroDetailComponent 模板中的例子通過 ngModel 指令使用了雙向數(shù)據(jù)綁定:
<input [(ngModel)]="hero.name">
在雙向綁定中,數(shù)據(jù)屬性值通過屬性綁定從組件流到輸入框。用戶的修改通過事件綁定流回組件,把屬性值設(shè)置為最新的值。
Angular 在每個 JavaScript 事件循環(huán)中處理所有的數(shù)據(jù)綁定,它會從組件樹的根部開始,遞歸處理全部子組件。
數(shù)據(jù)綁定在模板及其組件之間的通訊中扮演了非常重要的角色,它對于父組件和子組件之間的通訊也同樣重要。
Angular 的管道可以讓你在模板中聲明顯示值的轉(zhuǎn)換邏輯。 帶有 @Pipe 裝飾器的類中會定義一個轉(zhuǎn)換函數(shù),用來把輸入值轉(zhuǎn)換成供視圖顯示用的輸出值。
Angular 自帶了很多管道,比如 date
管道和 currency
管道,完整的列表參見 Pipes API 列表。你也可以自己定義一些新管道。
要在 HTML 模板中指定值的轉(zhuǎn)換方式,請使用 管道操作符 (|
)。
{{interpolated_value | pipe_name}}
你可以把管道串聯(lián)起來,把一個管道函數(shù)的輸出送給另一個管道函數(shù)進行轉(zhuǎn)換。 管道還能接收一些參數(shù),來控制它該如何進行轉(zhuǎn)換。比如,你可以把要使用的日期格式傳給 date
管道:
<!-- Default format: output 'Jun 15, 2015'-->
<p>Today is {{today | date}}</p>
<!-- fullDate format: output 'Monday, June 15, 2015'-->
<p>The date is {{today | date:'fullDate'}}</p>
<!-- shortTime format: output '9:43 AM'-->
<p>The time is {{today | date:'shortTime'}}</p>
Angular 的模板是動態(tài)的。當(dāng) Angular 渲染它們的時候,會根據(jù)指令給出的指示對 DOM 進行轉(zhuǎn)換。 指令就是一個帶有 @Directive()
裝飾器的類。
組件從技術(shù)角度上說就是一個指令,但是由于組件對 Angular 應(yīng)用來說非常獨特、非常重要,因此 Angular 專門定義了 @Component()
裝飾器,它使用一些面向模板的特性擴展了 @Directive()
裝飾器。
除組件外,還有兩種指令:結(jié)構(gòu)型指令和屬性型指令。 Angular 本身定義了一系列這兩種類型的指令,你也可以使用 @Directive()
裝飾器來定義自己的指令。
像組件一樣,指令的元數(shù)據(jù)把它所裝飾的指令類和一個 selector
關(guān)聯(lián)起來,selector
用來把該指令插入到 HTML 中。 在模板中,指令通常作為屬性出現(xiàn)在元素標簽上,可能僅僅作為名字出現(xiàn),也可能作為賦值目標或綁定目標出現(xiàn)。
1. 結(jié)構(gòu)型指令
結(jié)構(gòu)型指令通過添加、移除或替換 DOM 元素來修改布局。 這個范例模板使用了兩個內(nèi)置的結(jié)構(gòu)型指令來為要渲染的視圖添加程序邏輯:
<li *ngFor="let hero of heroes"></li>
<app-hero-detail *ngIf="selectedHero"></app-hero-detail>
*ngFor
是一個迭代器,它要求 Angular 為 heroes 列表中的每個英雄渲染出一個 <li>
。*ngIf
是個條件語句,只有當(dāng)選中的英雄存在時,它才會包含 HeroDetail 組件。2. 屬性型指令
屬性型指令會修改現(xiàn)有元素的外觀或行為。 在模板中,它們看起來就像普通的 HTML 屬性一樣,因此得名“屬性型指令”。
ngModel 指令就是屬性型指令的一個例子,它實現(xiàn)了雙向數(shù)據(jù)綁定。 ngModel 修改現(xiàn)有元素(一般是 <input>
)的行為:設(shè)置其顯示屬性值,并響應(yīng) change 事件。
<input [(ngModel)]="hero.name">
注:
- Angular 還有很多預(yù)定義指令,有些修改布局結(jié)構(gòu)(比如ngSwitch
),有些修改 DOM 元素和組件的樣子(比如ngStyle
和ngClass
)。
- 參考 [Angular9 結(jié)構(gòu)型指令]() 和 [Angular9 屬性型指令]() 以了解 Angular 兩種指令類型。
更多建議: