此刻,HeroesComponent 同時(shí)顯示了英雄列表和所選英雄的詳情。
把所有特性都放在同一個(gè)組件中,將會(huì)使應(yīng)用“長(zhǎng)大”后變得不可維護(hù)。 你要把大型組件拆分成小一點(diǎn)的子組件,每個(gè)子組件都要集中精力處理某個(gè)特定的任務(wù)或工作流。
本頁(yè)面中,你將邁出第一步 —— 把英雄詳情移入一個(gè)獨(dú)立的、可復(fù)用的 HeroDetailComponent。
HeroesComponent 將僅僅用來(lái)表示英雄列表。 HeroDetailComponent 將用來(lái)表示所選英雄的詳情。
使用 Angular CLI 生成一個(gè)名叫 hero-detail 的新組件。
ng generate component hero-detail
這個(gè)命令會(huì)做這些事:
在這個(gè)目錄中會(huì)生成四個(gè)文件:
該命令還會(huì)把 HeroDetailComponent 添加到 "src/app/app.module.ts" 文件中 @NgModule
的 declarations
列表中。
從 HeroesComponent 模板的底部把表示英雄詳情的 HTML 代碼剪切粘貼到所生成的 HeroDetailComponent 模板中。
所粘貼的 HTML 引用了 selectedHero
。 新的 HeroDetailComponent 可以展示任意英雄,而不僅僅所選的。因此還要把模板中的所有 selectedHero
替換為 hero
。
完工之后,HeroDetailComponent
的模板應(yīng)該是這樣的:
Path:"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>name:
<input [(ngModel)]="hero.name" placeholder="name"/>
</label>
</div>
</div>
HeroDetailComponent 模板中綁定了組件中的 hero
屬性,它的類(lèi)型是 Hero
。
打開(kāi) HeroDetailComponent 類(lèi)文件,并導(dǎo)入 Hero
符號(hào)。
Path:"src/app/hero-detail/hero-detail.component.ts (import Hero)"
import { Hero } from '../hero';
hero
屬性必須是一個(gè)帶有 @Input()
裝飾器的輸入屬性,因?yàn)橥獠康?HeroesComponent 組件將會(huì)綁定到它。就像這樣:
<app-hero-detail [hero]="selectedHero"></app-hero-detail>
修改 @angular/core
的導(dǎo)入語(yǔ)句,導(dǎo)入 Input
符號(hào)。
Path:"src/app/hero-detail/hero-detail.component.ts (import Input)"
import { Component, OnInit, Input } from '@angular/core';
添加一個(gè)帶有 @Input()
裝飾器的 hero
屬性。
Path:"src/app/hero-detail/hero-detail.component.ts"
@Input() hero: Hero;
這就是你要對(duì) HeroDetailComponent 類(lèi)做的唯一一項(xiàng)修改。 沒(méi)有其它屬性,也沒(méi)有展示邏輯。這個(gè)組件所做的只是通過(guò) hero
屬性接收一個(gè)英雄對(duì)象,并顯示它。
HeroesComponent 仍然是主從視圖。
在你從模板中剪切走代碼之前,它自己負(fù)責(zé)顯示英雄的詳情?,F(xiàn)在它要把這個(gè)職責(zé)委托給 HeroDetailComponent 了。
這兩個(gè)組件將會(huì)具有父子關(guān)系。 當(dāng)用戶(hù)從列表中選擇了某個(gè)英雄時(shí),父組件 HeroesComponent 將通過(guò)把要顯示的新英雄發(fā)送給子組件 HeroDetailComponent,來(lái)控制子組件。
你不用修改 HeroesComponent 類(lèi),但是要修改它的模板。
HeroDetailComponent 的選擇器是 'app-hero-detail'
。 把 <app-hero-detail>
添加到 HeroesComponent 模板的底部,以便把英雄詳情的視圖顯示到那里。
把 HeroesComponent.selectedHero 綁定到該元素的 hero
屬性,就像這樣:
Path:"heroes.component.html (HeroDetail binding)"
<app-hero-detail [hero]="selectedHero"></app-hero-detail>
[hero]="selectedHero"
是 Angular 的屬性綁定語(yǔ)法。
這是一種單向數(shù)據(jù)綁定。從 HeroesComponent 的 selectedHero 屬性綁定到目標(biāo)元素的 hero
屬性,并映射到了 HeroDetailComponent 的 hero
屬性。
現(xiàn)在,當(dāng)用戶(hù)在列表中點(diǎn)擊某個(gè)英雄時(shí),selectedHero
就改變了。 當(dāng) selectedHero
改變時(shí),屬性綁定會(huì)修改 HeroDetailComponent 的 hero
屬性,HeroDetailComponent 就會(huì)顯示這個(gè)新的英雄。
修改后的 HeroesComponent 的模板是這樣的:
Path:"heroes.component.html"
<h2>My Heroes</h2>
<ul class="heroes">
<li *ngFor="let hero of heroes"
[class.selected]="hero === selectedHero"
(click)="onSelect(hero)">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</li>
</ul>
<app-hero-detail [hero]="selectedHero"></app-hero-detail>
瀏覽器刷新,應(yīng)用又像以前一樣開(kāi)始工作了。
產(chǎn)生的變化:
像以前一樣,一旦用戶(hù)點(diǎn)擊了一個(gè)英雄的名字,該英雄的詳情就顯示在了英雄列表下方。 現(xiàn)在,HeroDetailComponent 負(fù)責(zé)顯示那些詳情,而不再是 HeroesComponent。
把原來(lái)的 HeroesComponent 重構(gòu)成兩個(gè)組件帶來(lái)了一些優(yōu)點(diǎn),無(wú)論是現(xiàn)在還是未來(lái):
你通過(guò)縮減 HeroesComponent 的職責(zé)簡(jiǎn)化了該組件。
你可以把 HeroDetailComponent 改進(jìn)成一個(gè)功能豐富的英雄編輯器,而不用改動(dòng)父組件 HeroesComponent。
你可以改進(jìn) HeroesComponent,而不用改動(dòng)英雄詳情視圖。
將來(lái)你可以在其它組件的模板中重復(fù)使用 HeroDetailComponent。
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() {
}
}
<div *ngIf="hero">
<h2>{{hero.name | uppercase}} Details</h2>
<div><span>id: </span>{{hero.id}}</div>
<div>
<label>name:
<input [(ngModel)]="hero.name" placeholder="name"/>
</label>
</div>
</div>
<h2>My Heroes</h2>
<ul class="heroes">
<li *ngFor="let hero of heroes"
[class.selected]="hero === selectedHero"
(click)="onSelect(hero)">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</li>
</ul>
<app-hero-detail [hero]="selectedHero"></app-hero-detail>
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 { }
更多建議: