Hero guide 創(chuàng)建特性組件

2020-06-29 16:48 更新

主從組件

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

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

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

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

制作 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 類的測試文件。

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

編寫模板

從 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>

添加 @Input() hero 屬性

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

打開 HeroDetailComponent 類文件,并導(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)入語句,導(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;

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

顯示 HeroDetailComponent

HeroesComponent 仍然是主從視圖。

在你從模板中剪切走代碼之前,它自己負(fù)責(zé)顯示英雄的詳情?,F(xiàn)在它要把這個(gè)職責(zé)委托給 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 屬性,就像這樣:

Path:"heroes.component.html (HeroDetail binding)"

<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 的模板是這樣的:

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)用又像以前一樣開始工作了。

產(chǎn)生的變化:

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

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

你通過縮減 HeroesComponent 的職責(zé)簡化了該組件。

你可以把 HeroDetailComponent 改進(jìn)成一個(gè)功能豐富的英雄編輯器,而不用改動(dòng)父組件 HeroesComponent。

你可以改進(jìn) HeroesComponent,而不用改動(dòng)英雄詳情視圖。

將來你可以在其它組件的模板中重復(fù)使用 HeroDetailComponent。

查看最終代碼

  1. Path:"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() {
      }


    }

  1. 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>

  1. Path:"src/app/heroes/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>

  1. Path:"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)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

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

編程獅公眾號(hào)