# Master/Detail Components
# 主从组件
At the moment, the `HeroesComponent` displays both the list of heroes and the selected hero's details.
此刻,`HeroesComponent` 同时显示了英雄列表和所选英雄的详情。
Keeping all features in one component as the application grows will not be maintainable.
You'll want to split up large components into smaller sub-components, each focused on a specific task or workflow.
把所有特性都放在同一个组件中,将会使应用“长大”后变得不可维护。
你要把大型组件拆分成小一点的子组件,每个子组件都要集中精力处理某个特定的任务或工作流。
In this page, you'll take the first step in that direction by moving the hero details into a separate, reusable `HeroDetailComponent`.
本页面中,你将迈出第一步 —— 把英雄详情移入一个独立的、可复用的 `HeroDetailComponent`。
The `HeroesComponent` will only present the list of heroes.
The `HeroDetailComponent` will present details of a selected hero.
`HeroesComponent` 将仅仅用来表示英雄列表。
`HeroDetailComponent` 将用来表示所选英雄的详情。
## Make the `HeroDetailComponent`
## 制作 `HeroDetailComponent`
Use the Angular CLI to generate a new component named `hero-detail`.
使用 Angular CLI 生成一个名叫 `hero-detail` 的新组件。
ng generate component hero-detail
The command scaffolds the `HeroDetailComponent` files and declares the component in `AppModule`.
该命令会生成 `HeroDetailComponent` 文件的脚手架,并把它声明在 `AppModule` 中。
### Write the template
### 编写模板
Cut the HTML for the hero detail from the bottom of the `HeroesComponent` template and paste it over the generated boilerplate in the `HeroDetailComponent` template.
从 `HeroesComponent` 模板的底部把表示英雄详情的 HTML 代码剪切粘贴到所生成的 `HeroDetailComponent` 模板中。
The pasted HTML refers to a `selectedHero`.
The new `HeroDetailComponent` can present _any_ hero, not just a selected hero.
So replace "selectedHero" with "hero" everywhere in the template.
所粘贴的 HTML 引用了 `selectedHero`。
新的 `HeroDetailComponent` 可以展示*任意*英雄,而不仅仅所选的。因此还要把模板中的所有 `selectedHero` 替换为 `hero`。
When you're done, the `HeroDetailComponent` template should look like this:
完工之后,`HeroDetailComponent` 的模板应该是这样的:
### Add the `@Input()` hero property
### 添加 `@Input() hero` 属性
The `HeroDetailComponent` template binds to the component's `hero` property
which is of type `Hero`.
`HeroDetailComponent` 模板中绑定了组件中的 `hero` 属性,它的类型是 `Hero`。
Open the `HeroDetailComponent` class file and import the `Hero` symbol.
打开 `HeroDetailComponent` 类文件,并导入 `Hero` 符号。
The `hero` property
[must be an _Input_ property](guide/template-syntax#inputs-outputs "Input and Output properties"),
annotated with the `@Input()` decorator,
because the _external_ `HeroesComponent` [will bind to it](#heroes-component-template) like this.
`hero` 属性[必须是一个带有 `@Input()` 装饰器的输入属性](guide/template-syntax#inputs-outputs "Input and Output properties"),因为*外部的* `HeroesComponent` 组件[将会绑定到它](#heroes-component-template)。就像这样:
Amend the `@angular/core` import statement to include the `Input` symbol.
修改 `@angular/core` 的导入语句,导入 `Input` 符号。
Add a `hero` property, preceded by the `@Input()` decorator.
添加一个带有 `@Input()` 装饰器的 `hero` 属性。
That's the only change you should make to the `HeroDetailComponent` class.
There are no more properties. There's no presentation logic.
This component simply receives a hero object through its `hero` property and displays it.
这就是你要对 `HeroDetailComponent` 类做的唯一一项修改。
没有其它属性,也没有展示逻辑。这个组件所做的只是通过 `hero` 属性接收一个英雄对象,并显示它。
## Show the `HeroDetailComponent`
## 显示 `HeroDetailComponent`
The `HeroesComponent` is still a master/detail view.
`HeroesComponent` 仍然是主从视图。
It used to display the hero details on its own, before you cut that portion of the template. Now it will delegate to the `HeroDetailComponent`.
在你从模板中剪切走代码之前,它自己负责显示英雄的详情。现在它要把这个职责委托给 `HeroDetailComponent` 了。
The two components will have a parent/child relationship.
The parent `HeroesComponent` will control the child `HeroDetailComponent`
by sending it a new hero to display whenever
the user selects a hero from the list.
这两个组件将会具有父子关系。
当用户从列表中选择了某个英雄时,父组件 `HeroesComponent` 将通过把要显示的新英雄发送给子组件 `HeroDetailComponent`,来控制子组件。
You won't change the `HeroesComponent` _class_ but you will change its _template_.
你不用修改 `HeroesComponent` *类*,但是要修改它的*模板*。
{@a heroes-component-template}
### Update the `HeroesComponent` template
### 修改 `HeroesComponent` 的模板
The `HeroDetailComponent` selector is `'app-hero-detail'`.
Add an `` element near the bottom of the `HeroesComponent` template, where the hero detail view used to be.
`HeroDetailComponent` 的选择器是 `'app-hero-detail'`。
把 `` 添加到 `HeroesComponent` 模板的底部,以便把英雄详情的视图显示到那里。
Bind the `HeroesComponent.selectedHero` to the element's `hero` property like this.
把 `HeroesComponent.selectedHero` 绑定到钙元素的 `hero` 属性,就像这样:
`[hero]="selectedHero"` is an Angular [property binding](guide/template-syntax#property-binding).
`[hero]="selectedHero"` 是 Angular 的[属性绑定](guide/template-syntax#property-binding)语法。
It's a _one way_ data binding from
the `selectedHero` property of the `HeroesComponent` to the `hero` property of the target element, which maps to the `hero` property of the `HeroDetailComponent`.
这是一种*单向*数据绑定。从 `HeroesComponent` 的 `selectedHero` 属性绑定到目标元素的 `hero` 属性,并映射到了 `HeroDetailComponent` 的 `hero` 属性。
Now when the user clicks a hero in the list, the `selectedHero` changes.
When the `selectedHero` changes, the _property binding_ updates `hero`
and the `HeroDetailComponent` displays the new hero.
现在,当用户在列表中点击某个英雄时,`selectedHero` 就改变了。
当 `selectedHero` 改变时,*属性绑定*会修改 `HeroDetailComponent` 的 `hero` 属性,`HeroDetailComponent` 就会显示这个新的英雄。
The revised `HeroesComponent` template should look like this:
修改后的 `HeroesComponent` 的模板是这样的:
The browser refreshes and the app starts working again as it did before.
浏览器刷新,应用又像以前一样开始工作了。
## What changed?
## 有哪些变化?
As [before](tutorial/toh-pt2), whenever a user clicks on a hero name,
the hero detail appears below the hero list.
Now the `HeroDetailComponent` is presenting those details instead of the `HeroesComponent`.
像[以前](tutorial/toh-pt2)一样,一旦用户点击了一个英雄的名字,该英雄的详情就显示在了英雄列表下方。
现在,`HeroDetailComponent` 负责显示那些详情,而不再是 `HeroesComponent`。
Refactoring the original `HeroesComponent` into two components yields benefits, both now and in the future:
把原来的 `HeroesComponent` 重构成两个组件带来了一些优点,无论是现在还是未来:
1. You simplified the `HeroesComponent` by reducing its responsibilities.
你通过缩减 `HeroesComponent` 的职责简化了该组件。
1. You can evolve the `HeroDetailComponent` into a rich hero editor
without touching the parent `HeroesComponent`.
你可以把 `HeroDetailComponent` 改进成一个功能丰富的英雄编辑器,而不用改动父组件 `HeroesComponent`。
1. You can evolve the `HeroesComponent` without touching the hero detail view.
你可以改进 `HeroesComponent`,而不用改动英雄详情视图。
1. You can re-use the `HeroDetailComponent` in the template of some future component.
将来你可以在其它组件的模板中重复使用 `HeroDetailComponent`。
## Final code review
## 查看最终代码
Here are the code files discussed on this page and your app should look like this .
你的应用应该变成了这样 。本页所提及的代码文件如下:
## Summary
## 小结
* You created a separate, reusable `HeroDetailComponent`.
你创建了一个独立的、可复用的 `HeroDetailComponent` 组件。
* You used a [property binding](guide/template-syntax#property-binding) to give the parent `HeroesComponent` control over the child `HeroDetailComponent`.
你用[属性绑定](guide/template-syntax#property-binding)语法来让父组件 `HeroesComponent` 可以控制子组件 `HeroDetailComponent`。
* You used the [`@Input` decorator](guide/template-syntax#inputs-outputs)
to make the `hero` property available for binding
by the external `HeroesComponent`.
你用 [`@Input` 装饰器](guide/template-syntax#inputs-outputs)来让 `hero` 属性可以在外部的 `HeroesComponent` 中绑定。