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