Angular 顯示英雄列表

在本頁面,你將擴展《英雄指南》應用,讓它顯示一個英雄列表, 並容許用戶選擇一個英雄,查看該英雄的詳細信息。css

建立模擬(mock)英雄數據

你須要一些英雄數據以供顯示。html

最終,你會從遠端的數據服務器獲取它。可是目前,你須要建立一些模擬英雄(some mock heroes),並假設這些數據是從遠程服務器上獲取的。git

在 src/app/ 文件夾中建立一個名叫 mock-heroes.ts 的文件。 定義一個包含十個英雄的常量數組 HEROES,並導出它。 該文件是這樣的。github

src/app/mock-heroes.tsapi

import { Hero } from './hero';數組

 

export const HEROES: Hero[] = [瀏覽器

  { id: 11, name: 'Mr. Nice' },服務器

  { id: 12, name: 'Narco' },app

  { id: 13, name: 'Bombasto' },ide

  { id: 14, name: 'Celeritas' },

  { id: 15, name: 'Magneta' },

  { id: 16, name: 'RubberMan' },

  { id: 17, name: 'Dynama' },

  { id: 18, name: 'Dr IQ' },

  { id: 19, name: 'Magma' },

  { id: 20, name: 'Tornado' }

];

顯示英雄

你要在 HeroesComponent 的頂部顯示這個英雄列表。

打開 HeroesComponent 類文件,並導入模擬的 HEROES 數據。

src/app/heroes/heroes.component.ts

import { HEROES } from '../mock-heroes';

往類中添加一個 heroes 屬性,這樣能夠暴露出這些英雄,以供綁定。

src/app/heroes/heroes.component.ts

export class HeroesComponent implements OnInit {

 

  heroes = HEROES;

使用 *ngFor 列出這些英雄

打開 HeroesComponent 的模板文件,並作以下修改:

  • 在頂部添加 <h2>
  • 而後添加表示無序列表的 HTML 元素(<ul>
  • 在 <ul> 中插入一個 <li> 元素,以顯示單個 hero 的屬性。
  • 點綴上一些 CSS 類(稍後你還會添加更多 CSS 樣式)。

完成後應該以下顯示:

heroes.component.html

heroes.component.html (heroes template)

content_copy

<h2>My Heroes</h2>

<ul class="heroes">

  <li>

    <span class="badge">{{hero.id}}</span> {{hero.name}}

  </li>

</ul>

如今,把 <li> 修改爲這樣:

<li *ngFor="let hero of heroes">

*ngFor 是一個 Angular 的複寫器(repeater)指令。 它會爲列表中的每項數據複寫它的宿主元素。

在這個例子中

  • <li> 就是 *ngFor 的宿主元素
  • heroes 就是來自 HeroesComponent 類的列表。
  • 當依次遍歷這個列表時,hero 會爲每一個迭代保存當前的英雄對象。

不要忘了 ngFor 前面的星號(*),它是該語法中的關鍵部分。

瀏覽器刷新以後,英雄列表出現了。

給英雄們應用樣式表

英雄列表應該富有吸引力,而且當用戶把鼠標移到某個英雄上和從列表中選中某個英雄時,應該給出視覺反饋。

教程的第一章,你曾在 styles.css 中爲整個應用設置了一些基礎的樣式。 但那個樣式表並不包含英雄列表所需的樣式。

當然,你能夠把更多樣式加入到 styles.css,而且聽任它隨着你添加更多組件而不斷膨脹。

但還有更好的方式。你能夠定義屬於特定組件的私有樣式,而且讓組件所需的一切(代碼、HTML 和 CSS)都放在一塊兒。

這種方式讓你在其它地方複用該組件更加容易,而且即便全局樣式和這裏不同,組件也仍然具備指望的外觀。

你能夠用多種方式定義私有樣式,或者內聯在 @Component.styles 數組中,或者在 @Component.styleUrls 所指出的樣式表文件中。

當 CLI 生成 HeroesComponent 時,它也同時爲 HeroesComponent 建立了空白的 heroes.component.css 樣式表文件,而且讓 @Component.styleUrls 指向它,就像這樣:

src/app/heroes/heroes.component.ts

@Component({

  selector: 'app-heroes',

  templateUrl: './heroes.component.html',

  styleUrls: ['./heroes.component.css']

})

打開 heroes.component.css 文件,而且把 HeroesComponent 的私有 CSS 樣式粘貼進去。 你能夠在本指南底部的查看最終代碼中找到它們。

@Component 元數據中指定的樣式和樣式表都是侷限於該組件的。 heroes.component.css 中的樣式只會做用於 HeroesComponent,既不會影響到組件外的 HTML,也不會影響到其它組件中的 HTML。

主從結構

當用戶在列表中點擊一個英雄時,該組件應該在頁面底部顯示所選英雄的詳情

在本節,你將監聽英雄條目的點擊事件,並更新英雄的詳情。

添加 click 事件綁定

再往 <li> 元素上插入一句點擊事件的綁定代碼:

heroes.component.html

<li *ngFor="let hero of heroes" (click)="onSelect(hero)">

這是 Angular 事件綁定 語法的例子。

click 外面的圓括號會讓 Angular 監聽這個 <li> 元素的 click 事件。 當用戶點擊 <li> 時,Angular 就會執行表達式 onSelect(hero)

onSelect() 是 HeroesComponent 上的一個方法,你很快就要寫它。 Angular 會把所點擊的 <li> 上的 hero 對象傳給它,這個 hero 也就是前面在 *ngFor 表達式中定義的那個。

添加 click 事件處理器

把該組件的 hero 屬性更名爲 selectedHero,但不要爲它賦值。 由於應用剛剛啓動時並無所選英雄

添加以下 onSelect() 方法,它會把模板中被點擊的英雄賦值給組件的 selectedHero 屬性。

src/app/heroes/heroes.component.ts

selectedHero: Hero;

onSelect(hero: Hero): void {

  this.selectedHero = hero;

}

修改詳情模板

該模板引用的仍然是老的 hero 屬性,但它已經不存在了。 把 hero 更名爲 selectedHero

heroes.component.html

<h2>{{selectedHero.name | uppercase}} Details</h2>

<div><span>id: </span>{{selectedHero.id}}</div>

<div>

  <label>name:

    <input [(ngModel)]="selectedHero.name" placeholder="name">

  </label>

</div>

刷新瀏覽器,應用掛了。

打開瀏覽器的開發者工具,它的控制檯中顯示出以下錯誤信息:

HeroesComponent.html:3 ERROR TypeError: Cannot read property 'name' of undefined

出現了什麼問題?

當應用啓動時,selectedHero 是 undefined設計如此

但模板中的綁定表達式引用了 selectedHero 的屬性(表達式爲 {{selectedHero.name}}),這必然會失敗,由於你還沒選過英雄呢。

如今,從列表中隨便點擊一個條目。 應用又正常了。 英雄們顯示在列表中,而且所點英雄的詳情也顯示在了頁面的下方。

修復 - 使用 *ngIf 來隱藏空白的細節

該組件應該只有當 selectedHero 存在時才顯示所選英雄的詳情。

把顯示英雄詳情的 HTML 包裹在一個 <div> 中。 而且爲這個 div 添加 Angular 的 *ngIf 指令,把它的值設置爲 selectedHero

不要忘了 ngIf 前面的星號(*),它是該語法中的關鍵部分。

src/app/heroes/heroes.component.html (*ngIf)

<div *ngIf="selectedHero">

 

  <h2>{{selectedHero.name | uppercase}} Details</h2>

  <div><span>id: </span>{{selectedHero.id}}</div>

  <div>

    <label>name:

      <input [(ngModel)]="selectedHero.name" placeholder="name">

    </label>

  </div>

 

</div>

瀏覽器刷新以後,英雄名字的列表又出現了。 詳情部分仍然是空。 點擊一個英雄,它的詳情就出現了。 這個應用看起來又再次工做正常顯示了。 英雄顯示在列表中,當你單擊英雄的名字的時候,有關你單擊英雄的詳細信息就顯示在頁面的底部了。

爲何這樣是正常的

當 selectedHero 爲 undefined 時,ngIf 從 DOM 中移除了英雄詳情。所以也就不用擔憂 selectedHero 的綁定了。

當用戶選擇一個英雄時,selectedHero 也就有了值,而且 ngIf 把英雄的詳情放回到 DOM 中。

給所選英雄添加樣式

全部的 <li> 元素看起來都是同樣的,所以很難從列表中識別出所選英雄

若是用戶點擊了「Magneta」,這個英雄應該用一個略有不一樣的背景色顯示出來,就像這樣:

所選英雄的顏色來自於你前面添加的樣式中的 CSS 類 .selected。 因此你只要在用戶點擊一個 <li> 時把 .selected 類應用到該元素上就能夠了。

Angular 的 CSS 類綁定機制讓根據條件添加或移除一個 CSS 類變得很容易。 只要把 [class.some-css-class]="some-condition" 添加到你要施加樣式的元素上就能夠了。

在 HeroesComponent 模板中的 <li> 元素上添加 [class.selected] 綁定,代碼以下:

heroes.component.html (toggle the 'selected' CSS class)

[class.selected]="hero === selectedHero"

若是當前行的英雄和 selectedHero 相同,Angular 就會添加 CSS 類 selected,不然就會移除它。

最終的 <li> 是這樣的:

heroes.component.html (list item hero)

<li *ngFor="let hero of heroes"

  [class.selected]="hero === selectedHero"

  (click)="onSelect(hero)">

  <span class="badge">{{hero.id}}</span> {{hero.name}}

</li>

查看最終代碼

你的應用如今變成了這樣:在線例子 / 下載範例

下面是本頁面中所說起的代碼文件,包括 HeroesComponent 的樣式。

對應的文件列表和代碼連接以下:

文件名

源代碼

src/app/heroes/heroes.component.ts https://github.com/cwiki-us-angular/cwiki-us-angular-tour-of-heroes-list/blob/master/src/app/heroes/heroes.component.ts
src/app/heroes/heroes.component.html https://github.com/cwiki-us-angular/cwiki-us-angular-tour-of-heroes-list/blob/master/src/app/heroes/heroes.component.html
src/app/heroes/heroes.component.css https://github.com/cwiki-us-angular/cwiki-us-angular-tour-of-heroes-list/blob/master/src/app/heroes/heroes.component.css

小結

  • 英雄指南應用在一個主從視圖中顯示了英雄列表。
  • 用戶能夠選擇一個英雄,並查看該英雄的詳情。
  • 你使用 *ngFor 顯示了一個列表。
  • 你使用 *ngIf 來根據條件包含或排除了一段 HTML。
  • 你能夠用 class 綁定來切換 CSS 的樣式類。

https://www.cwiki.us/display/AngularZH/Display+a+Heroes+List

相關文章
相關標籤/搜索