Add some blank lines, to avoid unnecessary conflicts on merging.
This commit is contained in:
parent
c1b8183c38
commit
20c59f9e4a
@ -32,7 +32,7 @@
|
|||||||
},
|
},
|
||||||
"toh-pt6": {
|
"toh-pt6": {
|
||||||
"title": "Http",
|
"title": "Http",
|
||||||
"intro": "We convert our service and components to use Http",
|
"intro": "把我们的服务和组件改用Http实现",
|
||||||
"nextable": true
|
"nextable": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ include ../_util-fns
|
|||||||
// #docregion intro
|
// #docregion intro
|
||||||
:marked
|
:marked
|
||||||
# Tour of Heroes: the vision
|
# Tour of Heroes: the vision
|
||||||
|
|
||||||
# 《英雄指南》目标概览
|
# 《英雄指南》目标概览
|
||||||
|
|
||||||
Our grand plan is to build an app to help a staffing agency manage its stable of heroes.
|
Our grand plan is to build an app to help a staffing agency manage its stable of heroes.
|
||||||
@ -53,6 +54,7 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-6')]。
|
|||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## The End Game
|
## The End Game
|
||||||
|
|
||||||
## 游戏的终点
|
## 游戏的终点
|
||||||
|
|
||||||
Here's a visual idea of where we're going in this tour, beginning with the "Dashboard"
|
Here's a visual idea of where we're going in this tour, beginning with the "Dashboard"
|
||||||
@ -118,6 +120,7 @@ figure.image-display
|
|||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## Up Next
|
## Up Next
|
||||||
|
|
||||||
## 接下来
|
## 接下来
|
||||||
|
|
||||||
We’ll build this Tour of Heroes together, step by step.
|
We’ll build this Tour of Heroes together, step by step.
|
||||||
|
@ -2,6 +2,7 @@ include ../_util-fns
|
|||||||
|
|
||||||
:marked
|
:marked
|
||||||
# Once Upon a Time
|
# Once Upon a Time
|
||||||
|
|
||||||
# 很久很久以前
|
# 很久很久以前
|
||||||
|
|
||||||
Every story starts somewhere. Our story starts where the [QuickStart](../quickstart.html) ends.
|
Every story starts somewhere. Our story starts where the [QuickStart](../quickstart.html) ends.
|
||||||
@ -41,7 +42,9 @@ include ../_quickstart_repo
|
|||||||
.file typings.json
|
.file typings.json
|
||||||
:marked
|
:marked
|
||||||
## Keep the app transpiling and running
|
## Keep the app transpiling and running
|
||||||
|
|
||||||
## 保持应用不断转译和运行
|
## 保持应用不断转译和运行
|
||||||
|
|
||||||
We want to start the TypeScript compiler, have it watch for changes, and start our server. We'll do this by typing
|
We want to start the TypeScript compiler, have it watch for changes, and start our server. We'll do this by typing
|
||||||
|
|
||||||
我们要启动TypeScript编译器,它会监视文件变更,并且启动开发服务器。我们只要敲:
|
我们要启动TypeScript编译器,它会监视文件变更,并且启动开发服务器。我们只要敲:
|
||||||
@ -58,7 +61,9 @@ code-example(language="bash").
|
|||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## Show our Hero
|
## Show our Hero
|
||||||
|
|
||||||
## 显示我们的英雄
|
## 显示我们的英雄
|
||||||
|
|
||||||
We want to display Hero data in our app
|
We want to display Hero data in our app
|
||||||
|
|
||||||
我们要在应用中显示英雄数据
|
我们要在应用中显示英雄数据
|
||||||
@ -92,8 +97,10 @@ code-example(language="bash").
|
|||||||
Learn more about interpolation in the [Displaying Data chapter](../guide/displaying-data.html).
|
Learn more about interpolation in the [Displaying Data chapter](../guide/displaying-data.html).
|
||||||
|
|
||||||
要了解插值表达式的更多知识,参阅[“显示数据”一章](../guide/displaying-data.html)。
|
要了解插值表达式的更多知识,参阅[“显示数据”一章](../guide/displaying-data.html)。
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
### Hero object
|
### Hero object
|
||||||
|
|
||||||
### Hero对象
|
### Hero对象
|
||||||
|
|
||||||
At the moment, our hero is just a name. Our hero needs more properties.
|
At the moment, our hero is just a name. Our hero needs more properties.
|
||||||
@ -132,7 +139,9 @@ code-example(language="bash").
|
|||||||
浏览器自动刷新,并继续显示这位英雄的名字。
|
浏览器自动刷新,并继续显示这位英雄的名字。
|
||||||
|
|
||||||
### Adding more HTML
|
### Adding more HTML
|
||||||
|
|
||||||
### 添加更多的HTML
|
### 添加更多的HTML
|
||||||
|
|
||||||
Displaying a name is good, but we want to see all of our hero’s properties.
|
Displaying a name is good, but we want to see all of our hero’s properties.
|
||||||
We’ll add a `<div>` for our hero’s `id` property and another `<div>` for our hero’s `name`.
|
We’ll add a `<div>` for our hero’s `id` property and another `<div>` for our hero’s `name`.
|
||||||
|
|
||||||
@ -146,6 +155,7 @@ code-example(language="bash").
|
|||||||
啊哦!我们的模板字符串已经太长了。我们最好小心点,免得在模板中出现拼写错误。
|
啊哦!我们的模板字符串已经太长了。我们最好小心点,免得在模板中出现拼写错误。
|
||||||
|
|
||||||
### Multi-line template strings
|
### Multi-line template strings
|
||||||
|
|
||||||
### 多行模板字符串
|
### 多行模板字符串
|
||||||
|
|
||||||
We could make a more readable template with string concatenation
|
We could make a more readable template with string concatenation
|
||||||
@ -166,7 +176,9 @@ code-example(language="bash").
|
|||||||
|
|
||||||
.callout.is-important
|
.callout.is-important
|
||||||
header A back-tick is not a single quote
|
header A back-tick is not a single quote
|
||||||
|
|
||||||
header 反引号不是单引号
|
header 反引号不是单引号
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
**Be careful!** A back-tick (`) looks a lot like a single quote (').
|
**Be careful!** A back-tick (`) looks a lot like a single quote (').
|
||||||
It's actually a completely different character.
|
It's actually a completely different character.
|
||||||
@ -183,6 +195,7 @@ code-example(language="bash").
|
|||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## Editing Our Hero
|
## Editing Our Hero
|
||||||
|
|
||||||
## 编辑我们的英雄
|
## 编辑我们的英雄
|
||||||
|
|
||||||
We want to be able to edit the hero name in a textbox.
|
We want to be able to edit the hero name in a textbox.
|
||||||
@ -194,6 +207,7 @@ code-example(language="bash").
|
|||||||
把英雄的名字从单纯的`<label>`重构成`<label>`和`<input>`元素的组合,就像下面这样:
|
把英雄的名字从单纯的`<label>`重构成`<label>`和`<input>`元素的组合,就像下面这样:
|
||||||
|
|
||||||
+makeExample('toh-1/ts-snippets/app.component.snippets.pt1.ts', 'editing-Hero', 'app.component.ts (input元素)')
|
+makeExample('toh-1/ts-snippets/app.component.snippets.pt1.ts', 'editing-Hero', 'app.component.ts (input元素)')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
We see in the browser that the hero’s name does appear in the `<input>` textbox.
|
We see in the browser that the hero’s name does appear in the `<input>` textbox.
|
||||||
But something doesn’t feel right.
|
But something doesn’t feel right.
|
||||||
@ -205,6 +219,7 @@ code-example(language="bash").
|
|||||||
当修改名字时,我们的改动并没有反映到`<h2>`中。使用单向数据绑定,我们没法实现所期望的这种行为。
|
当修改名字时,我们的改动并没有反映到`<h2>`中。使用单向数据绑定,我们没法实现所期望的这种行为。
|
||||||
|
|
||||||
### Two-Way Binding
|
### Two-Way Binding
|
||||||
|
|
||||||
### 双向绑定
|
### 双向绑定
|
||||||
|
|
||||||
We intend to display the name of the hero in the `<input>`, change it,
|
We intend to display the name of the hero in the `<input>`, change it,
|
||||||
@ -226,6 +241,7 @@ code-example(language="bash").
|
|||||||
|
|
||||||
要学习关于`ngModel`的更多知识,参见[表单](../guide/forms.html#ngModel)和
|
要学习关于`ngModel`的更多知识,参见[表单](../guide/forms.html#ngModel)和
|
||||||
[模板语法](../guide/template-syntax.html#ngModel)两章
|
[模板语法](../guide/template-syntax.html#ngModel)两章
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Replace the `<input>` with the following HTML
|
Replace the `<input>` with the following HTML
|
||||||
|
|
||||||
@ -243,20 +259,29 @@ code-example(language="html").
|
|||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## The Road We’ve Travelled
|
## The Road We’ve Travelled
|
||||||
|
|
||||||
## 我们已经走过的路
|
## 我们已经走过的路
|
||||||
|
|
||||||
Let’s take stock of what we’ve built.
|
Let’s take stock of what we’ve built.
|
||||||
|
|
||||||
我们来盘点一下已经构建完成的部分。
|
我们来盘点一下已经构建完成的部分。
|
||||||
|
|
||||||
* Our Tour of Heroes uses the double curly braces of interpolation (a form of one-way data binding)
|
* Our Tour of Heroes uses the double curly braces of interpolation (a form of one-way data binding)
|
||||||
to display the application title and properties of a `Hero` object.
|
to display the application title and properties of a `Hero` object.
|
||||||
|
|
||||||
* 我们的《英雄指南》使用双大括号(插值表达式 —— 单向数据绑定的一种形式)来显示应用的标题和`Hero`对象的属性。
|
* 我们的《英雄指南》使用双大括号(插值表达式 —— 单向数据绑定的一种形式)来显示应用的标题和`Hero`对象的属性。
|
||||||
|
|
||||||
* We wrote a multi-line template using ES2015’s template strings to make our template readable.
|
* We wrote a multi-line template using ES2015’s template strings to make our template readable.
|
||||||
|
|
||||||
* 我们使用ES2105的模板字符串写了一个多行模板,来让我们的模板更有可读性。
|
* 我们使用ES2105的模板字符串写了一个多行模板,来让我们的模板更有可读性。
|
||||||
|
|
||||||
* We can both display and change the hero’s name after adding a two-way data binding to the `<input>` element
|
* We can both display and change the hero’s name after adding a two-way data binding to the `<input>` element
|
||||||
using the built-in `ngModel` directive.
|
using the built-in `ngModel` directive.
|
||||||
|
|
||||||
* 为了同时显示和修改英雄的名字,我们还使用了内建的`ngModel`指令,往`<input>`元素上添加了双向数据绑定。
|
* 为了同时显示和修改英雄的名字,我们还使用了内建的`ngModel`指令,往`<input>`元素上添加了双向数据绑定。
|
||||||
|
|
||||||
* The `ngModel` directive also propagates changes to every other binding of the `hero.name`.
|
* The `ngModel` directive also propagates changes to every other binding of the `hero.name`.
|
||||||
|
|
||||||
* 通过`ngModel`指令,这些修改还影响到了每一个对`hero.name`的其它绑定。
|
* 通过`ngModel`指令,这些修改还影响到了每一个对`hero.name`的其它绑定。
|
||||||
|
|
||||||
p Run the #[+liveExampleLink2('', 'toh-1')] for this part.
|
p Run the #[+liveExampleLink2('', 'toh-1')] for this part.
|
||||||
@ -273,7 +298,9 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-1')]。
|
|||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## The Road Ahead
|
## The Road Ahead
|
||||||
|
|
||||||
## 前方的路
|
## 前方的路
|
||||||
|
|
||||||
Our Tour of Heroes only displays one hero and we really want to display a list of heroes.
|
Our Tour of Heroes only displays one hero and we really want to display a list of heroes.
|
||||||
We also want to allow the user to select a hero and display their details.
|
We also want to allow the user to select a hero and display their details.
|
||||||
We’ll learn more about how to retrieve lists, bind them to the
|
We’ll learn more about how to retrieve lists, bind them to the
|
||||||
|
@ -2,7 +2,9 @@ include ../_util-fns
|
|||||||
|
|
||||||
:marked
|
:marked
|
||||||
# It Takes Many Heroes
|
# It Takes Many Heroes
|
||||||
|
|
||||||
# 需要多个英雄
|
# 需要多个英雄
|
||||||
|
|
||||||
Our story needs more heroes.
|
Our story needs more heroes.
|
||||||
We’ll expand our Tour of Heroes app to display a list of heroes,
|
We’ll expand our Tour of Heroes app to display a list of heroes,
|
||||||
allow the user to select a hero, and display the hero’s details.
|
allow the user to select a hero, and display the hero’s details.
|
||||||
@ -24,7 +26,9 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-2')]。
|
|||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## Where We Left Off
|
## Where We Left Off
|
||||||
|
|
||||||
## 我们在哪儿
|
## 我们在哪儿
|
||||||
|
|
||||||
Before we continue with Part 2 of the Tour of Heroes,
|
Before we continue with Part 2 of the Tour of Heroes,
|
||||||
let’s verify we have the following structure after [Part 1](./toh-pt1.html).
|
let’s verify we have the following structure after [Part 1](./toh-pt1.html).
|
||||||
If not, we’ll need to go back to Part 1 and figure out what we missed.
|
If not, we’ll need to go back to Part 1 and figure out what we missed.
|
||||||
@ -48,7 +52,9 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-2')]。
|
|||||||
.file typings.json
|
.file typings.json
|
||||||
:marked
|
:marked
|
||||||
### Keep the app transpiling and running
|
### Keep the app transpiling and running
|
||||||
|
|
||||||
### 让应用代码保持转译和运行
|
### 让应用代码保持转译和运行
|
||||||
|
|
||||||
We want to start the TypeScript compiler, have it watch for changes, and start our server. We'll do this by typing
|
We want to start the TypeScript compiler, have it watch for changes, and start our server. We'll do this by typing
|
||||||
|
|
||||||
我们要启动TypeScript编译器,它会监视文件变更,并启动开发服务器。我们只要敲:
|
我们要启动TypeScript编译器,它会监视文件变更,并启动开发服务器。我们只要敲:
|
||||||
@ -64,9 +70,13 @@ code-example(language="bash").
|
|||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## Displaying Our Heroes
|
## Displaying Our Heroes
|
||||||
|
|
||||||
## 显示我们的英雄
|
## 显示我们的英雄
|
||||||
|
|
||||||
### Creating heroes
|
### Creating heroes
|
||||||
|
|
||||||
### 创建英雄
|
### 创建英雄
|
||||||
|
|
||||||
Let’s create an array of ten heroes at the bottom of `app.component.ts`.
|
Let’s create an array of ten heroes at the bottom of `app.component.ts`.
|
||||||
|
|
||||||
我们先在`app.component.ts`的底部创建一个由十位英雄组成的数组。
|
我们先在`app.component.ts`的底部创建一个由十位英雄组成的数组。
|
||||||
@ -83,7 +93,9 @@ code-example(language="bash").
|
|||||||
我们当然希望从一个Web服务中获取这个英雄列表,但别急,我们得把步子迈得小一点儿 —— 先用一组Mock(模拟)出来的英雄。
|
我们当然希望从一个Web服务中获取这个英雄列表,但别急,我们得把步子迈得小一点儿 —— 先用一组Mock(模拟)出来的英雄。
|
||||||
|
|
||||||
### Exposing heroes
|
### Exposing heroes
|
||||||
|
|
||||||
### 导出英雄们
|
### 导出英雄们
|
||||||
|
|
||||||
Let’s create a public property in `AppComponent` that exposes the heroes for binding.
|
Let’s create a public property in `AppComponent` that exposes the heroes for binding.
|
||||||
|
|
||||||
我们在`AppComponent`上创建一个公开属性,用来暴露这些英雄,以供绑定。
|
我们在`AppComponent`上创建一个公开属性,用来暴露这些英雄,以供绑定。
|
||||||
@ -94,6 +106,7 @@ code-example(language="bash").
|
|||||||
We did not have to define the `heroes` type. TypeScript can infer it from the `HEROES` array.
|
We did not have to define the `heroes` type. TypeScript can infer it from the `HEROES` array.
|
||||||
|
|
||||||
我们并不需要明确定义`heroes`属性的数据类型,TypeScript能从`HEROES`数组中推断出来。
|
我们并不需要明确定义`heroes`属性的数据类型,TypeScript能从`HEROES`数组中推断出来。
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
We could have defined the heroes list here in this component class.
|
We could have defined the heroes list here in this component class.
|
||||||
@ -104,9 +117,12 @@ code-example(language="bash").
|
|||||||
我们已经把英雄列表定义在了这个组件类中。
|
我们已经把英雄列表定义在了这个组件类中。
|
||||||
但显然,我们最终还是得从一个数据服务中获取这些英雄。
|
但显然,我们最终还是得从一个数据服务中获取这些英雄。
|
||||||
正因如此,我们从一开始就要有意识的把英雄数据隔离到一个类中来实现。
|
正因如此,我们从一开始就要有意识的把英雄数据隔离到一个类中来实现。
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
### Displaying heroes in a template
|
### Displaying heroes in a template
|
||||||
|
|
||||||
### 在一个模板中显示英雄
|
### 在一个模板中显示英雄
|
||||||
|
|
||||||
Our component has `heroes`. Let’s create an unordered list in our template to display them.
|
Our component has `heroes`. Let’s create an unordered list in our template to display them.
|
||||||
We’ll insert the following chunk of HTML below the title and above the hero details.
|
We’ll insert the following chunk of HTML below the title and above the hero details.
|
||||||
|
|
||||||
@ -121,6 +137,7 @@ code-example(language="bash").
|
|||||||
现在,我们有了一个模板。接下来,就用英雄们的数据来填充它。
|
现在,我们有了一个模板。接下来,就用英雄们的数据来填充它。
|
||||||
|
|
||||||
### Listing heroes with ngFor
|
### Listing heroes with ngFor
|
||||||
|
|
||||||
### 通过ngFor来显示英雄列表
|
### 通过ngFor来显示英雄列表
|
||||||
|
|
||||||
We want to bind the array of `heroes` in our component to our template, iterate over them,
|
We want to bind the array of `heroes` in our component to our template, iterate over them,
|
||||||
@ -187,7 +204,9 @@ code-example(language="bash").
|
|||||||
当浏览器刷新时,我们就看到了英雄列表。
|
当浏览器刷新时,我们就看到了英雄列表。
|
||||||
|
|
||||||
### Styling our heroes
|
### Styling our heroes
|
||||||
|
|
||||||
### 给我们的英雄们“美容”
|
### 给我们的英雄们“美容”
|
||||||
|
|
||||||
Our list of heroes looks pretty bland.
|
Our list of heroes looks pretty bland.
|
||||||
We want to make it visually obvious to a user which hero we are hovering over and which hero is selected.
|
We want to make it visually obvious to a user which hero we are hovering over and which hero is selected.
|
||||||
|
|
||||||
@ -224,7 +243,9 @@ code-example(language="bash").
|
|||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## Selecting a Hero
|
## Selecting a Hero
|
||||||
|
|
||||||
## 选择英雄
|
## 选择英雄
|
||||||
|
|
||||||
We have a list of heroes and we have a single hero displayed in our app.
|
We have a list of heroes and we have a single hero displayed in our app.
|
||||||
The list and the single hero are not connected in any way.
|
The list and the single hero are not connected in any way.
|
||||||
We want the user to select a hero from our list, and have the selected hero appear in the details view.
|
We want the user to select a hero from our list, and have the selected hero appear in the details view.
|
||||||
@ -242,7 +263,9 @@ code-example(language="bash").
|
|||||||
我们通过组件中的一个`selectedHero`属性来连接主从视图。它被绑定到了click事件上。
|
我们通过组件中的一个`selectedHero`属性来连接主从视图。它被绑定到了click事件上。
|
||||||
|
|
||||||
### Click event
|
### Click event
|
||||||
|
|
||||||
### click事件
|
### click事件
|
||||||
|
|
||||||
We modify the `<li>` by inserting an Angular event binding to its click event.
|
We modify the `<li>` by inserting an Angular event binding to its click event.
|
||||||
|
|
||||||
我们往`<li>`元素上插入一句Angular事件绑定代码,绑定到它的click事件。
|
我们往`<li>`元素上插入一句Angular事件绑定代码,绑定到它的click事件。
|
||||||
@ -253,8 +276,10 @@ code-example(language="bash").
|
|||||||
Focus on the event binding
|
Focus on the event binding
|
||||||
|
|
||||||
事件绑定详解
|
事件绑定详解
|
||||||
|
|
||||||
code-example(format="." language="bash").
|
code-example(format="." language="bash").
|
||||||
(click)="onSelect(hero)"
|
(click)="onSelect(hero)"
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
The parenthesis identify the `<li>` element’s `click` event as the target.
|
The parenthesis identify the `<li>` element’s `click` event as the target.
|
||||||
The expression to the right of the equal sign calls the `AppComponent` method, `onSelect()`,
|
The expression to the right of the equal sign calls the `AppComponent` method, `onSelect()`,
|
||||||
@ -277,7 +302,9 @@ code-example(language="bash").
|
|||||||
|
|
||||||
:marked
|
:marked
|
||||||
### Add the click handler
|
### Add the click handler
|
||||||
|
|
||||||
### 添加click事件处理器
|
### 添加click事件处理器
|
||||||
|
|
||||||
Our event binding refers to an `onSelect` method that doesn’t exist yet.
|
Our event binding refers to an `onSelect` method that doesn’t exist yet.
|
||||||
We’ll add that method to our component now.
|
We’ll add that method to our component now.
|
||||||
|
|
||||||
@ -293,6 +320,7 @@ code-example(language="bash").
|
|||||||
我们的组件还没有用来表示“当前选中的英雄”的变量,我们就从这一步儿开始。
|
我们的组件还没有用来表示“当前选中的英雄”的变量,我们就从这一步儿开始。
|
||||||
|
|
||||||
### Expose the selected hero
|
### Expose the selected hero
|
||||||
|
|
||||||
### 导出“当前选中的英雄”
|
### 导出“当前选中的英雄”
|
||||||
|
|
||||||
We no longer need the static `hero` property of the `AppComponent`.
|
We no longer need the static `hero` property of the `AppComponent`.
|
||||||
@ -324,8 +352,10 @@ code-example(language="bash").
|
|||||||
我们这就修改模板,让它绑定到新的`selectedHero`属性上去。
|
我们这就修改模板,让它绑定到新的`selectedHero`属性上去。
|
||||||
|
|
||||||
+makeExample('toh-2/ts-snippets/app.component.snippets.pt2.ts', 'selectedHero-details', 'app.component.ts (template excerpt)')
|
+makeExample('toh-2/ts-snippets/app.component.snippets.pt2.ts', 'selectedHero-details', 'app.component.ts (template excerpt)')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
### Hide the empty detail with ngIf
|
### Hide the empty detail with ngIf
|
||||||
|
|
||||||
### 利用ngIf隐藏空的详情
|
### 利用ngIf隐藏空的详情
|
||||||
|
|
||||||
When our app loads we see a list of heroes, but a hero is not selected.
|
When our app loads we see a list of heroes, but a hero is not selected.
|
||||||
@ -335,6 +365,7 @@ code-example(language="bash").
|
|||||||
当应用刚加载时,我们会看到一个英雄列表,但还没有任何英雄被选中。
|
当应用刚加载时,我们会看到一个英雄列表,但还没有任何英雄被选中。
|
||||||
`selectedHero`属性是`undefined`。
|
`selectedHero`属性是`undefined`。
|
||||||
因此,我们会看到浏览器控制台中出现下列错误:
|
因此,我们会看到浏览器控制台中出现下列错误:
|
||||||
|
|
||||||
code-example(language="html").
|
code-example(language="html").
|
||||||
EXCEPTION: TypeError: Cannot read property 'name' of undefined in [null]
|
EXCEPTION: TypeError: Cannot read property 'name' of undefined in [null]
|
||||||
|
|
||||||
@ -402,6 +433,7 @@ code-example(language="bash").
|
|||||||
正如我们所预期的那样。
|
正如我们所预期的那样。
|
||||||
|
|
||||||
### Styling the selection
|
### Styling the selection
|
||||||
|
|
||||||
### 给所选英雄添加样式
|
### 给所选英雄添加样式
|
||||||
|
|
||||||
We see the selected hero in the details area below but we can’t quickly locate that hero in the list above.
|
We see the selected hero in the details area below but we can’t quickly locate that hero in the list above.
|
||||||
@ -415,6 +447,7 @@ code-example(language="bash").
|
|||||||
|
|
||||||
figure.image-display
|
figure.image-display
|
||||||
img(src='/resources/images/devguide/toh/heroes-list-selected.png' alt="选中的英雄")
|
img(src='/resources/images/devguide/toh/heroes-list-selected.png' alt="选中的英雄")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
We’ll add a property binding on `class` for the `selected` class to the template. We'll set this to an expression that compares the current `selectedHero` to the `hero`.
|
We’ll add a property binding on `class` for the `selected` class to the template. We'll set this to an expression that compares the current `selectedHero` to the `hero`.
|
||||||
|
|
||||||
@ -425,7 +458,9 @@ code-example(language="bash").
|
|||||||
|
|
||||||
关键是CSS类的名字:`selected`。当两位英雄一致时,它为`true`,否则为`false`。
|
关键是CSS类的名字:`selected`。当两位英雄一致时,它为`true`,否则为`false`。
|
||||||
也就是说:“*当两位英雄匹配时,应用上`selected`类,否则不应用*”。
|
也就是说:“*当两位英雄匹配时,应用上`selected`类,否则不应用*”。
|
||||||
|
|
||||||
+makeExample('toh-2/ts-snippets/app.component.snippets.pt2.ts', 'class-selected-1', 'app.component.ts (setting the CSS class)')(format=".")
|
+makeExample('toh-2/ts-snippets/app.component.snippets.pt2.ts', 'class-selected-1', 'app.component.ts (setting the CSS class)')(format=".")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Notice in the template that the `class.selected` is surrounded in square brackets (`[]`).
|
Notice in the template that the `class.selected` is surrounded in square brackets (`[]`).
|
||||||
This is the syntax for a **property binding**, a binding in which data flows one way
|
This is the syntax for a **property binding**, a binding in which data flows one way
|
||||||
@ -450,6 +485,7 @@ code-example(language="bash").
|
|||||||
|
|
||||||
浏览器重新加载了你的应用。
|
浏览器重新加载了你的应用。
|
||||||
我们选中英雄Magneta,于是他通过背景色的变化被清晰的标记了出来。
|
我们选中英雄Magneta,于是他通过背景色的变化被清晰的标记了出来。
|
||||||
|
|
||||||
figure.image-display
|
figure.image-display
|
||||||
img(src='/resources/images/devguide/toh/heroes-list-1.png' alt="英雄列表应用的输出")
|
img(src='/resources/images/devguide/toh/heroes-list-1.png' alt="英雄列表应用的输出")
|
||||||
|
|
||||||
@ -467,16 +503,23 @@ code-example(language="bash").
|
|||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## The Road We’ve Travelled
|
## The Road We’ve Travelled
|
||||||
|
|
||||||
## 已走的路
|
## 已走的路
|
||||||
|
|
||||||
Here’s what we achieved in this chapter:
|
Here’s what we achieved in this chapter:
|
||||||
|
|
||||||
在本章中,我们达成了这些:
|
在本章中,我们达成了这些:
|
||||||
|
|
||||||
* Our Tour of Heroes now displays a list of selectable heroes
|
* Our Tour of Heroes now displays a list of selectable heroes
|
||||||
|
|
||||||
* 我们的《英雄指南》现在显示一个可选英雄的列表
|
* 我们的《英雄指南》现在显示一个可选英雄的列表
|
||||||
|
|
||||||
* We added the ability to select a hero and show the hero’s details
|
* We added the ability to select a hero and show the hero’s details
|
||||||
|
|
||||||
* 我们添加了选择英雄的能力,并且会显示这个英雄的详情
|
* 我们添加了选择英雄的能力,并且会显示这个英雄的详情
|
||||||
|
|
||||||
* We learned how to use the built-in directives `ngIf` and `ngFor` in a component’s template
|
* We learned how to use the built-in directives `ngIf` and `ngFor` in a component’s template
|
||||||
|
|
||||||
* 我们学会了如何在组件模板中使用内建的`ngIf`和`ngFor`指令
|
* 我们学会了如何在组件模板中使用内建的`ngIf`和`ngFor`指令
|
||||||
|
|
||||||
p Run the #[+liveExampleLink2('', 'toh-2')] for this part.
|
p Run the #[+liveExampleLink2('', 'toh-2')] for this part.
|
||||||
@ -485,7 +528,9 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-2')]。
|
|||||||
|
|
||||||
:marked
|
:marked
|
||||||
### The Road Ahead
|
### The Road Ahead
|
||||||
|
|
||||||
### 前方的路
|
### 前方的路
|
||||||
|
|
||||||
Our Tour of Heroes has grown, but it’s far from complete.
|
Our Tour of Heroes has grown, but it’s far from complete.
|
||||||
We can't put the entire app into a single component.
|
We can't put the entire app into a single component.
|
||||||
We need to break it up into sub-components and teach them to work together
|
We need to break it up into sub-components and teach them to work together
|
||||||
|
@ -14,7 +14,9 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-3')]。
|
|||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## Where We Left Off
|
## Where We Left Off
|
||||||
|
|
||||||
## 我们在哪儿
|
## 我们在哪儿
|
||||||
|
|
||||||
Before we continue with our Tour of Heroes, let’s verify we have the following structure. If not, we’ll need to go back and follow the previous chapters.
|
Before we continue with our Tour of Heroes, let’s verify we have the following structure. If not, we’ll need to go back and follow the previous chapters.
|
||||||
|
|
||||||
在继续《英雄指南》之前,先来检查一下,你是否已经有了如下目录结构。如果没有,你得先回上一章,看看错过了哪里。
|
在继续《英雄指南》之前,先来检查一下,你是否已经有了如下目录结构。如果没有,你得先回上一章,看看错过了哪里。
|
||||||
@ -34,9 +36,12 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-3')]。
|
|||||||
.file systemjs.config.js
|
.file systemjs.config.js
|
||||||
.file tsconfig.json
|
.file tsconfig.json
|
||||||
.file typings.json
|
.file typings.json
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
### Keep the app transpiling and running
|
### Keep the app transpiling and running
|
||||||
|
|
||||||
### 让应用代码保持转译和运行
|
### 让应用代码保持转译和运行
|
||||||
|
|
||||||
We want to start the TypeScript compiler, have it watch for changes, and start our server. We'll do this by typing
|
We want to start the TypeScript compiler, have it watch for changes, and start our server. We'll do this by typing
|
||||||
|
|
||||||
我们要启动TypeScript编译器,它会监视文件变更,并启动开发服务器。只要敲:
|
我们要启动TypeScript编译器,它会监视文件变更,并启动开发服务器。只要敲:
|
||||||
@ -50,7 +55,9 @@ code-example(language="bash").
|
|||||||
这个命令会在我们构建《英雄指南》的时候让应用得以持续运行。
|
这个命令会在我们构建《英雄指南》的时候让应用得以持续运行。
|
||||||
|
|
||||||
## Making a Hero Detail Component
|
## Making a Hero Detail Component
|
||||||
|
|
||||||
## 制作英雄详情组件
|
## 制作英雄详情组件
|
||||||
|
|
||||||
Our heroes list and our hero details are in the same component in the same file.
|
Our heroes list and our hero details are in the same component in the same file.
|
||||||
They're small now but each could grow.
|
They're small now but each could grow.
|
||||||
We are sure to receive new requirements for one and not the other.
|
We are sure to receive new requirements for one and not the other.
|
||||||
@ -77,16 +84,21 @@ code-example(language="bash").
|
|||||||
我们来把英雄详情拆分成一个独立的组件。
|
我们来把英雄详情拆分成一个独立的组件。
|
||||||
|
|
||||||
### Separating the Hero Detail Component
|
### Separating the Hero Detail Component
|
||||||
|
|
||||||
### 拆分英雄详情组件
|
### 拆分英雄详情组件
|
||||||
|
|
||||||
Add a new file named `hero-detail.component.ts` to the `app` folder and create `HeroDetailComponent` as follows.
|
Add a new file named `hero-detail.component.ts` to the `app` folder and create `HeroDetailComponent` as follows.
|
||||||
|
|
||||||
在`app`目录下添加一个名叫`hero-detail.component.ts`的文件,并且创建`HeroDetailComponent`。代码如下:
|
在`app`目录下添加一个名叫`hero-detail.component.ts`的文件,并且创建`HeroDetailComponent`。代码如下:
|
||||||
|
|
||||||
+makeExample('toh-3/ts/app/hero-detail.component.ts', 'v1', 'app/hero-detail.component.ts (initial version)')(format=".")
|
+makeExample('toh-3/ts/app/hero-detail.component.ts', 'v1', 'app/hero-detail.component.ts (initial version)')(format=".")
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
### Naming conventions
|
### Naming conventions
|
||||||
|
|
||||||
### 命名约定
|
### 命名约定
|
||||||
|
|
||||||
We like to identify at a glance which classes are components and which files contain components.
|
We like to identify at a glance which classes are components and which files contain components.
|
||||||
|
|
||||||
我们希望一眼就能看出哪个类是组件,以及哪个文件包含组件。
|
我们希望一眼就能看出哪个类是组件,以及哪个文件包含组件。
|
||||||
@ -128,9 +140,12 @@ code-example(language="bash").
|
|||||||
When we finish here, we'll import it into `AppComponent` and create a corresponding `<my-hero-detail>` element.
|
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
|
:marked
|
||||||
#### Hero Detail Template
|
#### Hero Detail Template
|
||||||
|
|
||||||
#### 英雄详情模板
|
#### 英雄详情模板
|
||||||
|
|
||||||
At the moment, the *Heroes* and *Hero Detail* views are combined in one template in `AppComponent`.
|
At the moment, the *Heroes* and *Hero Detail* views are combined in one template in `AppComponent`.
|
||||||
Let’s **cut** the *Hero Detail* content from `AppComponent` and **paste** it into the new template property of `HeroDetailComponent`.
|
Let’s **cut** the *Hero Detail* content from `AppComponent` and **paste** it into the new template property of `HeroDetailComponent`.
|
||||||
|
|
||||||
@ -155,11 +170,15 @@ code-example(language="bash").
|
|||||||
现在,我们的英雄详情布局只存在于`HeroDetailComponent`组件中了。
|
现在,我们的英雄详情布局只存在于`HeroDetailComponent`组件中了。
|
||||||
|
|
||||||
#### Add the *hero* property
|
#### Add the *hero* property
|
||||||
|
|
||||||
#### 添加 *hero* 属性
|
#### 添加 *hero* 属性
|
||||||
|
|
||||||
Let’s add that `hero` property we were talking about to the component class.
|
Let’s add that `hero` property we were talking about to the component class.
|
||||||
|
|
||||||
我们这就添加刚刚所说的`hero`属性到组件类中。
|
我们这就添加刚刚所说的`hero`属性到组件类中。
|
||||||
|
|
||||||
+makeExample('toh-3/ts/app/hero-detail.component.ts', 'hero')
|
+makeExample('toh-3/ts/app/hero-detail.component.ts', 'hero')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Uh oh. We declared the `hero` property as type `Hero` but our `Hero` class is over in the `app.component.ts` file.
|
Uh oh. We declared the `hero` property as type `Hero` but our `Hero` class is over in the `app.component.ts` file.
|
||||||
We have two components, each in their own file, that need to reference the `Hero` class.
|
We have two components, each in their own file, that need to reference the `Hero` class.
|
||||||
@ -184,6 +203,7 @@ code-example(language="bash").
|
|||||||
|
|
||||||
:marked
|
:marked
|
||||||
#### The *hero* property is an ***input***
|
#### The *hero* property is an ***input***
|
||||||
|
|
||||||
#### *hero*是一个***输入***属性
|
#### *hero*是一个***输入***属性
|
||||||
|
|
||||||
The `HeroDetailComponent` must be told what hero to display. Who will tell it? The parent `AppComponent`!
|
The `HeroDetailComponent` must be told what hero to display. Who will tell it? The parent `AppComponent`!
|
||||||
@ -201,8 +221,10 @@ code-example(language="bash").
|
|||||||
|
|
||||||
我们马上升级`AppComponent`的模板,以便把该组件的`selectedHero`属性绑定到`HeroDetailComponent`组件的`hero`属性上。
|
我们马上升级`AppComponent`的模板,以便把该组件的`selectedHero`属性绑定到`HeroDetailComponent`组件的`hero`属性上。
|
||||||
绑定看起来*可能*是这样的:
|
绑定看起来*可能*是这样的:
|
||||||
|
|
||||||
code-example(format=".").
|
code-example(format=".").
|
||||||
<my-hero-detail [hero]="selectedHero"></my-hero-detail>
|
<my-hero-detail [hero]="selectedHero"></my-hero-detail>
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Notice that the `hero` property is the ***target*** of a property binding — it's in square brackets to the left of the (=).
|
Notice that the `hero` property is the ***target*** of a property binding — it's in square brackets to the left of the (=).
|
||||||
|
|
||||||
@ -212,6 +234,7 @@ code-example(format=".").
|
|||||||
If we don't, Angular rejects the binding and throws an error.
|
If we don't, Angular rejects the binding and throws an error.
|
||||||
|
|
||||||
Angular希望我们把***目标属性***定义成组件的***输入属性***,否则,Angular会拒绝绑定,并且抛出一个错误。
|
Angular希望我们把***目标属性***定义成组件的***输入属性***,否则,Angular会拒绝绑定,并且抛出一个错误。
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
We explain input properties in more detail [here](../guide/attribute-directives.html#why-input)
|
We explain input properties in more detail [here](../guide/attribute-directives.html#why-input)
|
||||||
@ -219,12 +242,14 @@ code-example(format=".").
|
|||||||
*source* properties do not.
|
*source* properties do not.
|
||||||
|
|
||||||
我们在[这里](../guide/attribute-directives.html#why-input)详细解释了输入属性,以及为什么*目标属性*需要“显式定义”这样的特殊待遇,而*来源属性*却不需要。
|
我们在[这里](../guide/attribute-directives.html#why-input)详细解释了输入属性,以及为什么*目标属性*需要“显式定义”这样的特殊待遇,而*来源属性*却不需要。
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
There are a couple of ways we can declare that `hero` is an *input*.
|
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.
|
We'll do it the way we *prefer*, by annotating the `hero` property with the `@Input` decorator that we imported earlier.
|
||||||
|
|
||||||
我们有几种方式把`hero`声明成*输入属性*。
|
我们有几种方式把`hero`声明成*输入属性*。
|
||||||
这里我们采用*首选*的方式:使用我们前面导入的`@Input`装饰器,为`hero`属性加上注解。
|
这里我们采用*首选*的方式:使用我们前面导入的`@Input`装饰器,为`hero`属性加上注解。
|
||||||
|
|
||||||
+makeExample('toh-3/ts/app/hero-detail.component.ts', 'hero-input')(format='.')
|
+makeExample('toh-3/ts/app/hero-detail.component.ts', 'hero-input')(format='.')
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
@ -233,10 +258,13 @@ code-example(format=".").
|
|||||||
[Attribute Directives](../guide/attribute-directives.html#input) chapter.
|
[Attribute Directives](../guide/attribute-directives.html#input) chapter.
|
||||||
|
|
||||||
要了解`@Input()`装饰器的更多知识,参见[属性型指令](../guide/attribute-directives.html#input)一章。
|
要了解`@Input()`装饰器的更多知识,参见[属性型指令](../guide/attribute-directives.html#input)一章。
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## Refresh the AppComponent
|
## Refresh the AppComponent
|
||||||
|
|
||||||
## 刷新AppComponent
|
## 刷新AppComponent
|
||||||
|
|
||||||
We return to the `AppComponent` and teach it to use the `HeroDetailComponent`.
|
We return to the `AppComponent` and teach it to use the `HeroDetailComponent`.
|
||||||
|
|
||||||
回到`AppComponent`组件,我们要教它使用`HeroDetailComponent`组件。
|
回到`AppComponent`组件,我们要教它使用`HeroDetailComponent`组件。
|
||||||
@ -244,6 +272,7 @@ code-example(format=".").
|
|||||||
We begin by importing the `HeroDetailComponent` so we can refer to it.
|
We begin by importing the `HeroDetailComponent` so we can refer to it.
|
||||||
|
|
||||||
我们先导入`HeroDetailComponent`组件,好让我们可以引用它。
|
我们先导入`HeroDetailComponent`组件,好让我们可以引用它。
|
||||||
|
|
||||||
+makeExample('toh-3/ts/app/app.component.ts', 'hero-detail-import')
|
+makeExample('toh-3/ts/app/app.component.ts', 'hero-detail-import')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
@ -251,18 +280,22 @@ code-example(format=".").
|
|||||||
and add an element tag that represents the `HeroDetailComponent`.
|
and add an element tag that represents the `HeroDetailComponent`.
|
||||||
|
|
||||||
找到我们刚刚从模板中移除*英雄详情*的地方,放上用来表示`HeroDetailComponent`组件的HTML标签。
|
找到我们刚刚从模板中移除*英雄详情*的地方,放上用来表示`HeroDetailComponent`组件的HTML标签。
|
||||||
|
|
||||||
code-example(format=".").
|
code-example(format=".").
|
||||||
<my-hero-detail></my-hero-detail>
|
<my-hero-detail></my-hero-detail>
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
*my-hero-detail* is the name we set as the `selector` in the `HeroDetailComponent` metadata.
|
*my-hero-detail* is the name we set as the `selector` in the `HeroDetailComponent` metadata.
|
||||||
|
|
||||||
*my-hero-detail*是我们在`HeroDetailComponent`元数据中的`selector`属性所指定的名字。
|
*my-hero-detail*是我们在`HeroDetailComponent`元数据中的`selector`属性所指定的名字。
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
The two components won't coordinate until we bind the `selectedHero` property of the `AppComponent`
|
The two components won't coordinate until we bind the `selectedHero` property of the `AppComponent`
|
||||||
to the `HeroDetailComponent` element's `hero` property like this:
|
to the `HeroDetailComponent` element's `hero` property like this:
|
||||||
|
|
||||||
这两个组件目前还不能协同工作,直到我们把`AppComponent`组件的`selectedHero`属性和`HeroDetailComponent`组件的`hero`属性绑定在一起,就像这样:
|
这两个组件目前还不能协同工作,直到我们把`AppComponent`组件的`selectedHero`属性和`HeroDetailComponent`组件的`hero`属性绑定在一起,就像这样:
|
||||||
|
|
||||||
code-example(format=".").
|
code-example(format=".").
|
||||||
<my-hero-detail [hero]="selectedHero"></my-hero-detail>
|
<my-hero-detail [hero]="selectedHero"></my-hero-detail>
|
||||||
:marked
|
:marked
|
||||||
@ -304,11 +337,14 @@ code-example(format=".").
|
|||||||
|
|
||||||
我们要把它列在元数据的`directives`数组中,这样Angular才会知道它。
|
我们要把它列在元数据的`directives`数组中,这样Angular才会知道它。
|
||||||
让我们把这个数组属性加在`@Component`配置对象的底部,紧跟在`template`和`styles`属性之后。
|
让我们把这个数组属性加在`@Component`配置对象的底部,紧跟在`template`和`styles`属性之后。
|
||||||
|
|
||||||
+makeExample('toh-3/ts/app/app.component.ts', 'directives', 'app/app.component.ts (Directives)')
|
+makeExample('toh-3/ts/app/app.component.ts', 'directives', 'app/app.component.ts (Directives)')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
### It works!
|
### It works!
|
||||||
|
|
||||||
### 搞定!
|
### 搞定!
|
||||||
|
|
||||||
When we view our app in the browser we see the list of heroes.
|
When we view our app in the browser we see the list of heroes.
|
||||||
When we select a hero we can see the selected hero’s details.
|
When we select a hero we can see the selected hero’s details.
|
||||||
|
|
||||||
@ -325,7 +361,9 @@ code-example(format=".").
|
|||||||
我们创建了第一个可复用组件!
|
我们创建了第一个可复用组件!
|
||||||
|
|
||||||
### Reviewing the App Structure
|
### Reviewing the App Structure
|
||||||
|
|
||||||
### 回顾应用结构
|
### 回顾应用结构
|
||||||
|
|
||||||
Let’s verify that we have the following structure after all of our good refactoring in this chapter:
|
Let’s verify that we have the following structure after all of our good refactoring in this chapter:
|
||||||
|
|
||||||
来验证下吧,在本章中,经过这些漂亮的重构,我们应该得到了下列结构:
|
来验证下吧,在本章中,经过这些漂亮的重构,我们应该得到了下列结构:
|
||||||
@ -345,6 +383,7 @@ code-example(format=".").
|
|||||||
.file package.json
|
.file package.json
|
||||||
.file tsconfig.json
|
.file tsconfig.json
|
||||||
.file typings.json
|
.file typings.json
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Here are the code files we discussed in this chapter.
|
Here are the code files we discussed in this chapter.
|
||||||
|
|
||||||
@ -363,18 +402,27 @@ code-example(format=".").
|
|||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## The Road We’ve Travelled
|
## The Road We’ve Travelled
|
||||||
|
|
||||||
## 走过的路
|
## 走过的路
|
||||||
|
|
||||||
Let’s take stock of what we’ve built.
|
Let’s take stock of what we’ve built.
|
||||||
|
|
||||||
来盘点一下我们已经构建完的部分。
|
来盘点一下我们已经构建完的部分。
|
||||||
|
|
||||||
* We created a reusable component
|
* We created a reusable component
|
||||||
|
|
||||||
* 我们创建了一个可复用组件
|
* 我们创建了一个可复用组件
|
||||||
|
|
||||||
* We learned how to make a component accept input
|
* We learned how to make a component accept input
|
||||||
|
|
||||||
* 我们学会了如何让一个组件接收输入
|
* 我们学会了如何让一个组件接收输入
|
||||||
|
|
||||||
* We learned to bind a parent component to a child component.
|
* We learned to bind a parent component to a child component.
|
||||||
|
|
||||||
* 我们学会了把父组件绑定到子组件。
|
* 我们学会了把父组件绑定到子组件。
|
||||||
|
|
||||||
* We learned to declare the application directives we need in a `directives` array.
|
* We learned to declare the application directives we need in a `directives` array.
|
||||||
|
|
||||||
* 我们学会了在`directives`中定义应用所需的指令。
|
* 我们学会了在`directives`中定义应用所需的指令。
|
||||||
|
|
||||||
p Run the #[+liveExampleLink2('', 'toh-3')] for this part.
|
p Run the #[+liveExampleLink2('', 'toh-3')] for this part.
|
||||||
@ -384,7 +432,9 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-3')]。
|
|||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## The Road Ahead
|
## The Road Ahead
|
||||||
|
|
||||||
## 前方的路
|
## 前方的路
|
||||||
|
|
||||||
Our Tour of Heroes has become more reusable with shared components.
|
Our Tour of Heroes has become more reusable with shared components.
|
||||||
|
|
||||||
通过抽取共享组件,我们的《英雄指南》变得更有复用性了。
|
通过抽取共享组件,我们的《英雄指南》变得更有复用性了。
|
||||||
|
@ -2,7 +2,9 @@ include ../_util-fns
|
|||||||
|
|
||||||
:marked
|
:marked
|
||||||
# Services
|
# Services
|
||||||
|
|
||||||
# 服务
|
# 服务
|
||||||
|
|
||||||
The Tour of Heroes is evolving and we anticipate adding more components in the near future.
|
The Tour of Heroes is evolving and we anticipate adding more components in the near future.
|
||||||
|
|
||||||
《英雄指南》继续前行。接下来,我们准备添加更多的组件。
|
《英雄指南》继续前行。接下来,我们准备添加更多的组件。
|
||||||
@ -33,7 +35,9 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-4')]。
|
|||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## Where We Left Off
|
## Where We Left Off
|
||||||
|
|
||||||
## 我们在哪儿
|
## 我们在哪儿
|
||||||
|
|
||||||
Before we continue with our Tour of Heroes, let’s verify we have the following structure.
|
Before we continue with our Tour of Heroes, let’s verify we have the following structure.
|
||||||
If not, we’ll need to go back and follow the previous chapters.
|
If not, we’ll need to go back and follow the previous chapters.
|
||||||
|
|
||||||
@ -74,7 +78,9 @@ code-example(language="bash").
|
|||||||
当我们继续构建《英雄指南》时,应用会自动运行和更新。
|
当我们继续构建《英雄指南》时,应用会自动运行和更新。
|
||||||
|
|
||||||
## Creating a Hero Service
|
## Creating a Hero Service
|
||||||
|
|
||||||
## 创建英雄服务
|
## 创建英雄服务
|
||||||
|
|
||||||
Our stakeholders have shared their larger vision for our app.
|
Our stakeholders have shared their larger vision for our app.
|
||||||
They tell us they want to show the heroes in various ways on different pages.
|
They tell us they want to show the heroes in various ways on different pages.
|
||||||
We already can select a hero from a list.
|
We already can select a hero from a list.
|
||||||
@ -101,10 +107,13 @@ code-example(language="bash").
|
|||||||
我们可以把提供英雄数据的任务重构为一个单独的服务,它将提供英雄数据,并且把这个服务在所有需要英雄数据的组件之间共享。
|
我们可以把提供英雄数据的任务重构为一个单独的服务,它将提供英雄数据,并且把这个服务在所有需要英雄数据的组件之间共享。
|
||||||
|
|
||||||
### Create the HeroService
|
### Create the HeroService
|
||||||
|
|
||||||
### 创建HeroService
|
### 创建HeroService
|
||||||
|
|
||||||
Create a file in the `app` folder called `hero.service.ts`.
|
Create a file in the `app` folder called `hero.service.ts`.
|
||||||
|
|
||||||
在`app`目录下创建一个名叫`hero.service.ts`的文件。
|
在`app`目录下创建一个名叫`hero.service.ts`的文件。
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
We've adopted a convention in which we spell the name of a service in lowercase followed by `.service`.
|
We've adopted a convention in which we spell the name of a service in lowercase followed by `.service`.
|
||||||
@ -114,6 +123,7 @@ code-example(language="bash").
|
|||||||
我们遵循的文件命名约定是:服务名称的小写形式(基本名),加上`.service`后缀。
|
我们遵循的文件命名约定是:服务名称的小写形式(基本名),加上`.service`后缀。
|
||||||
如果服务名称包含多个单词,我们就把基本名部分写成中线形式(dash-case,也被称作烤串形式kebab-case)。
|
如果服务名称包含多个单词,我们就把基本名部分写成中线形式(dash-case,也被称作烤串形式kebab-case)。
|
||||||
比如,`SpecialSuperHeroService`服务应该被定义在`special-super-hero.service.ts`文件中。
|
比如,`SpecialSuperHeroService`服务应该被定义在`special-super-hero.service.ts`文件中。
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
We name the class `HeroService` and export it for others to import.
|
We name the class `HeroService` and export it for others to import.
|
||||||
|
|
||||||
@ -123,15 +133,19 @@ code-example(language="bash").
|
|||||||
|
|
||||||
:marked
|
:marked
|
||||||
### Injectable Services
|
### Injectable Services
|
||||||
|
|
||||||
### 可注入的服务
|
### 可注入的服务
|
||||||
|
|
||||||
Notice that we imported the Angular `Injectable` function and applied that function as an `@Injectable()` decorator.
|
Notice that we imported the Angular `Injectable` function and applied that function as an `@Injectable()` decorator.
|
||||||
|
|
||||||
注意,我们引入了Angular的`Injectable`函数,并通过`@Injectable()`装饰器使用这个函数。
|
注意,我们引入了Angular的`Injectable`函数,并通过`@Injectable()`装饰器使用这个函数。
|
||||||
|
|
||||||
.callout.is-helpful
|
.callout.is-helpful
|
||||||
:marked
|
:marked
|
||||||
**Don't forget the parentheses!** Neglecting them leads to an error that's difficult to diagnose.
|
**Don't forget the parentheses!** Neglecting them leads to an error that's difficult to diagnose.
|
||||||
|
|
||||||
**不要忘了写圆括号!**如果忘了写,就会导致一个很难诊断的错误。
|
**不要忘了写圆括号!**如果忘了写,就会导致一个很难诊断的错误。
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
TypeScript sees the `@Injectable()` decorator and emits metadata about our service,
|
TypeScript sees the `@Injectable()` decorator and emits metadata about our service,
|
||||||
metadata that Angular may need to inject other dependencies into this service.
|
metadata that Angular may need to inject other dependencies into this service.
|
||||||
@ -146,12 +160,15 @@ code-example(language="bash").
|
|||||||
|
|
||||||
:marked
|
:marked
|
||||||
### Getting Heroes
|
### Getting Heroes
|
||||||
|
|
||||||
### 获取英雄
|
### 获取英雄
|
||||||
|
|
||||||
Add a `getHeroes` method stub.
|
Add a `getHeroes` method stub.
|
||||||
|
|
||||||
添加一个名叫`getHeros`的桩方法。
|
添加一个名叫`getHeros`的桩方法。
|
||||||
|
|
||||||
+makeExample('toh-4/ts/app/hero.service.1.ts', 'getHeroes-stub', 'app/hero.service.ts (getHeroes stub)')(format=".")
|
+makeExample('toh-4/ts/app/hero.service.1.ts', 'getHeroes-stub', 'app/hero.service.ts (getHeroes stub)')(format=".")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
We're holding back on the implementation for a moment to make an important point.
|
We're holding back on the implementation for a moment to make an important point.
|
||||||
|
|
||||||
@ -174,7 +191,9 @@ code-example(language="bash").
|
|||||||
这下子,我们可以随时改变数据访问的实现方式了。
|
这下子,我们可以随时改变数据访问的实现方式了。
|
||||||
|
|
||||||
### Mock Heroes
|
### Mock Heroes
|
||||||
|
|
||||||
### Mock英雄数据
|
### Mock英雄数据
|
||||||
|
|
||||||
We already have mock `Hero` data sitting in the `AppComponent`. It doesn't belong there. It doesn't belong *here* either.
|
We already have mock `Hero` data sitting in the `AppComponent`. It doesn't belong there. It doesn't belong *here* either.
|
||||||
We'll move the mock data to its own file.
|
We'll move the mock data to its own file.
|
||||||
|
|
||||||
@ -187,6 +206,7 @@ code-example(language="bash").
|
|||||||
我们还要把`import {Hero}...`语句拷贝过来,因为我们的英雄数组用到了`Hero`类。
|
我们还要把`import {Hero}...`语句拷贝过来,因为我们的英雄数组用到了`Hero`类。
|
||||||
|
|
||||||
+makeExample('toh-4/ts/app/mock-heroes.ts', null, 'app/mock-heroes.ts')
|
+makeExample('toh-4/ts/app/mock-heroes.ts', null, 'app/mock-heroes.ts')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
We export the `HEROES` constant so we can import it elsewhere — such as our `HeroService`.
|
We export the `HEROES` constant so we can import it elsewhere — such as our `HeroService`.
|
||||||
|
|
||||||
@ -198,9 +218,12 @@ code-example(language="bash").
|
|||||||
同时,回到刚剪切出`HEROES`数组的`app.component.ts`文件,我们留下了一个尚未初始化的`heroes`属性:
|
同时,回到刚剪切出`HEROES`数组的`app.component.ts`文件,我们留下了一个尚未初始化的`heroes`属性:
|
||||||
|
|
||||||
+makeExample('toh-4/ts/app/app.component.1.ts', 'heroes-prop', 'app/app.component.ts (heroes property)')(format=".")
|
+makeExample('toh-4/ts/app/app.component.1.ts', 'heroes-prop', 'app/app.component.ts (heroes property)')(format=".")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
### Return Mocked Heroes
|
### Return Mocked Heroes
|
||||||
|
|
||||||
### 返回模拟的英雄数据
|
### 返回模拟的英雄数据
|
||||||
|
|
||||||
Back in the `HeroService` we import the mock `HEROES` and return it from the `getHeroes` method.
|
Back in the `HeroService` we import the mock `HEROES` and return it from the `getHeroes` method.
|
||||||
Our `HeroService` looks like this:
|
Our `HeroService` looks like this:
|
||||||
|
|
||||||
@ -208,9 +231,12 @@ code-example(language="bash").
|
|||||||
我们的`HeroService`服务现在看起来是这样:
|
我们的`HeroService`服务现在看起来是这样:
|
||||||
|
|
||||||
+makeExample('toh-4/ts/app/hero.service.1.ts', null, 'app/hero.service.ts')(format=".")
|
+makeExample('toh-4/ts/app/hero.service.1.ts', null, 'app/hero.service.ts')(format=".")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
### Use the Hero Service
|
### Use the Hero Service
|
||||||
|
|
||||||
### 使用HeroService服务
|
### 使用HeroService服务
|
||||||
|
|
||||||
We're ready to use the `HeroService` in other components starting with our `AppComponent`.
|
We're ready to use the `HeroService` in other components starting with our `AppComponent`.
|
||||||
|
|
||||||
我们已经在包括`AppComponent`在内的多个组件中使用了`HeroService`服务。
|
我们已经在包括`AppComponent`在内的多个组件中使用了`HeroService`服务。
|
||||||
@ -220,6 +246,7 @@ code-example(language="bash").
|
|||||||
通常,我们会从导入要用的东西开始,比如`HeroService`。
|
通常,我们会从导入要用的东西开始,比如`HeroService`。
|
||||||
|
|
||||||
+makeExcerpt('toh-4/ts/app/app.component.ts', 'hero-service-import')
|
+makeExcerpt('toh-4/ts/app/app.component.ts', 'hero-service-import')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Importing the service allows us to *reference* it in our code.
|
Importing the service allows us to *reference* it in our code.
|
||||||
How should the `AppComponent` acquire a runtime concrete `HeroService` instance?
|
How should the `AppComponent` acquire a runtime concrete `HeroService` instance?
|
||||||
@ -236,6 +263,7 @@ code-example(language="bash").
|
|||||||
固然,我们可以使用`new`关键字来创建`HeroService`的实例,就像这样:
|
固然,我们可以使用`new`关键字来创建`HeroService`的实例,就像这样:
|
||||||
|
|
||||||
+makeExample('toh-4/ts/app/app.component.1.ts', 'new-service')(format=".")
|
+makeExample('toh-4/ts/app/app.component.1.ts', 'new-service')(format=".")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
That's a bad idea for several reasons including
|
That's a bad idea for several reasons including
|
||||||
|
|
||||||
@ -269,6 +297,7 @@ code-example(language="bash").
|
|||||||
比如,能离线操作吗?能在测试时使用不同的模拟版本吗?这可不容易。
|
比如,能离线操作吗?能在测试时使用不同的模拟版本吗?这可不容易。
|
||||||
|
|
||||||
* What if ... what if ... Hey, we've got work to do!*
|
* What if ... what if ... Hey, we've got work to do!*
|
||||||
|
|
||||||
* 如果……如果……嘿!这下我们可有得忙了!
|
* 如果……如果……嘿!这下我们可有得忙了!
|
||||||
|
|
||||||
We get it. Really we do.
|
We get it. Really we do.
|
||||||
@ -277,6 +306,7 @@ code-example(language="bash").
|
|||||||
有办法了,真的!这个办法真是简单得不可思议,它能解决这些问题,你就再也没有犯错误的借口了。
|
有办法了,真的!这个办法真是简单得不可思议,它能解决这些问题,你就再也没有犯错误的借口了。
|
||||||
|
|
||||||
### Inject the *HeroService*
|
### Inject the *HeroService*
|
||||||
|
|
||||||
### 注入 *HeroService*
|
### 注入 *HeroService*
|
||||||
|
|
||||||
Two lines replace the one line that created with *new*:
|
Two lines replace the one line that created with *new*:
|
||||||
@ -301,6 +331,7 @@ code-example(language="bash").
|
|||||||
defines a private `heroService` property and identifies it as a `HeroService` injection site.
|
defines a private `heroService` property and identifies it as a `HeroService` injection site.
|
||||||
|
|
||||||
构造函数自己什么也不用做,它在参数中定义了一个私有的`heroService`属性,并把它标记为注入`HeroService`的靶点。
|
构造函数自己什么也不用做,它在参数中定义了一个私有的`heroService`属性,并把它标记为注入`HeroService`的靶点。
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Now Angular will know to supply an instance of the `HeroService` when it creates a new `AppComponent`.
|
Now Angular will know to supply an instance of the `HeroService` when it creates a new `AppComponent`.
|
||||||
|
|
||||||
@ -322,6 +353,7 @@ code-example(language="bash").
|
|||||||
code-example(format="nocode").
|
code-example(format="nocode").
|
||||||
EXCEPTION: No provider for HeroService! (AppComponent -> HeroService)
|
EXCEPTION: No provider for HeroService! (AppComponent -> HeroService)
|
||||||
(异常:没有HeroService的供应商!(AppComponent -> HeroService))
|
(异常:没有HeroService的供应商!(AppComponent -> HeroService))
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
We have to teach the *injector* how to make a `HeroService` by registering a `HeroService` **provider**.
|
We have to teach the *injector* how to make a `HeroService` by registering a `HeroService` **provider**.
|
||||||
Do that by adding the following `providers` array property to the bottom of the component metadata
|
Do that by adding the following `providers` array property to the bottom of the component metadata
|
||||||
@ -331,16 +363,20 @@ code-example(format="nocode").
|
|||||||
要做到这一点,我们应该在`@Component`组件的元数据底部添加`providers`数组属性如下:
|
要做到这一点,我们应该在`@Component`组件的元数据底部添加`providers`数组属性如下:
|
||||||
|
|
||||||
+makeExcerpt('toh-4/ts/app/app.component.1.ts', 'providers')
|
+makeExcerpt('toh-4/ts/app/app.component.1.ts', 'providers')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
The `providers` array tells Angular to create a fresh instance of the `HeroService` when it creates a new `AppComponent`.
|
The `providers` array tells Angular to create a fresh instance of the `HeroService` when it creates a new `AppComponent`.
|
||||||
The `AppComponent` can use that service to get heroes and so can every child component of its component tree.
|
The `AppComponent` can use that service to get heroes and so can every child component of its component tree.
|
||||||
|
|
||||||
`providers`数组告诉Angular,当它创建新的`AppComponent`组件时,也要创建一个`HeroService`的新实例。
|
`providers`数组告诉Angular,当它创建新的`AppComponent`组件时,也要创建一个`HeroService`的新实例。
|
||||||
`AppComponent`会使用那个服务来获取影响列表,在它组件树中的每一个子组件也同样如此。
|
`AppComponent`会使用那个服务来获取影响列表,在它组件树中的每一个子组件也同样如此。
|
||||||
|
|
||||||
a#child-component
|
a#child-component
|
||||||
:marked
|
:marked
|
||||||
### *getHeroes* in the *AppComponent*
|
### *getHeroes* in the *AppComponent*
|
||||||
|
|
||||||
### *AppComponent* 中的 *getHeroes*
|
### *AppComponent* 中的 *getHeroes*
|
||||||
|
|
||||||
We've got the service in a `heroService` private variable. Let's use it.
|
We've got the service in a `heroService` private variable. Let's use it.
|
||||||
|
|
||||||
我们已经获得了此服务,并把它存入了私有变量`heroService`中。我们这就开始使用它。
|
我们已经获得了此服务,并把它存入了私有变量`heroService`中。我们这就开始使用它。
|
||||||
@ -348,7 +384,9 @@ a#child-component
|
|||||||
We pause to think. We can call the service and get the data in one line.
|
We pause to think. We can call the service and get the data in one line.
|
||||||
|
|
||||||
停下来想一想。我们可以在同一行内调用此服务并获得数据。
|
停下来想一想。我们可以在同一行内调用此服务并获得数据。
|
||||||
|
|
||||||
+makeExample('toh-4/ts/app/app.component.1.ts', 'get-heroes')(format=".")
|
+makeExample('toh-4/ts/app/app.component.1.ts', 'get-heroes')(format=".")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
We don't really need a dedicated method to wrap one line. We write it anyway:
|
We don't really need a dedicated method to wrap one line. We write it anyway:
|
||||||
|
|
||||||
@ -359,7 +397,9 @@ a#child-component
|
|||||||
<a id="oninit"></a>
|
<a id="oninit"></a>
|
||||||
:marked
|
:marked
|
||||||
### The *ngOnInit* Lifecycle Hook
|
### The *ngOnInit* Lifecycle Hook
|
||||||
|
|
||||||
### *ngOnInit* 生命周期钩子
|
### *ngOnInit* 生命周期钩子
|
||||||
|
|
||||||
`AppComponent` should fetch and display heroes without a fuss.
|
`AppComponent` should fetch and display heroes without a fuss.
|
||||||
Where do we call the `getHeroes` method? In a constructor? We do *not*!
|
Where do we call the `getHeroes` method? In a constructor? We do *not*!
|
||||||
|
|
||||||
@ -392,17 +432,20 @@ a#child-component
|
|||||||
Each interface has a single method. When the component implements that method, Angular calls it at the appropriate time.
|
Each interface has a single method. When the component implements that method, Angular calls it at the appropriate time.
|
||||||
|
|
||||||
每个接口都有唯一的一个方法。只要组件实现了这个方法,Angular就会在合适的时机调用它。
|
每个接口都有唯一的一个方法。只要组件实现了这个方法,Angular就会在合适的时机调用它。
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
Learn more about lifecycle hooks in the [Lifecycle Hooks](../guide/lifecycle-hooks.html) chapter.
|
Learn more about lifecycle hooks in the [Lifecycle Hooks](../guide/lifecycle-hooks.html) chapter.
|
||||||
|
|
||||||
要了解关于生命周期钩子的更多知识,请参见 [生命周期钩子](../guide/lifecycle-hooks.html) 一章。
|
要了解关于生命周期钩子的更多知识,请参见 [生命周期钩子](../guide/lifecycle-hooks.html) 一章。
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Here's the essential outline for the `OnInit` interface:
|
Here's the essential outline for the `OnInit` interface:
|
||||||
|
|
||||||
这是`OnInit`接口的基本轮廓:
|
这是`OnInit`接口的基本轮廓:
|
||||||
|
|
||||||
+makeExample('toh-4/ts/app/app.component.1.ts', 'on-init', 'app/app.component.ts (ngOnInit stub)')(format=".")
|
+makeExample('toh-4/ts/app/app.component.1.ts', 'on-init', 'app/app.component.ts (ngOnInit stub)')(format=".")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
We write an `ngOnInit` method with our initialization logic inside and leave it to Angular to call it
|
We write an `ngOnInit` method with our initialization logic inside and leave it to Angular to call it
|
||||||
at the right time. In our case, we initialize by calling `getHeroes`.
|
at the right time. In our case, we initialize by calling `getHeroes`.
|
||||||
@ -410,6 +453,7 @@ a#child-component
|
|||||||
我们写下带有初始化逻辑的`ngOnInit`方法,然后留给Angular,供其在正确的时机调用。在这个例子中,我们通过调用`getHeroes`来完成初始化。
|
我们写下带有初始化逻辑的`ngOnInit`方法,然后留给Angular,供其在正确的时机调用。在这个例子中,我们通过调用`getHeroes`来完成初始化。
|
||||||
|
|
||||||
+makeExcerpt('toh-4/ts/app/app.component.1.ts', 'ng-on-init')
|
+makeExcerpt('toh-4/ts/app/app.component.1.ts', 'ng-on-init')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Our application should be running as expected, showing a list of heroes and a hero detail view
|
Our application should be running as expected, showing a list of heroes and a hero detail view
|
||||||
when we click on a hero name.
|
when we click on a hero name.
|
||||||
@ -432,6 +476,7 @@ a#child-component
|
|||||||
我们的`HeroService`立即返回一个模拟的英雄列表,它的`getHeroes`函数签名是同步的。
|
我们的`HeroService`立即返回一个模拟的英雄列表,它的`getHeroes`函数签名是同步的。
|
||||||
|
|
||||||
+makeExample('toh-4/ts/app/app.component.1.ts', 'get-heroes')(format=".")
|
+makeExample('toh-4/ts/app/app.component.1.ts', 'get-heroes')(format=".")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Ask for heroes and they are there in the returned result.
|
Ask for heroes and they are there in the returned result.
|
||||||
|
|
||||||
@ -465,17 +510,20 @@ a#child-component
|
|||||||
**承诺** 就是 …… 好吧,它就是一个承诺 —— 在有了结果时,它承诺会回调我们。
|
**承诺** 就是 …… 好吧,它就是一个承诺 —— 在有了结果时,它承诺会回调我们。
|
||||||
我们请求一个异步服务去做点什么,然后给它一个回调函数。
|
我们请求一个异步服务去做点什么,然后给它一个回调函数。
|
||||||
它会去做(无论用哪种方式),一旦完成,它就会调用我们的回调函数,并通过参数把工作成果或者错误信息传给我们。
|
它会去做(无论用哪种方式),一旦完成,它就会调用我们的回调函数,并通过参数把工作成果或者错误信息传给我们。
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
We are simplifying. Learn about ES2015 Promises [here](http://exploringjs.com/es6/ch_promises.html) and elsewhere on the web.
|
We are simplifying. Learn about ES2015 Promises [here](http://exploringjs.com/es6/ch_promises.html) and elsewhere on the web.
|
||||||
|
|
||||||
这里只是粗浅的说说,要了解更多,请参见[这里](http://exploringjs.com/es6/ch_promises.html)或在Web上搜索其它学习资源。
|
这里只是粗浅的说说,要了解更多,请参见[这里](http://exploringjs.com/es6/ch_promises.html)或在Web上搜索其它学习资源。
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Update the `HeroService` with this !{_Promise}-returning `getHeroes` method:
|
Update the `HeroService` with this !{_Promise}-returning `getHeroes` method:
|
||||||
|
|
||||||
把`HeroService`的`getHeroes`方法改写为返回承诺的形式:
|
把`HeroService`的`getHeroes`方法改写为返回承诺的形式:
|
||||||
|
|
||||||
+makeExample('toh-4/ts/app/hero.service.ts', 'get-heroes', 'app/hero.service.ts (excerpt)')(format=".")
|
+makeExample('toh-4/ts/app/hero.service.ts', 'get-heroes', 'app/hero.service.ts (excerpt)')(format=".")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
We're still mocking the data. We're simulating the behavior of an ultra-fast, zero-latency server,
|
We're still mocking the data. We're simulating the behavior of an ultra-fast, zero-latency server,
|
||||||
by returning an **immediately resolved !{_Promise}** with our mock heroes as the result.
|
by returning an **immediately resolved !{_Promise}** with our mock heroes as the result.
|
||||||
@ -491,6 +539,7 @@ a#child-component
|
|||||||
回到`AppComponent`和它的`getHeroes`方法,我们看到它看起来还是这样的:
|
回到`AppComponent`和它的`getHeroes`方法,我们看到它看起来还是这样的:
|
||||||
|
|
||||||
+makeExample('toh-4/ts/app/app.component.1.ts', 'getHeroes', 'app/app.component.ts (getHeroes - old)')(format=".")
|
+makeExample('toh-4/ts/app/app.component.1.ts', 'getHeroes', 'app/app.component.ts (getHeroes - old)')(format=".")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
As a result of our change to `HeroService`, we're now setting `this.heroes` to a !{_Promise} rather than an array of heroes.
|
As a result of our change to `HeroService`, we're now setting `this.heroes` to a !{_Promise} rather than an array of heroes.
|
||||||
|
|
||||||
@ -507,6 +556,7 @@ a#child-component
|
|||||||
我们把回调函数作为参数传给承诺对象的**then**函数:
|
我们把回调函数作为参数传给承诺对象的**then**函数:
|
||||||
|
|
||||||
+makeExample('toh-4/ts/app/app.component.ts', 'get-heroes', 'app/app.component.ts (getHeroes - revised)')(format=".")
|
+makeExample('toh-4/ts/app/app.component.ts', 'get-heroes', 'app/app.component.ts (getHeroes - revised)')(format=".")
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
The [ES2015 arrow function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
|
The [ES2015 arrow function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
|
||||||
@ -514,6 +564,7 @@ a#child-component
|
|||||||
|
|
||||||
回调中所用的[ES2015箭头函数](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
|
回调中所用的[ES2015箭头函数](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
|
||||||
能比等价的函数表达式更加快速、优雅的处理*this*指针。
|
能比等价的函数表达式更加快速、优雅的处理*this*指针。
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Our callback sets the component's `heroes` property to the array of heroes returned by the service. That's all there is to it!
|
Our callback sets the component's `heroes` property to the array of heroes returned by the service. That's all there is to it!
|
||||||
|
|
||||||
@ -523,14 +574,18 @@ a#child-component
|
|||||||
responding to a name selection with a detail view.
|
responding to a name selection with a detail view.
|
||||||
|
|
||||||
我们的程序仍在运行,仍在显示英雄列表,在选择英雄时,仍然会把他/她显示在详情页面中。
|
我们的程序仍在运行,仍在显示英雄列表,在选择英雄时,仍然会把他/她显示在详情页面中。
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
Checkout the "[Take it slow](#slow)" appendix to see what the app might be like with a poor connection.
|
Checkout the "[Take it slow](#slow)" appendix to see what the app might be like with a poor connection.
|
||||||
|
|
||||||
查看附件中的“[慢一点儿](#slow)”一节,来了解在较差的网络连接中这个应用会是什么样的。
|
查看附件中的“[慢一点儿](#slow)”一节,来了解在较差的网络连接中这个应用会是什么样的。
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
### Review the App Structure
|
### Review the App Structure
|
||||||
|
|
||||||
### 回顾本应用的结构
|
### 回顾本应用的结构
|
||||||
|
|
||||||
Let’s verify that we have the following structure after all of our good refactoring in this chapter:
|
Let’s verify that we have the following structure after all of our good refactoring in this chapter:
|
||||||
|
|
||||||
再检查下,经历了本章的所有重构之后,我们应该有了下列文件结构:
|
再检查下,经历了本章的所有重构之后,我们应该有了下列文件结构:
|
||||||
@ -570,7 +625,9 @@ a#child-component
|
|||||||
`)
|
`)
|
||||||
:marked
|
:marked
|
||||||
## The Road We’ve Travelled
|
## The Road We’ve Travelled
|
||||||
|
|
||||||
## 走过的路
|
## 走过的路
|
||||||
|
|
||||||
Let’s take stock of what we’ve built.
|
Let’s take stock of what we’ve built.
|
||||||
|
|
||||||
来盘点一下我们已经构建完的部分。
|
来盘点一下我们已经构建完的部分。
|
||||||
@ -601,7 +658,9 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-4')]。
|
|||||||
|
|
||||||
:marked
|
:marked
|
||||||
### The Road Ahead
|
### The Road Ahead
|
||||||
|
|
||||||
### 前方的路
|
### 前方的路
|
||||||
|
|
||||||
Our Tour of Heroes has become more reusable using shared components and services.
|
Our Tour of Heroes has become more reusable using shared components and services.
|
||||||
We want to create a dashboard, add menu links that route between the views, and format data in a template.
|
We want to create a dashboard, add menu links that route between the views, and format data in a template.
|
||||||
As our app evolves, we’ll learn how to design it to make it easier to grow and maintain.
|
As our app evolves, we’ll learn how to design it to make it easier to grow and maintain.
|
||||||
@ -618,6 +677,7 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-4')]。
|
|||||||
<a id="slow"></a>
|
<a id="slow"></a>
|
||||||
:marked
|
:marked
|
||||||
### Appendix: Take it slow
|
### Appendix: Take it slow
|
||||||
|
|
||||||
### 附件:慢一点儿
|
### 附件:慢一点儿
|
||||||
|
|
||||||
We can simulate a slow connection.
|
We can simulate a slow connection.
|
||||||
@ -629,6 +689,7 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-4')]。
|
|||||||
导入`Hero`类,并且在`HeroService`中添加如下的`getHeroesSlowly`方法:
|
导入`Hero`类,并且在`HeroService`中添加如下的`getHeroesSlowly`方法:
|
||||||
|
|
||||||
+makeExample('toh-4/ts/app/hero.service.ts', 'get-heroes-slowly', 'app/hero.service.ts (getHeroesSlowly)')(format=".")
|
+makeExample('toh-4/ts/app/hero.service.ts', 'get-heroes-slowly', 'app/hero.service.ts (getHeroesSlowly)')(format=".")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Like `getHeroes`, it also returns a !{_Promise}.
|
Like `getHeroes`, it also returns a !{_Promise}.
|
||||||
But this !{_Promise} waits 2 seconds before resolving the !{_Promise} with mock heroes.
|
But this !{_Promise} waits 2 seconds before resolving the !{_Promise} with mock heroes.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user