此刻,HeroesComponent
同时显示了英雄列表和所选英雄的详情。
把所有特性都放在同一个组件中,将会使应用“长大”后变得不可维护。你要把大型组件拆分成小一点的子组件,每个子组件都要集中精力处理某个特定的任务或工作流。
本页面中,你将迈出第一步 —— 把英雄详情移入一个独立的、可复用的 HeroDetailComponent
。
HeroesComponent
将仅仅用来表示英雄列表。HeroDetailComponent
将用来表示所选英雄的详情。
要查看本页所讲的范例程序,参阅现场演练 / 下载范例。
使用 Angular CLI 生成一个名叫 hero-detail
的新组件。
ng generate component hero-detail
这个命令会做这些事:
src/app/hero-detail
。在这个目录中会生成四个文件:
HeroDetailComponent
的 TypeScript 文件。HeroDetailComponent
类的测试文件。该命令还会把 HeroDetailComponent
添加到 src/app/app.module.ts
文件中 @NgModule
的 declarations
列表中。
从 HeroesComponent
模板的底部把表示英雄详情的 HTML 代码剪切粘贴到所生成的 HeroDetailComponent
模板中。
所粘贴的 HTML 引用了 selectedHero
。新的 HeroDetailComponent
可以展示任意英雄,而不仅仅所选的。因此还要把模板中的所有 selectedHero
替换为 hero
。
完工之后,HeroDetailComponent
的模板应该是这样的:
<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>
HeroDetailComponent
模板中绑定了组件中的 hero
属性,它的类型是 Hero
。
打开 HeroDetailComponent
类文件,并导入 Hero
符号。
import { Hero } from "../hero";
hero
属性必须是一个带有 @Input()
装饰器的输入属性,因为外部的 HeroesComponent
组件将会绑定到它。就像这样:
<app-hero-detail [hero]="selectedHero"></app-hero-detail>
修改 @angular/core
的导入语句,导入 Input
符号。
import { Component, OnInit, Input } from "@angular/core";
添加一个带有 @Input()
装饰器的 hero
属性。
@Input() hero?: Hero;
这就是你要对 HeroDetailComponent
类做的唯一一项修改。没有其它属性,也没有展示逻辑。这个组件所做的只是通过 hero
属性接收一个英雄对象,并显示它。
HeroesComponent
会自行显示英雄的详情,但后面我们要移除这部分。本节会指导你把这部分逻辑委派给 HeroDetailComponent
。
这两个组件将会具有父子关系。当用户从列表中选择了某个英雄时,父组件 HeroesComponent
将通过把要显示的新英雄发送给子组件 HeroDetailComponent
,来控制子组件。
你不用修改 HeroesComponent
类,但是要修改它的模板。
HeroDetailComponent
的选择器是 "app-hero-detail"
。把 <app-hero-detail>
添加到 HeroesComponent
模板的底部,以便把英雄详情的视图显示到那里。
把 HeroesComponent.selectedHero
绑定到该元素的 hero
属性,就像这样。
<app-hero-detail [hero]="selectedHero"></app-hero-detail>
[hero]="selectedHero"
是 Angular 的属性绑定语法。
这是一种单向数据绑定。从 HeroesComponent
的 selectedHero
属性绑定到目标元素的 hero
属性,并映射到了 HeroDetailComponent
的 hero
属性。
现在,当用户在列表中点击某个英雄时,selectedHero
就改变了。当 selectedHero
改变时,属性绑定会修改 HeroDetailComponent
的 hero
属性,HeroDetailComponent
就会显示这个新的英雄。
修改后的 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>
浏览器刷新,应用又像以前一样开始工作了。
像以前一样,一旦用户点击了一个英雄的名字,该英雄的详情就显示在了英雄列表下方。现在,HeroDetailComponent
负责显示那些详情,而不再是 HeroesComponent
。
把原来的 HeroesComponent
重构成两个组件带来了一些优点,无论是现在还是未来:
HeroesComponent
的职责缩小了该组件。HeroDetailComponent
改进成一个功能丰富的英雄编辑器,而不用改动父组件 HeroesComponent
。HeroesComponent
,而不用改动英雄详情视图。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(): void {
}
}
<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>
<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>
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 { }
HeroDetailComponent
组件。
HeroesComponent
可以控制子组件 HeroDetailComponent
。
@Input
装饰器来让 hero
属性可以在外部的 HeroesComponent
中绑定。Vue.js2.0混合基础混合是一种灵活的分布式复用 Vue 组件的方式。混合对象可以包含任意组件选项。以组件使用混合对象时,所有混合...
软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的...
HTML DOM 实例 使用JavaScript访问和操作的HTML DOM对象的例子。 Document 对象使用 document.write() 输出文本 使用 document.w...
CSS 主要用于控制网页的外观,CSS 代码可以随意变化网页的布局和网页的内容样式。当 CSS3 出现以后,更是可以让网页增添了不少动...
HTML embed 标签type 属性规定 embed 标签内使用的嵌入的内容的 MIME 类型,请参考下述示例:实例一个嵌入的带 MIME 类型的 flas...
HTML button 标签value 属性用于设置HTML表单按钮的初始值,如下面的参考示例,我们设置了两个带有不同初始值的实例两个按钮带有...
实例HTML5 menu标签用于定义菜单列表。两个菜单按钮系列选项实例("File" 和 "Edit"):menu type="toolbar"li menu label="File...
简介 stdlib .h 头文件定义了四个变量类型、一些宏和各种通用工具函数。 库变量 下面是头文件 stdlib.h 中定义的变量类型:序号...