修订了教程-多个组件的一部分

部分“标记(tag)”批量替换为“标签”
This commit is contained in:
Zhicheng Wang 2016-05-11 21:04:09 +08:00
parent 15c927b29f
commit f413edce53
4 changed files with 41 additions and 40 deletions

View File

@ -567,7 +567,7 @@ include _util-fns
before it is assigned to an element property
or displayed between element tags as in this example.
[属性数据绑定](#data-binding) 的形式之一:位于双大括号中的[模板表达式](#template-expression)会被渲染成文本。在被赋值给元素属性或者显示在元素标中之前,这些文本可能先与周边的文本合并,参见下面的例子。
[属性数据绑定](#data-binding) 的形式之一:位于双大括号中的[模板表达式](#template-expression)会被渲染成文本。在被赋值给元素属性或者显示在元素标中之前,这些文本可能先与周边的文本合并,参见下面的例子。
code-example(language="html" escape="html").
<label>My current hero is {{hero.name}}</label>
@ -834,7 +834,7 @@ include _util-fns
It likely has anchor tags or buttons with `RouterLink` directives that users can click to navigate.
它很大可能还会有一些有`RouterLink`指令的锚标记或按钮,用户可以用来点击导航。
它很大可能还会有一些有`RouterLink`指令的a标签或按钮,用户可以用来点击导航。
<a id="S"></a>
.l-main-section

View File

@ -131,7 +131,7 @@ code-example(format="." language="bash").
First modify the `<li>` tag by adding the built-in directive `*ngFor`.
首先,修改`<li>`标,往上添加内建指令:`*ngFor`。
首先,修改`<li>`标,往上添加内建指令:`*ngFor`。
+makeExample('toh-2/ts-snippets/app.component.snippets.pt2.ts', 'heroes-ngfor-1', 'app.component.ts (ngFor)')
@ -176,7 +176,7 @@ code-example(format="." language="bash").
Now we insert some content between the `<li>` tags
that uses the `hero` template variable to display the heros properties.
现在,我们在`<li>`标中插入一些内容,以便使用模板变量`hero`来显示英雄的属性。
现在,我们在`<li>`标中插入一些内容,以便使用模板变量`hero`来显示英雄的属性。
+makeExample('toh-2/ts-snippets/app.component.snippets.pt2.ts', 'ng-for', 'app.component.ts (ngFor模板)')(format=".")

View File

@ -5,7 +5,7 @@ include ../_util-fns
Use cases are flowing in for reusing components, passing data to components, and creating more reusable assets. Let's separate the heroes list from the hero details and make the details component reusable.
我们的应用继续成长。
这次的例子将依次展示:复用组件、给组件传入数据、创建高复用度的软件资产。我们先把英雄列表从英雄详情中分离出来,并且让详情组件可复用。
这次的例子将依次展示:复用组件、给组件传入数据以及创建更容易复用的软件资产。我们先把英雄列表从英雄详情中分离出来,并且让详情组件可复用。
[Run the live example for part 3](/resources/live-examples/toh-3/ts/plnkr.html)
@ -39,7 +39,7 @@ include ../_util-fns
### 让应用代码保持转译和运行
We want to start the TypeScript compiler, have it watch for changes, and start our server. We'll do this by typing
我们要启动TypeScript编译器它会监视文件变更并启动开发服务器。我们只要敲:
我们要启动TypeScript编译器它会监视文件变更并启动开发服务器。只要敲
code-example(format="." language="bash").
npm start
@ -61,8 +61,8 @@ code-example(format="." language="bash").
我们的英雄列表和英雄详情目前位于同一个文件的同一个组件中。
现在它们还很小,但很快它们都会长大。
我们将来肯定会收到新需求:针对这一个,却不能影响另一个。
然而,每一个更改都会给这两个组件带来风险,并且带来双倍的测试负担,却不会带来好处。
如果我们不得不在应用之外复用英雄详情组件,那么英雄列表组件也会跟着混进去。
然而,每一个更改都会给这两个组件带来风险,并且带来双倍的测试负担,却没有任何好处。
如果我们不得不在应用之外复用英雄详情组件,那么英雄列表组件也会跟着混进去。
Our current component violates the
[Single Responsibility Principle](https://blog.8thlight.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html).
@ -70,7 +70,7 @@ code-example(format="." language="bash").
especially if doing them right is easy and we learn how to build Angular apps in the process.
我们这个组件违反了[单一职责原则](https://blog.8thlight.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html)。
虽然这只是一个教程,但我们还是要坚持做正确的事 —— 况且,做正确的事如此容易我们何乐而不为呢别忘了我们正在学习的就是如何构建真正的Angular应用。
虽然这只是一个教程,但我们还是得坚持做正确的事 —— 况且,做正确的事这么容易我们何乐而不为呢别忘了我们正在学习的就是如何构建真正的Angular应用。
Lets break the hero details out into its own component.
@ -79,6 +79,7 @@ code-example(format="." language="bash").
### Separating the Hero Detail Component
### 拆分英雄详情组件
Add a new file named `hero-detail.component.ts` to the `app` folder and create `HeroDetailComponent` as follows.
在`app`目录下添加一个名叫`hero-detail.component.ts`的文件,并且创建`HeroDetailComponent`。代码如下:
+makeExample('toh-3/ts/app/hero-detail.component.ts', 'v1', 'hero-detail.component.ts (初始版本)')(format=".")
@ -93,7 +94,7 @@ code-example(format="." language="bash").
Notice that we have an `AppComponent` in a file named `app.component.ts` and our new
`HeroDetailComponent` is in a file named `hero-detail.component.ts`.
注意,在名叫`app.component.ts`的文件中有一个`AppComponent`组件,在名叫`hero-detail.component.ts`的文件中有一个`HeroDetailComponent`组件。
你会注意,在名叫`app.component.ts`的文件中有一个`AppComponent`组件,在名叫`hero-detail.component.ts`的文件中有一个`HeroDetailComponent`组件。
All of our component names end in "Component". All of our component file names end in ".component".
@ -102,7 +103,7 @@ code-example(format="." language="bash").
We spell our file names in lower dash case (AKA "kebab-case") so we don't worry about
case sensitivity on the server or in source control.
这里我们使用小写中线命名法(也叫烤串命名法),所以我们不用担心它在服务器或者版本控制系统中出现大小写问题。
这里我们使用小写中线命名法(也叫烤串命名法)拼写文件名,所以不用担心它在服务器或者版本控制系统中出现大小写问题。
<!-- TODO
.l-sub-section
:marked
@ -114,26 +115,26 @@ code-example(format="." language="bash").
:marked
We begin by importing the `Component` and `Input` decorators from Angular because we're going to need them soon.
一开始我们先从Angular中导入`Component`和`Input`装饰器,因为马上就会用到它们。
一开始,我们先从Angular中导入`Component`和`Input`装饰器,因为马上就会用到它们。
We create metadata with the `@Component` decorator where we
specify the selector name that identifies this component's element.
Then we export the class to make it available to other components.
我们使用`@Component`装饰器创建元数据在元数据中,我们指定选择器的名字,用以标记此组件的元素。
然后,我们导出这个类,以便其它组件可以使用它。
我们使用`@Component`装饰器创建元数据在元数据中,我们指定选择器的名字,用以标记此组件的元素。
然后,我们导出这个组件类,以便其它组件可以使用它。
When we finish here, we'll import it into `AppComponent` and create a corresponding `<my-hero-detail>` element.
做完这些,我们把它导入`AppComponent`组件,并创建相应的`<my-hero-detail>`元素。
做完这些,我们把它导入`AppComponent`组件,并创建相应的`<my-hero-detail>`元素。
:marked
#### Hero Detail Template
#### 英雄详情模板
At the moment, the *Heroes* and *Hero Detail* views are combined in one template in `AppComponent`.
Lets **cut** the *Hero Detail* content from `AppComponent` and **paste** it into the new template property of `HeroDetailComponent`.
目前,在`AppComponent`中 *英雄列表* 和 *英雄详情* 视图被组合在同一个模板中。
我们从`AppComponent`中 **剪切** *英雄详情* 的内容,并且粘贴到`HeroDetailComponent`组件的`template`属性中。
目前,`AppComponent`的*英雄列表*和*英雄详情*视图被组合在同一个模板中。
我们从`AppComponent`中**剪切**出*英雄详情*的内容,并且粘贴到`HeroDetailComponent`组件的`template`属性中。
We previously bound to the `selectedHero.name` property of the `AppComponent`.
Our `HeroDetailComponent` will have a `hero` property, not a `selectedHero` property.
@ -141,15 +142,15 @@ code-example(format="." language="bash").
The result looks like this:
以前我们绑定到了`AppComponent`的`selectedHero.name`属性中。
我们的`HeroDetailComponent`组件将会有一个`hero`属性,而不是`selectedHero`属性。
所以,我们把模板中的所有`selectedHero`替换为`hero`。只改这些就够了。
`HeroDetailComponent`组件将会有一个`hero`属性,而不是`selectedHero`属性。
所以,我们把模板中的所有`selectedHero`替换为`hero`。只改这些就够了。
最终结果如下所示:
+makeExample('toh-3/ts/app/hero-detail.component.ts', 'template', 'hero-detail.component.ts (模板)')(format=".")
:marked
Now our hero detail layout exists only in the `HeroDetailComponent`.
现在,我们的英雄详情布局只存在于`HeroDetailComponent`组件中。
现在,我们的英雄详情布局只存在于`HeroDetailComponent`组件中
#### Add the *hero* property
#### 添加 *hero* 属性
@ -166,7 +167,7 @@ code-example(format="." language="bash").
We solve the problem by relocating the `Hero` class from `app.component.ts` to its own `hero.ts` file.
解决这个问题,我们也从`app.component.ts`文件中把`Hero`类移到属于它自己的`hero.ts`文件中。
要解决这个问题,我们也从`app.component.ts`文件中把`Hero`类移到属于它自己的`hero.ts`文件中。
+makeExample('toh-3/ts/app/hero.ts', null, 'hero.ts (导出Hero类)')(format=".")
@ -174,54 +175,54 @@ code-example(format="." language="bash").
We export the `Hero` class from `hero.ts` because we'll need to reference it in both component files.
Add the following import statement near the top of both `app.component.ts` and `hero-detail.component.ts`.
我们从`hero.ts`中导出`Hero`类,这是因为我们需要从这些组件文件中引用它。
我们得从`hero.ts`中导出`Hero`类,因为我们要从那些组件文件中引用它。
在`app.component.ts`和`hero-detail.component.ts`的顶部添加下列import语句
+makeExample('toh-3/ts/app/hero-detail.component.ts', 'hero-import', 'hero-detail.component.ts与app.component.ts(导入Hero类)')
:marked
#### The *hero* property is an ***input***
#### *hero* 是一个 ***输入*** 属性
#### *hero*是一个***输入***属性
The `HeroDetailComponent` must be told what hero to display. Who will tell it? The parent `AppComponent`!
还得告诉`HeroDetailComponent`显示哪个英雄。谁告诉它呢?自然是父组件`AppComponent`
还得告诉`HeroDetailComponent`显示哪个英雄。谁告诉它呢?自然是父组件`AppComponent`
The `AppComponent` knows which hero to show: the hero that the user selected from the list.
The user's selection is in its `selectedHero` property.
`AppComponent`自然知道该显示哪个英雄:用户从列表中选中的那个。
这个英雄就是`selectedHero`属性的值。
`AppComponent`确实知道该显示哪个英雄 —— 用户从列表中选中的那个。
这个英雄就是`selectedHero`属性的值。
We will soon update the `AppComponent` template so that it binds its `selectedHero` property
to the `hero` property of our `HeroDetailComponent`. The binding *might* look like this:
我们马上就要升级`AppComponent`模板,以便把该组件的`selectedHero`属性绑定到`HeroDetailComponent`组件的`hero`属性上。
绑定看起来可能是这样的:
我们马上升级`AppComponent`模板,以便把该组件的`selectedHero`属性绑定到`HeroDetailComponent`组件的`hero`属性上。
绑定看起来*可能*是这样的:
code-example(format=".").
&lt;my-hero-detail [hero]="selectedHero">&lt;/my-hero-detail>
:marked
Notice that the `hero` property is the ***target*** of a property binding &mdash; it's in square brackets to the left of the (=).
注意,在等号(=)左边方括号中的这个`hero`是属性绑定的目标。
注意,在等号(=)左边方括号中的这个`hero`是属性绑定的***目标***
Angular insists that we declare a ***target*** property to be an ***input*** property.
If we don't, Angular rejects the binding and throws an error.
Angular期望我们把 ***目标属性*** 定义成组件的 ***输入属性*** 否则Angular会拒绝绑定并且抛出一个错误。
Angular希望我们把***目标属性***定义成组件的***输入属性***否则Angular会拒绝绑定并且抛出一个错误。
.l-sub-section
:marked
We explain input properties in more detail [here](../guide/attribute-directives.html#why-input)
where we also explain why *target* properties require this special treatment and
*source* properties do not.
我们在[这里](../guide/attribute-directives.html#why-input)详细解释了输入属性,以及为什么 *目标属性* 需要这种特殊待遇,而 *来源属性* 却不需要。
我们在[这里](../guide/attribute-directives.html#why-input)详细解释了输入属性,以及为什么*目标属性*需要“显式定义”这样的特殊待遇,而*来源属性*却不需要。
:marked
There are a couple of ways we can declare that `hero` is an *input*.
We'll do it the way we *prefer*, by annotating the `hero` property with the `@Input` decorator that we imported earlier.
我们有一大堆方式把`hero`声明成 *输入属性*
这里我们采用建议的方式:使用我们前面导入的`@Input`装饰器,为`hero`属性加上注解。
我们有几种方式把`hero`声明成*输入属性*
这里我们采用*首选*的方式:使用我们前面导入的`@Input`装饰器,为`hero`属性加上注解。
+makeExample('toh-3/ts/app/hero-detail.component.ts', 'hero-input')(format='.')
.l-sub-section
@ -247,7 +248,7 @@ code-example(format=".").
Find the location in the template where we removed the *Hero Detail* content
and add an element tag that represents the `HeroDetailComponent`.
找到我们刚刚从模板中移除 *英雄详情* 的地方,放上用来表示`HeroDetailComponent`组件的HTML标
找到我们刚刚从模板中移除*英雄详情*的地方,放上用来表示`HeroDetailComponent`组件的HTML标
code-example(format=".").
&lt;my-hero-detail>&lt;/my-hero-detail>
.l-sub-section
@ -260,7 +261,7 @@ code-example(format=".").
to the `HeroDetailComponent` element's `hero` property like this:
这两个组件目前还不能协同工作,直到我们把`AppComponent`组件的`selectedHero`属性和`HeroDetailComponent`组件的`hero`属性绑定在一起,就像这样:
code-example(format=".")
code-example(format=".").
&lt;my-hero-detail [hero]="selectedHero">&lt;/my-hero-detail>
:marked
The `AppComponent`s template should now look like this
@ -272,12 +273,12 @@ code-example(format=".")
Thanks to the binding, the `HeroDetailComponent` should receive the hero from the `AppComponent` and display that hero's detail beneath the list.
The detail should update every time the user picks a new hero.
感谢数据绑定机制,`HeroDetailComponent`组件可以从`AppComponent`组件中获取英雄数据,并且在列表的下方显示英雄的详情。
感谢数据绑定机制,`HeroDetailComponent`组件应该能从`AppComponent`组件中获取英雄数据,并且在列表的下方显示英雄的详情
每当用户选中一个新的英雄时,详情信息应该随之更新。
It's not happening yet!
但什么没有发生!
但什么没有发生!
We click among the heroes. No details. We look for an error in the console of the browser development tools. No error.
@ -285,12 +286,12 @@ code-example(format=".")
It is as if Angular were ignoring the new tag. That's because *it is ignoring the new tag*.
看起来像是Angular忽略了这个新标记。确实这是因为 *它忽略了不认识的标记*
看起来好像Angular忽略了这个新标签。确实如此这是因为*它忽略了不认识的标签*
### The *directives* array
### *directives* 数组
A browser ignores HTML tags and attributes that it doesn't recognize. So does Angular.
浏览器会忽略它不认识的HTML标和属性。Angular也是这样。
浏览器会忽略它不认识的HTML标和属性。Angular也是这样。
We've imported `HeroDetailComponent`, we've used it in the template, but we haven't told Angular about it.

View File

@ -345,7 +345,7 @@ code-example(format="." language="html").
Recall that the `AppComponent` creates an instance of `HeroDetail` by virtue of the
`<my-hero-detail>` tag at the bottom of its template. That `HeroDetail` is a child of the `AppComponent`.
回忆一下,`AppComponent`在它的模板底部包含了一个`<my-hero-detail>`标,于是创建了一个`HeroDetail`的实例。这个`HeroDetail`就叫做`AppComponent`的子组件。
回忆一下,`AppComponent`在它的模板底部包含了一个`<my-hero-detail>`标,于是创建了一个`HeroDetail`的实例。这个`HeroDetail`就叫做`AppComponent`的子组件。
If the `HeroDetailComponent` needed its parent component's `HeroService`,
it would ask Angular to inject the service into its constructor which would look just like the one for `AppComponent`: