各種 Angular 組件構(gòu)成了應(yīng)用的數(shù)據(jù)結(jié)構(gòu)。 組件關(guān)聯(lián)到的 HTML 模板提供了在 Web 頁(yè)面的上下文中顯示數(shù)據(jù)的各種方法。 組件類和模板,共同構(gòu)成了應(yīng)用數(shù)據(jù)的一個(gè)視圖。
在頁(yè)面上把數(shù)據(jù)的值及其表現(xiàn)形式組合起來(lái)的過(guò)程,就叫做數(shù)據(jù)綁定。 通過(guò)將 HTML 模板中的各個(gè)控件綁定到組件類中的各種數(shù)據(jù)屬性,你就把數(shù)據(jù)展示給了用戶(并從該用戶收集數(shù)據(jù))。
另外,你可以使用指令來(lái)向模板中添加邏輯,指令告訴 Angular 在渲染頁(yè)面時(shí)要如何修改。
Angular 定義了一種模板語(yǔ)言,它擴(kuò)展了 HTML 標(biāo)記,其擴(kuò)展語(yǔ)法可以讓你定義各種各樣的數(shù)據(jù)綁定和邏輯指令。 當(dāng)渲染完此頁(yè)面之后,Angular 會(huì)解釋這種模板語(yǔ)法,來(lái)根據(jù)你的邏輯更新 HTML 和數(shù)據(jù)的當(dāng)前狀態(tài)。 在你讀完模板語(yǔ)法這章之前,本頁(yè)中的練習(xí)可以先讓你快速了解下這種模板語(yǔ)法的工作方式。
在這個(gè)示例中,你將創(chuàng)建一個(gè)帶有英雄列表的組件。 你會(huì)顯示出這些英雄的名字清單,某些情況下,還會(huì)在清單下方顯示一條消息。 最終的用戶界面是這樣的:
要顯示組件的屬性,最簡(jiǎn)單的方式就是通過(guò)插值 (interpolation) 來(lái)綁定屬性名。 要使用插值,就把屬性名包裹在雙花括號(hào)里放進(jìn)視圖模板,如 {{myHero}}。
使用 CLI
命令 ng new displaying-data
創(chuàng)建一個(gè)工作空間和一個(gè)名叫 displaying-data
的應(yīng)用。
刪除 "app.component.html" 文件,這個(gè)范例中不再需要它了。
然后,到 "app.component.ts" 文件中修改組件的模板和代碼。
修改完之后,它應(yīng)該是這樣的:
Path:"src/app/app.component.ts"
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<h1>{{title}}</h1>
<h2>My favorite hero is: {{myHero}}</h2>
`
})
export class AppComponent {
title = 'Tour of Heroes';
myHero = 'Windstorm';
}
再把兩個(gè)屬性 title
和 myHero
添加到之前空白的組件中。
修改完的模板會(huì)使用雙花括號(hào)形式的插值來(lái)顯示這兩個(gè)模板屬性:
Path:"src/app/app.component.ts (template)"
template: `
<h1>{{title}}</h1>
<h2>My favorite hero is: {{myHero}}</h2>
`
模板是包在 ECMAScript 2015 反引號(hào) (`) 中的一個(gè)多行字符串。 允許把一個(gè)字符串寫在多行上, 使 HTML 模板更容易閱讀。
Angular 自動(dòng)從組件中提取 title
和 myHero
屬性的值,并且把這些值插入瀏覽器中。當(dāng)這些屬性發(fā)生變化時(shí),Angular 就會(huì)自動(dòng)刷新顯示。
嚴(yán)格來(lái)說(shuō),“重新顯示”是在某些與視圖有關(guān)的異步事件之后發(fā)生的,例如,按鍵、定時(shí)器完成或?qū)?HTTP 請(qǐng)求的響應(yīng)。
注:
- 你沒(méi)有調(diào)用 new 來(lái)創(chuàng)建 AppComponent 類的實(shí)例,是 Angular 替你創(chuàng)建了它。那么它是如何創(chuàng)建的呢?
-@Component
裝飾器中指定的 CSS 選擇器selector
,它指定了一個(gè)叫<app-root&
的元素。 該元素是 "index.html" 文件里的一個(gè)占位符。
Path:"src/index.html (body)"
<body>
<app-root></app-root>
</body>
當(dāng)你通過(guò) "main.ts" 中的 AppComponent
類啟動(dòng)時(shí),Angular 在 "index.html" 中查找一個(gè) <app-root>
元素, 然后實(shí)例化一個(gè) AppComponent
,并將其渲染到 <app-root>
標(biāo)簽中。
運(yùn)行應(yīng)用。它應(yīng)該顯示出標(biāo)題和英雄名:
@Component
元數(shù)據(jù)告訴 Angular 要到哪里去找該組件的模板。 你有兩種方式存放組件的模板。
你可以使用 @Component
裝飾器的 template
屬性來(lái)定義內(nèi)聯(lián)模板。內(nèi)聯(lián)模板對(duì)于小型示例或測(cè)試很有用。
此外,你還可以把模板定義在單獨(dú)的 HTML 文件中,并且讓 @Component
裝飾器的 templateUrl
屬性指向該文件。這種配置方式通常用于所有比小型測(cè)試或示例更復(fù)雜的場(chǎng)景中,它也是生成新組件時(shí)的默認(rèn)值。
無(wú)論用哪種風(fēng)格,模板數(shù)據(jù)綁定在訪問(wèn)組件屬性方面都是完全一樣的。 這里的應(yīng)用使用了內(nèi)聯(lián) HTML,是因?yàn)樵撃0搴苄?,而且示例也很?jiǎn)單,用不到外部 HTML 文件。
ng generate component
在生成組件時(shí)會(huì)帶有模板文件,你可以通過(guò)參數(shù)來(lái)覆蓋它:ng generate component hero -t
下面的例子使用變量賦值來(lái)對(duì)組件進(jìn)行初始化。
export class AppComponent {
title: string;
myHero: string;
constructor() {
this.title = 'Tour of Heroes';
this.myHero = 'Windstorm';
}
}
你可以用構(gòu)造函數(shù)來(lái)代替這些屬性的聲明和初始化語(yǔ)句。
*ngFor
指令(Angular 預(yù)置)可以讓你循環(huán)遍歷數(shù)據(jù)。下面的例子使用該指令來(lái)顯示數(shù)組型屬性中的所有值。
要顯示一個(gè)英雄列表,先向組件中添加一個(gè)英雄名字?jǐn)?shù)組,然后把 myHero
重定義為數(shù)組中的第一個(gè)名字。
Path:"src/app/app.component.ts (class)"
export class AppComponent {
title = 'Tour of Heroes';
heroes = ['Windstorm', 'Bombasto', 'Magneta', 'Tornado'];
myHero = this.heroes[0];
}
接著,在模板中使用 Angular 的 ngFor
指令來(lái)顯示 heroes 列表中的每一項(xiàng)。
Path:"src/app/app.component.ts (template)"
template: `
<h1>{{title}}</h1>
<h2>My favorite hero is: {{myHero}}</h2>
<p>Heroes:</p>
<ul>
<li *ngFor="let hero of heroes">
{{ hero }}
</li>
</ul>
`
這個(gè)界面使用了由 <ul>
和 <li>
標(biāo)簽組成的無(wú)序列表。<li>
元素里的 *ngFor
是 Angular 的“迭代”指令。 它將 <li>
元素及其子級(jí)標(biāo)記為“迭代模板”:
Path:"src/app/app.component.ts (li)"
<li *ngFor="let hero of heroes">
{{ hero }}
</li>
注:
- 不要忘記*ngFor
中的前導(dǎo)星號(hào) (*
)。它是語(yǔ)法中不可或缺的一部分。
注意看 ngFor
雙引號(hào)表達(dá)式中的 hero
,它是一個(gè)模板輸入變量。 更多模板輸入變量的信息,見(jiàn)模板語(yǔ)法中的 微語(yǔ)法 (microsyntax
)。
Angular 為列表中的每個(gè)條目復(fù)制一個(gè) <li>
元素,在每個(gè)迭代中,把 hero
變量設(shè)置為當(dāng)前條目(英雄)。 Angular 把 hero
變量作為雙花括號(hào)插值的上下文。
本例中,
ngFor
用于顯示一個(gè)“數(shù)組”, 但ngFor
可以為任何可迭代的 (iterable
) 對(duì)象重復(fù)渲染條目。
現(xiàn)在,英雄們出現(xiàn)在了一個(gè)無(wú)序列表中。
應(yīng)用代碼直接在組件內(nèi)部直接定義了數(shù)據(jù)。 作為演示還可以,但它顯然不是最佳實(shí)踐。
現(xiàn)在使用的是到了一個(gè)字符串?dāng)?shù)組的綁定。在真實(shí)的應(yīng)用中,大多是到一個(gè)對(duì)象數(shù)組的綁定。
要將此綁定轉(zhuǎn)換成使用對(duì)象,需要把這個(gè)英雄名字?jǐn)?shù)組變成 Hero
對(duì)象數(shù)組。但首先得有一個(gè) Hero
類。
ng generate class hero
此命令創(chuàng)建了如下代碼:
Path:"src/app/hero.ts"
export class Hero {
constructor(
public id: number,
public name: string) { }
}
你定義了一個(gè)類,具有一個(gè)構(gòu)造函數(shù)和兩個(gè)屬性:id
和 name
。
它可能看上去不像是有屬性的類,但它確實(shí)有,利用的是 TypeScript 提供的簡(jiǎn)寫形式 —— 用構(gòu)造函數(shù)的參數(shù)直接定義屬性。
來(lái)看第一個(gè)參數(shù):
Path:"src/app/hero.ts (id)"
public id: number,
這個(gè)簡(jiǎn)寫語(yǔ)法做了很多:
導(dǎo)入了 Hero 類之后,組件的 heroes 屬性就可以返回一個(gè)類型化的Hero 對(duì)象數(shù)組了。
Path:"src/app/app.component.ts (heroes)"
heroes = [
new Hero(1, 'Windstorm'),
new Hero(13, 'Bombasto'),
new Hero(15, 'Magneta'),
new Hero(20, 'Tornado')
];
myHero = this.heroes[0];
接著,修改模板。 現(xiàn)在它顯示的是英雄的 id
和 name
。 要修復(fù)它,只顯示英雄的 name
屬性就行了。
Path:"src/app/app.component.ts (template)"
template: `
<h1>{{title}}</h1>
<h2>My favorite hero is: {{myHero.name}}</h2>
<p>Heroes:</p>
<ul>
<li *ngFor="let hero of heroes">
{{ hero.name }}
</li>
</ul>
`
顯示上還和以前一樣,不過(guò)代碼更清晰了。
有時(shí),應(yīng)用需要只在特定情況下顯示視圖或視圖的一部分。
來(lái)改一下這個(gè)例子,如果多于三位英雄,顯示一條消息。
Angular 的 ngIf
指令會(huì)根據(jù)一個(gè)布爾條件來(lái)顯示或移除一個(gè)元素。 來(lái)看看實(shí)際效果,把下列語(yǔ)句加到模板的底部:
Path:"src/app/app.component.ts (message)"
<p *ngIf="heroes.length > 3">There are many heroes!</p>
雙引號(hào)內(nèi)的模板表達(dá)式 *ngIf="heroes.length > 3"
的外觀和行為與 TypeScript 非常相似。當(dāng)組件的英雄列表包含三個(gè)以上的條目時(shí),Angular 會(huì)將這段話添加到 DOM 中,這條消息就顯示出來(lái)了。如果只有三個(gè)或更少的條目,Angular 就會(huì)省略該段落,也就不會(huì)顯示任何消息。
雙引號(hào)中的模板表達(dá)式 *ngIf="heros.length > 3"
,外觀和行為很象 TypeScript。 當(dāng)組件中的英雄列表有三個(gè)以上的條目時(shí),Angular 就會(huì)把這個(gè)段落添加到 DOM 中,于是消息顯示了出來(lái)。 如果有三個(gè)或更少的條目,則 Angular 會(huì)省略這些段落,所以不顯示消息。
注:
- Angular 并不是在顯示和隱藏這條消息,它是在從 DOM 中添加和移除這個(gè)段落元素。 這會(huì)提高性能,特別是在一些大的項(xiàng)目中有條件地包含或排除一大堆帶著很多數(shù)據(jù)綁定的 HTML 時(shí)。
試一下。因?yàn)檫@個(gè)數(shù)組中有四個(gè)條目,所以消息應(yīng)該顯示出來(lái)。 回到 "app.component.ts",從英雄數(shù)組中刪除或注釋掉一個(gè)元素。 瀏覽器應(yīng)該自動(dòng)刷新,消息應(yīng)該會(huì)消失。
import { Component } from '@angular/core';
import { Hero } from './hero';
@Component({
selector: 'app-root',
template: `
<h1>{{title}}</h1>
<h2>My favorite hero is: {{myHero.name}}</h2>
<p>Heroes:</p>
<ul>
<li *ngFor="let hero of heroes">
{{ hero.name }}
</li>
</ul>
<p *ngIf="heroes.length > 3">There are many heroes!</p>
`
})
export class AppComponent {
title = 'Tour of Heroes';
heroes = [
new Hero(1, 'Windstorm'),
new Hero(13, 'Bombasto'),
new Hero(15, 'Magneta'),
new Hero(20, 'Tornado')
];
myHero = this.heroes[0];
}
export class Hero {
constructor(
public id: number,
public name: string) { }
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
@NgModule({
imports: [
BrowserModule
],
declarations: [
AppComponent
],
bootstrap: [ AppComponent ]
})
export class AppModule { }
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule);
現(xiàn)在您知道了如何使用:
interpolation
) 來(lái)顯示一個(gè)組件屬性。ngFor
顯示數(shù)組。ngIf
根據(jù)一個(gè)布爾表達(dá)式有條件地顯示一段 HTML。
更多建議: