1. 程式人生 > 實用技巧 >顯示英雄列表 ( 教程 | Tutorial) – Angular 中文開發手冊

顯示英雄列表 ( 教程 | Tutorial) – Angular 中文開發手冊

[

顯示英雄列表 ( 教程 | Tutorial) - Angular 中文開發手冊
本頁中,你將擴充套件《英雄指南》應用,讓它顯示一個英雄列表, 並允許使用者選擇一個英雄,檢視該英雄的詳細資訊。

建立模擬(mock)的英雄資料

你需要一些英雄資料以供顯示。最終,你會從遠端的資料伺服器獲取它。 不過目前,你要先建立一些模擬的英雄資料,並假裝它們是從伺服器上取到的。在 src/app/ 資料夾中建立一個名叫 mock-heroes.ts 的檔案。 定義一個包含十個英雄的常量陣列 HEROES,並匯出它。 該檔案是這樣的。src/app/mock-heroes.ts

content_copyimport { Hero } from './hero';

export const HEROES: Hero[] = [
  { id: 11, name: 'Mr. Nice' },
  { id: 12, name: 'Narco' },
  { id: 13, name: 'Bombasto' },
  { 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)

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

往類中新增一個 heroes 屬性,這樣可以暴露出這些英雄,以供繫結。

content_copyheroes = HEROES;

使用 *ngFor 列出這些英雄

開啟 HeroesComponent 的模板檔案,並做如下修改:在頂部新增 <h2>,然後新增表示無序列表的 HTML 元素(<ul>)在 <ul> 中插入一個 <li> 元素,以顯示單個 hero 的屬性。點綴上一些 CSS 類(稍後你還會新增更多 CSS 樣式)。做完之後應該是這樣的: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> 修改成這樣:

content_copy<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)

content_copy@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 (template excerpt)

content_copy<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 (onSelect)

content_copyselectedHero: Hero;

onSelect(hero: Hero): void {
  this.selectedHero = hero;
}

修改詳情模板

該模板引用的仍然是老的 hero 屬性,但它已經不存在了。 把 hero 改名為 selectedHero。heroes.component.html (selected hero details)

content_copy<h2>{{selectedHero.name | uppercase}} Details</h2>
<div><span>id: </span>{{selectedHero.id}}</div>
<div>
  <label>name:
    <input [(ngModel)]="selectedHero.name" placeholder="name">
  </label>
</div>

使用 *ngIf 隱藏空白的詳情

重新整理瀏覽器,應用掛了。開啟瀏覽器的開發者工具,它的控制檯中顯示出如下錯誤資訊:

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

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

怎麼回事?

當應用啟動時,selectedHero 是 undefined,設計如此。但模板中的繫結表示式引用了 selectedHero 的屬性(表示式為 {{selectedHero.name}}),這必然會失敗,因為你還沒選過英雄呢。

修復

該元件應該只有當 selectedHero 存在時才顯示所選英雄的詳情。把顯示英雄詳情的 HTML 包裹在一個 <div> 中。 並且為這個 div 新增 Angular 的 *ngIf 指令,把它的值設定為 selectedHero。不要忘了 ngIf 前面的星號(*),它是該語法中的關鍵部分。src/app/heroes/heroes.component.html (*ngIf)

content_copy<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)

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

如果當前行的英雄和 selectedHero 相同,Angular 就會新增 CSS 類 selected,否則就會移除它。最終的 <li> 是這樣的:heroes.component.html (list item hero)

content_copy<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.tssrc/app/heroes/heroes.component.htmlsrc/app/heroes/heroes.component.css

content_copyimport { Component, OnInit } from '@angular/core';import { Hero } from '../hero';import { HEROES } from '../mock-heroes'; @Component({  selector: 'app-heroes',  templateUrl: './heroes.component.html',  styleUrls: ['./heroes.component.css']})export class HeroesComponent implements OnInit {   heroes = HEROES;   selectedHero: Hero;    constructor() { }   ngOnInit() {  }   onSelect(hero: Hero): void {    this.selectedHero = hero;  }}

小結

英雄指南應用在一個主從檢視中顯示了英雄列表。使用者可以選擇一個英雄,並檢視該英雄的詳情。你使用 *ngFor 顯示了一個列表。你使用 *ngIf 來根據條件包含或排除了一段 HTML。你可以用 class 繫結來切換 CSS 的樣式類。

]
  •   本文標題:顯示英雄列表 ( 教程 | Tutorial) – Angular 中文開發手冊 - Break易站轉載請保留頁面地址:https://www.breakyizhan.com/javascript/26360.html