Angular 英雄之旅-英雄編輯器

2022-07-18 16:12 更新

英雄編輯器

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

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

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

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

ng generate component heroes

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

?HeroesComponent ?的類文件如下:

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 核心庫中導(dǎo)入 ?Component ?符號,并為組件類加上 ?@Component? 裝飾器。

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

CLI 自動生成了三個元數(shù)據(jù)屬性:

屬性

詳情

selector

組件的 CSS 元素選擇器

templateUrl

組件模板文件的位置。

styleUrls

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

CSS 元素選擇器 ?app-heroes? 用來在父組件的模板中匹配 HTML 元素的名稱,以識別出該組件。

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

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

添加 hero 屬性

往 ?HeroesComponent ?中添加一個 ?hero ?屬性,用來表示一個名叫 “Windstorm” 的英雄。

hero = 'Windstorm';

顯示英雄

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

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

顯示 HeroesComponent 視圖

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

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

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

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

創(chuàng)建 Hero 類

真實的英雄當然不止一個名字。

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

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

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

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

修改后的 ?HeroesComponent ?類應(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 {
  }

}

頁面顯示變得不正常了,因為你剛剛把 ?hero ?從字符串改成了對象。

顯示 hero 對象

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

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

瀏覽器自動刷新,并顯示這位英雄的信息。

使用 UppercasePipe 進行格式化

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

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

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

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

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

編輯英雄名字

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

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

要想讓這種數(shù)據(jù)流動自動化,就要在表單元素 ?<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ù)綁定語法。

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

缺少 FormsModule

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

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

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

雖然 ?ngModel ?是一個有效的 Angular 指令,不過它在默認情況下是不可用的。

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

AppModule

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

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

最重要的 ?@NgModule? 裝飾器位于頂層類 AppModule 上。

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

導(dǎo)入 FormsModule

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

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

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

imports: [
  BrowserModule,
  FormsModule
],

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

聲明 HeroesComponent

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

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

這是因為 Angular CLI 在生成 ?HeroesComponent ?組件的時候就自動把它加到了 ?AppModule ?中。

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

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

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

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

查看最終代碼

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

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


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

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號