Angular 英雄之旅-英雄編輯器

2022-07-18 16:12 更新

英雄編輯器

應(yīng)用程序現(xiàn)在有了基本的標(biāo)題。接下來(lái)你要?jiǎng)?chuàng)建一個(gè)新的組件來(lái)顯示英雄信息并且把這個(gè)組件放到應(yīng)用程序的外殼里去。

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

創(chuàng)建英雄列表組件

使用 Angular CLI 創(chuàng)建一個(gè)名為 ?heroes ?的新組件。

ng generate component heroes

CLI 創(chuàng)建了一個(gè)新的文件夾 ?src/app/heroes/?,并生成了 ?HeroesComponent ?的四個(gè)文件。

?HeroesComponent ?的類(lèi)文件如下:

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

@Component({
  selector: 'app-heroes',
  templateUrl: './heroes.component.html',
  styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {

  constructor() { }

  ngOnInit(): void {
  }

}

你要從 Angular 核心庫(kù)中導(dǎo)入 ?Component ?符號(hào),并為組件類(lèi)加上 ?@Component? 裝飾器。

?@Component? 是個(gè)裝飾器函數(shù),用于為該組件指定 Angular 所需的元數(shù)據(jù)。

CLI 自動(dòng)生成了三個(gè)元數(shù)據(jù)屬性:

屬性

詳情

selector

組件的 CSS 元素選擇器

templateUrl

組件模板文件的位置。

styleUrls

組件私有 CSS 樣式表文件的位置。

CSS 元素選擇器 ?app-heroes? 用來(lái)在父組件的模板中匹配 HTML 元素的名稱(chēng),以識(shí)別出該組件。

?ngOnInit()? 是一個(gè)生命周期鉤子,Angular 在創(chuàng)建完組件后很快就會(huì)調(diào)用 ?ngOnInit()?。這里是放置初始化邏輯的好地方。

始終要 ?export ?這個(gè)組件類(lèi),以便在其它地方(比如 ?AppModule?)導(dǎo)入它。

添加 hero 屬性

往 ?HeroesComponent ?中添加一個(gè) ?hero ?屬性,用來(lái)表示一個(gè)名叫 “Windstorm” 的英雄。

hero = 'Windstorm';

顯示英雄

打開(kāi)模板文件 ?heroes.component.html?。刪除 Angular CLI 自動(dòng)生成的默認(rèn)內(nèi)容,改為到 ?hero ?屬性的數(shù)據(jù)綁定。

<h2>{{hero}}</h2>

顯示 HeroesComponent 視圖

要顯示 ?HeroesComponent ?你必須把它加到殼組件 ?AppComponent ?的模板中。

別忘了,?app-heroes? 就是 ?HeroesComponent ?的 元素選擇器。 所以,只要把 ?<app-heroes>? 元素添加到 ?AppComponent ?的模板文件中就可以了,就放在標(biāo)題下方。

<h1>{{title}}</h1>
<app-heroes></app-heroes>

如果 CLI 的 ?ng serve? 命令仍在運(yùn)行,瀏覽器就會(huì)自動(dòng)刷新,并且同時(shí)顯示出應(yīng)用的標(biāo)題和英雄的名字。

創(chuàng)建 Hero 類(lèi)

真實(shí)的英雄當(dāng)然不止一個(gè)名字。

在 ?src/app? 文件夾中為 ?Hero ?類(lèi)創(chuàng)建一個(gè)文件,并添加 ?id ?和 ?name ?屬性。

export interface Hero {
  id: number;
  name: string;
}

回到 ?HeroesComponent ?類(lèi),并且導(dǎo)入這個(gè) ?Hero ?類(lèi)。

把組件的 ?hero ?屬性的類(lèi)型重構(gòu)為 ?Hero?。然后以 ?1? 為 ?id?、以 “Windstorm” 為名字初始化它。

修改后的 ?HeroesComponent ?類(lèi)應(yīng)該是這樣的:

import { Component, OnInit } from '@angular/core';
import { Hero } from '../hero';

@Component({
  selector: 'app-heroes',
  templateUrl: './heroes.component.html',
  styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {
  hero: Hero = {
    id: 1,
    name: 'Windstorm'
  };

  constructor() { }

  ngOnInit(): void {
  }

}

頁(yè)面顯示變得不正常了,因?yàn)槟銊倓偘?nbsp;?hero ?從字符串改成了對(duì)象。

顯示 hero 對(duì)象

修改模板中的綁定,以顯示英雄的名字,并在詳情中顯示 ?id ?和 ?name?,就像這樣:

<h2>{{hero.name}} Details</h2>
<div><span>id: </span>{{hero.id}}</div>
<div><span>name: </span>{{hero.name}}</div>

瀏覽器自動(dòng)刷新,并顯示這位英雄的信息。

使用 UppercasePipe 進(jìn)行格式化

把 ?hero.name? 的綁定修改成這樣。

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

瀏覽器刷新了?,F(xiàn)在,英雄的名字顯示成了大寫(xiě)字母。

綁定表達(dá)式中的 ?uppercase ?位于管道操作符(?|?)的右邊,用來(lái)調(diào)用內(nèi)置管道 ?UppercasePipe?。

管道 是格式化字符串、金額、日期和其它顯示數(shù)據(jù)的好辦法。Angular 發(fā)布了一些內(nèi)置管道,而且你還可以創(chuàng)建自己的管道。

編輯英雄名字

用戶(hù)應(yīng)該能在一個(gè) ?<input>? 輸入框中編輯英雄的名字。

當(dāng)用戶(hù)輸入時(shí),這個(gè)輸入框應(yīng)該能同時(shí)顯示修改英雄的 ?name ?屬性。也就是說(shuō),數(shù)據(jù)流從組件類(lèi)流出到屏幕,并且從屏幕流回到組件類(lèi)。

要想讓這種數(shù)據(jù)流動(dòng)自動(dòng)化,就要在表單元素 ?<input>? 和組件的 ?hero.name? 屬性之間建立雙向數(shù)據(jù)綁定。

雙向綁定

把模板中的英雄詳情區(qū)重構(gòu)成這樣:

<div>
  <label for="name">Hero name: </label>
  <input id="name" [(ngModel)]="hero.name" placeholder="name">
</div>

?[(ngModel)]? 是 Angular 的雙向數(shù)據(jù)綁定語(yǔ)法。

這里把 ?hero.name? 屬性綁定到了 HTML 的 textbox 元素上,以便數(shù)據(jù)流可以雙向流動(dòng):從 ?hero.name? 屬性流動(dòng)到 textbox,并且從 textbox 流回到 ?hero.name?。

缺少 FormsModule

注意,當(dāng)你加上 ?[(ngModel)]? 之后這個(gè)應(yīng)用無(wú)法工作了。

打開(kāi)瀏覽器的開(kāi)發(fā)工具,就會(huì)在控制臺(tái)中看到如下信息:

Template parse errors:
Can't bind to 'ngModel' since it isn't a known property of 'input'.

雖然 ?ngModel ?是一個(gè)有效的 Angular 指令,不過(guò)它在默認(rèn)情況下是不可用的。

它屬于一個(gè)可選模塊 ?FormsModule?,你必須自行添加此模塊才能使用該指令。

AppModule

Angular 需要知道如何把應(yīng)用程序的各個(gè)部分組合到一起,以及該應(yīng)用需要哪些其它文件和庫(kù)。這些信息被稱(chēng)為元數(shù)據(jù)(metadata)。

有些元數(shù)據(jù)位于 ?@Component? 裝飾器中,你會(huì)把它加到組件類(lèi)上。另一些關(guān)鍵性的元數(shù)據(jù)位于 ?@NgModule? 裝飾器中。

最重要的 ?@NgModule? 裝飾器位于頂層類(lèi) AppModule 上。

Angular CLI 在創(chuàng)建項(xiàng)目的時(shí)候就在 ?src/app/app.module.ts? 中生成了一個(gè) ?AppModule ?類(lèi)。這里也就是你要添加 ?FormsModule ?的地方。

導(dǎo)入 FormsModule

打開(kāi) ?AppModule ?(?app.module.ts?) 并從 ?@angular/forms? 庫(kù)中導(dǎo)入 ?FormsModule ?符號(hào)。

import { FormsModule } from '@angular/forms'; // <-- NgModel lives here

然后把 ?FormsModule ?添加到 ?@NgModule? 元數(shù)據(jù)的 ?imports ?數(shù)組中,這里是該應(yīng)用所需外部模塊的列表。

imports: [
  BrowserModule,
  FormsModule
],

刷新瀏覽器,應(yīng)用又能正常工作了。你可以編輯英雄的名字,并且會(huì)看到這個(gè)改動(dòng)立刻體現(xiàn)在這個(gè)輸入框上方的 ?<h2>? 中。

聲明 HeroesComponent

每個(gè)組件都必須聲明在(且只能聲明在)一個(gè) ?NgModule ?中。

沒(méi)有聲明過(guò) ?HeroesComponent?,可為什么本應(yīng)用卻正常呢?

這是因?yàn)?nbsp;Angular CLI 在生成 ?HeroesComponent ?組件的時(shí)候就自動(dòng)把它加到了 ?AppModule ?中。

打開(kāi) ?src/app/app.module.ts? 你就會(huì)發(fā)現(xiàn) ?HeroesComponent ?已經(jīng)在頂部導(dǎo)入過(guò)了。

import { HeroesComponent } from './heroes/heroes.component';

?HeroesComponent ?也已經(jīng)聲明在了 ?@NgModule.declarations? 數(shù)組中。

declarations: [
  AppComponent,
  HeroesComponent
],
注意:
?AppModule ?聲明了應(yīng)用中的所有組件,?AppComponent ?和 ?HeroesComponent?。

查看最終代碼

下面是本頁(yè)所提到的源代碼。

  • src/app/heroes/heroes.component.ts
  • import { Component, OnInit } from '@angular/core';
    import { Hero } from '../hero';
    
    @Component({
      selector: 'app-heroes',
      templateUrl: './heroes.component.html',
      styleUrls: ['./heroes.component.css']
    })
    export class HeroesComponent implements OnInit {
      hero: Hero = {
        id: 1,
        name: 'Windstorm'
      };
    
      constructor() { }
    
      ngOnInit(): void {
      }
    
    }
  • src/app/heroes/heroes.component.html
  • <h2>{{hero.name | uppercase}} Details</h2>
    <div><span>id: </span>{{hero.id}}</div>
    <div>
      <label for="name">Hero name: </label>
      <input id="name" [(ngModel)]="hero.name" placeholder="name">
    </div>
  • src/app/app.module.ts
  • import { BrowserModule } from '@angular/platform-browser';
    import { NgModule } from '@angular/core';
    import { FormsModule } from '@angular/forms'; // <-- NgModel lives here
    
    import { AppComponent } from './app.component';
    import { HeroesComponent } from './heroes/heroes.component';
    
    @NgModule({
      declarations: [
        AppComponent,
        HeroesComponent
      ],
      imports: [
        BrowserModule,
        FormsModule
      ],
      providers: [],
      bootstrap: [AppComponent]
    })
    export class AppModule { }
  • src/app/app.component.ts
  • import { Component } from '@angular/core';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent {
      title = 'Tour of Heroes';
    }
  • src/app/app.component.html
  • <h1>{{title}}</h1>
    <app-heroes></app-heroes>
  • src/app/hero.ts
  • export interface Hero {
      id: number;
      name: string;
    }

小結(jié)

  • 你使用 CLI 創(chuàng)建了第二個(gè)組件 ?HeroesComponent ?
  • 你把 ?HeroesComponent ?添加到了殼組件 ?AppComponent ?中,以便顯示它
  • 你使用 ?UppercasePipe ?來(lái)格式化英雄的名字
  • 你用 ?ngModel ?指令實(shí)現(xiàn)了雙向數(shù)據(jù)綁定
  • 你知道了 ?AppModule ?
  • 你把 ?FormsModule ?導(dǎo)入了 ?AppModule?,以便 Angular 能識(shí)別并應(yīng)用 ?ngModel ?指令
  • 你知道了把組件聲明到 ?AppModule ?是很重要的,并認(rèn)識(shí)到 CLI 會(huì)自動(dòng)幫你聲明它


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

掃描二維碼

下載編程獅App

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

編程獅公眾號(hào)