Angular 英雄之旅-創(chuàng)建特性組件

2022-07-19 10:07 更新

主從組件

此刻,?HeroesComponent ?同時(shí)顯示了英雄列表和所選英雄的詳情。

把所有特性都放在同一個(gè)組件中,將會(huì)使應(yīng)用“長(zhǎng)大”后變得不可維護(hù)。你要把大型組件拆分成小一點(diǎn)的子組件,每個(gè)子組件都要集中精力處理某個(gè)特定的任務(wù)或工作流。

本頁面中,你將邁出第一步 —— 把英雄詳情移入一個(gè)獨(dú)立的、可復(fù)用的 ?HeroDetailComponent?。

?HeroesComponent ?將僅僅用來表示英雄列表。?HeroDetailComponent ?將用來表示所選英雄的詳情。

要查看本頁所講的范例程序,參閱現(xiàn)場(chǎng)演練 / 下載范例

制作 HeroDetailComponent

使用 Angular CLI 生成一個(gè)名叫 ?hero-detail? 的新組件。

ng generate component hero-detail

這個(gè)命令會(huì)做這些事:

  • 創(chuàng)建目錄 ?src/app/hero-detail?。

在這個(gè)目錄中會(huì)生成四個(gè)文件:

  • 作為組件樣式的 CSS 文件。
  • 作為組件模板的 HTML 文件。
  • 存放組件類 ?HeroDetailComponent ?的 TypeScript 文件。
  • ?HeroDetailComponent ?類的測(cè)試文件。

該命令還會(huì)把 ?HeroDetailComponent ?添加到 ?src/app/app.module.ts? 文件中 ?@NgModule? 的 ?declarations ?列表中。

編寫模板

從 ?HeroesComponent ?模板的底部把表示英雄詳情的 HTML 代碼剪切粘貼到所生成的 ?HeroDetailComponent ?模板中。

所粘貼的 HTML 引用了 ?selectedHero?。新的 ?HeroDetailComponent ?可以展示任意英雄,而不僅僅所選的。因此還要把模板中的所有 ?selectedHero ?替換為 ?hero?。

完工之后,?HeroDetailComponent ?的模板應(yīng)該是這樣的:

<div *ngIf="hero">

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

</div>

添加 @Input() hero 屬性

?HeroDetailComponent ?模板中綁定了組件中的 ?hero ?屬性,它的類型是 ?Hero?。

打開 ?HeroDetailComponent ?類文件,并導(dǎo)入 ?Hero ?符號(hào)。

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

?hero ?屬性必須是一個(gè)帶有 ?@Input()? 裝飾器的輸入屬性,因?yàn)橥獠康?nbsp;?HeroesComponent ?組件將會(huì)綁定到它。就像這樣:

<app-hero-detail [hero]="selectedHero"></app-hero-detail>

修改 ?@angular/core? 的導(dǎo)入語句,導(dǎo)入 ?Input ?符號(hào)。

import { Component, OnInit, Input } from '@angular/core';

添加一個(gè)帶有 ?@Input()? 裝飾器的 ?hero ?屬性。

@Input() hero?: Hero;

這就是你要對(duì) ?HeroDetailComponent ?類做的唯一一項(xiàng)修改。沒有其它屬性,也沒有展示邏輯。這個(gè)組件所做的只是通過 ?hero ?屬性接收一個(gè)英雄對(duì)象,并顯示它。

顯示 HeroDetailComponent

?HeroesComponent ?會(huì)自行顯示英雄的詳情,但后面我們要移除這部分。本節(jié)會(huì)指導(dǎo)你把這部分邏輯委派給 ?HeroDetailComponent?。

這兩個(gè)組件將會(huì)具有父子關(guān)系。當(dāng)用戶從列表中選擇了某個(gè)英雄時(shí),父組件 ?HeroesComponent ?將通過把要顯示的新英雄發(fā)送給子組件 ?HeroDetailComponent?,來控制子組件。

你不用修改 ?HeroesComponent,但是要修改它的模板。

修改 HeroesComponent 的模板

?HeroDetailComponent ?的選擇器是 ?'app-hero-detail'?。把 ?<app-hero-detail>? 添加到 ?HeroesComponent ?模板的底部,以便把英雄詳情的視圖顯示到那里。

把 ?HeroesComponent.selectedHero? 綁定到該元素的 ?hero ?屬性,就像這樣。

<app-hero-detail [hero]="selectedHero"></app-hero-detail>

?[hero]="selectedHero"? 是 Angular 的屬性綁定語法。

這是一種單向數(shù)據(jù)綁定。從 ?HeroesComponent ?的 ?selectedHero ?屬性綁定到目標(biāo)元素的 ?hero ?屬性,并映射到了 ?HeroDetailComponent ?的 ?hero ?屬性。

現(xiàn)在,當(dāng)用戶在列表中點(diǎn)擊某個(gè)英雄時(shí),?selectedHero ?就改變了。當(dāng) ?selectedHero ?改變時(shí),屬性綁定會(huì)修改 ?HeroDetailComponent ?的 ?hero ?屬性,?HeroDetailComponent ?就會(huì)顯示這個(gè)新的英雄。

修改后的 ?HeroesComponent ?的模板是這樣的:

<h2>My Heroes</h2>

<ul class="heroes">
  <li *ngFor="let hero of heroes">
    <button [class.selected]="hero === selectedHero" type="button" (click)="onSelect(hero)">
      <span class="badge">{{hero.id}}</span>
      <span class="name">{{hero.name}}</span>
    </button>
  </li>
</ul>

<app-hero-detail [hero]="selectedHero"></app-hero-detail>

瀏覽器刷新,應(yīng)用又像以前一樣開始工作了。

有哪些變化?

像以前一樣,一旦用戶點(diǎn)擊了一個(gè)英雄的名字,該英雄的詳情就顯示在了英雄列表下方?,F(xiàn)在,?HeroDetailComponent ?負(fù)責(zé)顯示那些詳情,而不再是 ?HeroesComponent?。

把原來的 ?HeroesComponent ?重構(gòu)成兩個(gè)組件帶來了一些優(yōu)點(diǎn),無論是現(xiàn)在還是未來:

  1. 你通過縮減 ?HeroesComponent ?的職責(zé)縮小了該組件。
  2. 你可以把 ?HeroDetailComponent ?改進(jìn)成一個(gè)功能豐富的英雄編輯器,而不用改動(dòng)父組件 ?HeroesComponent?。
  3. 你可以改進(jìn) ?HeroesComponent?,而不用改動(dòng)英雄詳情視圖。
  4. 將來你可以在其它組件的模板中重復(fù)使用 ?HeroDetailComponent?。

查看最終代碼

下面是本頁所提到的源代碼。

  • src/app/hero-detail/hero-detail.component.ts
  • import { Component, OnInit, Input } from '@angular/core';
    import { Hero } from '../hero';
    
    @Component({
      selector: 'app-hero-detail',
      templateUrl: './hero-detail.component.html',
      styleUrls: ['./hero-detail.component.css']
    })
    export class HeroDetailComponent implements OnInit {
      @Input() hero?: Hero;
    
      constructor() { }
    
      ngOnInit(): void {
      }
    
    }
  • src/app/hero-detail/hero-detail.component.html
  • <div *ngIf="hero">
    
      <h2>{{hero.name | uppercase}} Details</h2>
      <div><span>id: </span>{{hero.id}}</div>
      <div>
        <label for="hero-name">Hero name: </label>
        <input id="hero-name" [(ngModel)]="hero.name" placeholder="name">
      </div>
    
    </div>
  • src/app/heroes/heroes.component.html
  • <h2>My Heroes</h2>
    
    <ul class="heroes">
      <li *ngFor="let hero of heroes">
        <button [class.selected]="hero === selectedHero" type="button" (click)="onSelect(hero)">
          <span class="badge">{{hero.id}}</span>
          <span class="name">{{hero.name}}</span>
        </button>
      </li>
    </ul>
    
    <app-hero-detail [hero]="selectedHero"></app-hero-detail>
  • src/app/app.module.ts
  • import { BrowserModule } from '@angular/platform-browser';
    import { NgModule } from '@angular/core';
    import { FormsModule } from '@angular/forms';
    
    import { AppComponent } from './app.component';
    import { HeroesComponent } from './heroes/heroes.component';
    import { HeroDetailComponent } from './hero-detail/hero-detail.component';
    
    @NgModule({
      declarations: [
        AppComponent,
        HeroesComponent,
        HeroDetailComponent
      ],
      imports: [
        BrowserModule,
        FormsModule
      ],
      providers: [],
      bootstrap: [AppComponent]
    })
    export class AppModule { }

小結(jié)

  • 你創(chuàng)建了一個(gè)獨(dú)立的、可復(fù)用的 ?HeroDetailComponent ?組件。
  • 你用屬性綁定語法來讓父組件 ?HeroesComponent ?可以控制子組件 ?HeroDetailComponent?。
  • 你用 ?@Input? 裝飾器來讓 ?hero ?屬性可以在外部的 ?HeroesComponent ?中綁定。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)