2016-02-06 02:27:06 -05:00
include ../_util-fns
2015-12-23 12:42:57 -05:00
:marked
# Routing Around the App
2016-04-17 11:31:22 -04:00
# 应用中的路由
2015-12-23 12:42:57 -05:00
We received new requirements for our Tour of Heroes application:
2016-04-17 11:31:22 -04:00
我们收到了关于《英雄指南》应用的新需求:
2015-12-23 12:42:57 -05:00
* add a *Dashboard* view.
2016-04-17 11:31:22 -04:00
* 添加一个 *仪表盘* 视图。
2015-12-23 12:42:57 -05:00
* navigate between the *Heroes* and *Dashboard* views.
2016-04-17 11:31:22 -04:00
* 在 *英雄列表* 和 *仪表盘* 视图之间导航。
2015-12-23 12:42:57 -05:00
* clicking on a hero in either view navigates to a detail view of the selected hero.
2016-04-17 11:31:22 -04:00
* 无论在哪个视图中点击一个英雄,都会导航到该英雄的详情页。
2015-12-23 12:42:57 -05:00
* clicking a *deep link* in an email opens the detail view for a particular hero;
2016-04-17 11:31:22 -04:00
* 在邮件中点击一个 *深链接* ,会直接打开一个特定英雄的详情视图。
2015-12-23 12:42:57 -05:00
When we’ re done, users will be able to navigate the app like this:
2016-04-17 11:31:22 -04:00
完成时,用户就能像这样浏览一个应用:
2015-12-23 12:42:57 -05:00
figure.image-display
2016-04-17 11:31:22 -04:00
img(src='/resources/images/devguide/toh/nav-diagram.png' alt="查看导航")
2015-12-23 12:42:57 -05:00
:marked
We'll add Angular’ s *Component Router* to our app to satisfy these requirements.
2016-04-17 11:31:22 -04:00
我们将把Angular *组件路由器* 加入应用中,以满足这些需求。(译注:硬件的路由器是用来让你找到另一台机器的,而这里的路由器用于帮你找到一个组件)
2015-12-23 12:42:57 -05:00
.l-sub-section
:marked
The [Routing and Navigation](../guide/router.html) chapter covers the router in more detail
than we will in this tour.
2016-04-17 11:31:22 -04:00
[路由与导航](../guide/router.html)一章覆盖了比该教程中更详细的路由知识。
2015-12-23 12:42:57 -05:00
:marked
[Run the live example](/resources/live-examples/toh-5/ts/plnkr.html).
2016-04-17 11:31:22 -04:00
[运行鲜活范例](/resources/live-examples/toh-5/ts/plnkr.html).
2015-12-23 12:42:57 -05:00
.l-sub-section
2016-04-17 11:31:22 -04:00
img(src='/resources/images/devguide/plunker-separate-window-button.png' alt="弹出窗口" align="right" style="margin-right:-20px")
2015-12-23 12:42:57 -05:00
:marked
2016-02-28 16:55:37 -05:00
To see the URL changes in the browser address bar,
pop out the preview window by clicking the blue 'X' button in the upper right corner:
2015-12-23 12:42:57 -05:00
2016-04-17 11:31:22 -04:00
注意看浏览器地址栏中的URL变化, 点击右上角的蓝色'X'按钮,弹出预览窗口。
2015-12-23 12:42:57 -05:00
.l-main-section
:marked
## Where We Left Off
2016-04-17 11:31:22 -04:00
## 我们在哪儿
2015-12-23 12:42:57 -05:00
Before we continue with our Tour of Heroes, let’ s verify that we have the following structure after adding our hero service
and hero detail component. If not, we’ ll need to go back and follow the previous chapters.
2016-04-17 11:31:22 -04:00
在继续《英雄指南》之前,我们先检查一下,在添加了英雄服务和英雄详情组件之后,你是否已经有了如下目录结构。如果没有,你得先回上一章,再照做一次。
2015-12-23 12:42:57 -05:00
.filetree
.file angular2-tour-of-heroes
.children
.file app
.children
.file app.component.ts
.file hero.ts
.file hero-detail.component.ts
.file hero.service.ts
.file main.ts
.file mock-heroes.ts
2016-02-11 18:08:06 -05:00
.file node_modules ...
.file typings ...
2015-12-23 12:42:57 -05:00
.file index.html
.file package.json
.file tsconfig.json
2016-02-11 18:08:06 -05:00
.file typings.json
2015-12-23 12:42:57 -05:00
:marked
### Keep the app transpiling and running
2016-04-17 11:31:22 -04:00
### 让应用代码保持转译和运行
2015-12-23 12:42:57 -05:00
Open a terminal/console window and enter the following command to
start the TypeScript compiler, start the server, and watch for changes:
2016-04-17 11:31:22 -04:00
打开terminal/console窗口, 运行下列命令启动TypeScript编译器, 它会监视文件变更, 并启动开发服务器:
2015-12-23 12:42:57 -05:00
code-example(format="." language="bash").
npm start
:marked
The application runs and updates automatically as we continue to build the Tour of Heroes.
2016-04-17 11:31:22 -04:00
我们继续构建《英雄指南》,应用也会保持运行并自动更新。
2015-12-23 12:42:57 -05:00
## Action plan
2016-04-17 11:31:22 -04:00
## 行动计划
2015-12-23 12:42:57 -05:00
Here's our plan
2016-04-17 11:31:22 -04:00
下面是我们的计划
2015-12-23 12:42:57 -05:00
* turn `AppComponent` into an application shell that only handles navigation.
2016-04-17 11:31:22 -04:00
* 把`AppComponent`变成应用的一个“壳层”,它只处理导航。
2015-12-23 12:42:57 -05:00
* relocate the *Heroes* concerns within the current `AppComponent` to a separate `HeroesComponent`
2016-04-17 11:31:22 -04:00
* 把现在`AppComponent`所关注的这些事移到一个独立的`HeroesComponent`中
2015-12-23 12:42:57 -05:00
* add routing
2016-04-17 11:31:22 -04:00
* 添加路由
2015-12-23 12:42:57 -05:00
* create a new `DashboardComponent`
2016-04-17 11:31:22 -04:00
* 添加一个新的`DashboardComponent`组件
2015-12-23 12:42:57 -05:00
* tie the *Dashboard* into the navigation structure.
2016-04-17 11:31:22 -04:00
* 把 *仪表盘* 加入导航结构中。
2015-12-23 12:42:57 -05:00
.l-sub-section
:marked
*Routing* is another name for *navigation*. The *router* is the mechanism for navigating from view to view.
2016-04-17 11:31:22 -04:00
*路由* 是导航的另一个名字。 *路由器* 就是从一个视图导航到另一个视图的机制。
2015-12-23 12:42:57 -05:00
.l-main-section
:marked
## Splitting the *AppComponent*
2016-04-17 11:31:22 -04:00
## 拆分 *AppComponent*
2015-12-23 12:42:57 -05:00
Our current app loads `AppComponent` and immediately displays the list of heroes.
2016-04-17 11:31:22 -04:00
现在的应用会加载`AppComponent`组件,并且立即显示出英雄列表。
2015-12-23 12:42:57 -05:00
Our revised app should present a shell with a choice of views (*Dashboard* and *Heroes*) and then default to one of them.
2016-04-17 11:31:22 -04:00
我们修改过的应用将提供一个壳,它会从 *仪表盘* 和 *英雄列表* 中选择一个视图,然后默认转到其中之一。
2015-12-23 12:42:57 -05:00
The `AppComponent` should only handle navigation.
Let's move the display of *Heroes* out of `AppComponent` and into its own `HeroesComponent`.
2016-04-17 11:31:22 -04:00
`AppComponent`组件应该只处理导航。
我们来把 *英雄列表* 的显示职责,从`AppComponent`移到`HeroesComponent`组件中。
2015-12-23 12:42:57 -05:00
### *HeroesComponent*
2016-04-17 11:31:22 -04:00
### *HeroesComponent*
2015-12-23 12:42:57 -05:00
`AppComponent` is already dedicated to *Heroes*.
Instead of moving anything out of `AppComponent`, we'll just rename it `HeroesComponent`
and create a new `AppComponent` shell separately.
2016-04-17 11:31:22 -04:00
`AppComponent`已经移交给`HeroesComponent`了。
与其把`AppComponent`中的所有东西都移过去,不如把它改名为`HeroesComponent`,并且单独创建一个新的`AppComponent`壳。
2015-12-23 12:42:57 -05:00
The steps are:
2016-04-17 11:31:22 -04:00
步骤如下:
2015-12-23 12:42:57 -05:00
* rename `app.component.ts` file to `heroes.component.ts`.
2016-04-17 11:31:22 -04:00
* 把`app.component.ts`文件改名为`heroes.component.ts`。
2015-12-23 12:42:57 -05:00
* rename the `AppComponent` class to `HeroesComponent`.
2016-04-17 11:31:22 -04:00
* 把`AppComponent`类改名为`HeroesComponent`。
2015-12-23 12:42:57 -05:00
* rename the selector `my-app` to `my-heroes`.
2016-04-17 11:31:22 -04:00
* 把`my-app`选择器改名为`my-heroes`。
2015-12-23 12:42:57 -05:00
:marked
2016-04-17 11:31:22 -04:00
+makeExample('toh-5/ts/app/heroes.component.ts', 'heroes-component-renaming', 'app/heroes.component.ts (改名)')(format=".")
2015-12-23 12:42:57 -05:00
:marked
## Create *AppComponent*
2016-04-17 11:31:22 -04:00
## 创建 *AppComponent*
2015-12-23 12:42:57 -05:00
The new `AppComponent` will be the application shell.
It will have some navigation links at the top and a display area below for the pages we navigate to.
2016-04-17 11:31:22 -04:00
新的`AppComponent`将成为应用的“壳”。
它将在顶部放一些导航链接,并且把我们要导航到的页面放在下面的区域。
2015-12-23 12:42:57 -05:00
The initial steps are:
2016-04-17 11:31:22 -04:00
这些起始步骤是:
2015-12-23 12:42:57 -05:00
* create a new file named `app.component.ts`.
2016-04-17 11:31:22 -04:00
* 创建一个名叫`app.component.ts`的新文件。
2015-12-23 12:42:57 -05:00
* define an `AppComponent` class.
2016-04-17 11:31:22 -04:00
* 定义一个`AppComponent`类。
2015-12-23 12:42:57 -05:00
* `export` it so we can reference it during bootstrapping in `main.ts`.
2016-04-17 11:31:22 -04:00
* `export`它,以便我们能在`main.ts`的启动期间引用它。
2015-12-23 12:42:57 -05:00
* expose an application `title` property.
2016-04-17 11:31:22 -04:00
* 导出应用的`title`属性。
2015-12-23 12:42:57 -05:00
* add the `@Component` metadata decorator above the class with a `my-app` selector.
2016-04-17 11:31:22 -04:00
* 在类的顶部添加`@Component`元数据装饰器,其中指定`my-app`选择器。
2015-12-23 12:42:57 -05:00
* add a template with `<h1>` tags surrounding a binding to the `title` property.
2016-04-17 11:31:22 -04:00
* 在模板中添加一个`<h1>`标签,其中是到`title`属性的绑定。
2015-12-23 12:42:57 -05:00
* add the `<my-heroes>` tags to the template so we still see the heroes.
2016-04-17 11:31:22 -04:00
* 在模板中添加`<my-heroes>`标签,以便我们仍然能看到英雄列表。
2015-12-23 12:42:57 -05:00
* add the `HeroesComponent` to the `directives` array so Angular recognizes the `<my-heroes>` tags.
2016-04-17 11:31:22 -04:00
* 添加`HeroesComponent`组件到`directives`数组中, 以便Angular能认识`<my-heroes>`标签。
2015-12-23 12:42:57 -05:00
* add the `HeroService` to the `providers` array because we'll need it in every other view.
2016-04-17 11:31:22 -04:00
* 添加`HeroService`到`providers`数组中,因为我们的每一个视图都需要它。
2015-12-23 12:42:57 -05:00
* add the supporting `import` statements.
2016-04-17 11:31:22 -04:00
* 添加支援性的`import`语句。
2015-12-23 12:42:57 -05:00
Our first draft looks like this:
2016-04-17 11:31:22 -04:00
我们的第一个草稿就像这样:
2015-12-23 12:42:57 -05:00
+makeExample('toh-5/ts/app/app.component.1.ts', null, 'app/app.component.ts (v1)')
:marked
.callout.is-critical
header Remove <i>HeroService</i> from the <i>HeroesComponent</i> providers
2016-04-17 11:31:22 -04:00
header 从<i>HeroesComponent</i>的`providers`中移除<i>HeroService</i>
2015-12-23 12:42:57 -05:00
:marked
Go back to the `HeroesComponent` and **remove the `HeroService`** from its `providers` array.
We are *promoting* this service from the `HeroesComponent` to the `AppComponent`.
We ***do not want two copies*** of this service at two different levels of our app.
2016-04-17 11:31:22 -04:00
回到`HeroesComponent`,并从`providers`数组中 **移除`HeroService`** 。
我们要把它从`AppComponent` *晋升* 到`HeroesComponent`中。
我们不希望在应用的两个不同层次上存在它的 ***两个副本*** 。
2015-12-23 12:42:57 -05:00
:marked
The app still runs and still displays heroes.
Our refactoring of `AppComponent` into a new `AppComponent` and a `HeroesComponent` worked!
We have done no harm.
2016-04-17 11:31:22 -04:00
应用仍然在运行,并且显示着英雄列表。
我们把`AppComponent`重构成了一个新的`AppComponent`和`HeroesComponent`,它们工作得很好!
我们毫发无伤的完成了重构。
2015-12-23 12:42:57 -05:00
:marked
## Add Routing
2016-04-17 11:31:22 -04:00
## 添加路由
2015-12-23 12:42:57 -05:00
We're ready to take the next step.
Instead of displaying heroes automatically, we'd like to show them *after* the user clicks a button.
In other words, we'd like to navigate to the list of heroes.
2016-04-17 11:31:22 -04:00
我们已准备好开始下一步。
与其自动显示英雄列表,我们更希望在用户点击按钮之后显示它。
换句话说,我们希望通过导航显示英雄列表。
2015-12-23 12:42:57 -05:00
We'll need the Angular *Component Router*.
2016-04-17 11:31:22 -04:00
我们需要Angular的 *组件路由器* 。
2015-12-23 12:42:57 -05:00
### Include the Router Library
2016-04-17 11:31:22 -04:00
### 包含路由库
2015-12-23 12:42:57 -05:00
Not all apps need routing which is why the Angular *Component Router* is in a separate, optional module library.
2016-04-17 11:31:22 -04:00
不是所有的应用都需要路由, 所以Angular的 *组件路由器* 是一个独立的、可选的模块库。
2015-12-23 12:42:57 -05:00
Our Tour of Heroes needs routing,
so we load the library in the `index.html` in a script tag immediately *after* the angular script itself.
2016-04-17 11:31:22 -04:00
我们的《英雄指南》需要路由。
所以我们在`index.html`的script标签中加载这个库, 仅在加载Angular脚本之后。
+makeExample('toh-5/ts/index.html', 'router', 'index.html (路由)')(format=".")
2015-12-23 12:42:57 -05:00
:marked
While we're in `index.html`, we add `<base href="/">` at the top of the `<head>` section.
2016-04-17 11:31:22 -04:00
在`index.html`中,我们还要添加在`<head>`区的顶部添加`<base href="/">`语句。
2015-12-23 12:42:57 -05:00
+makeExample('toh-5/ts/index.html', 'base-href', 'index.html (base href)')(format=".")
.callout.is-important
header base href is essential
2016-04-23 02:54:01 -04:00
header base href是不可或缺的
2015-12-23 12:42:57 -05:00
:marked
See the *base href* section of the [Router](../guide/router.html#!#base-href) chapter to learn why this matters.
2016-04-17 11:31:22 -04:00
查看[路由器](../guide/router.html#!#base-href)一章的 *base href* 部分,了解为何如此。
2015-12-23 12:42:57 -05:00
:marked
### Make the router available.
2016-04-17 11:31:22 -04:00
### 让路由可用。
2015-12-23 12:42:57 -05:00
The *Component Router* is a service. Like any service, we have to import it and make it
available to the application by adding it to the `providers` array.
2016-04-17 11:31:22 -04:00
*组件路由器* 是一个服务。像所有服务一样,我们得导入它,并且通过把它加入`providers`数组来让它在应用中可用。
2015-12-23 12:42:57 -05:00
The Angular router is a combination of multiple services (`ROUTER_PROVIDERS`), multiple directives (`ROUTER_DIRECTIVES`),
and a configuration decorator (`RouteConfig`). We'll import them all together:
2016-04-17 11:31:22 -04:00
Angular路由器是由多个服务(`ROUTER_PROVIDERS`)和多个指令(`ROUTER_DIRECTIVES`)以及一个配置装饰器(`RouteConfig`)组成的。我们一次性导入它们。
+makeExample('toh-5/ts/app/app.component.2.ts', 'import-router', 'app.component.ts (导入router)')(format=".")
2015-12-23 12:42:57 -05:00
:marked
Next we update the `directives` and `providers` metadata arrays to *include* the router assets.
2016-04-17 11:31:22 -04:00
接下来,我们我们更新`directives`和`providers`元数据数组,来包含这些路由器部件。
+makeExample('toh-5/ts/app/app.component.2.ts', 'directives-and-providers', 'app.component.ts (directives和providers)')(format=".")
2015-12-23 12:42:57 -05:00
:marked
Notice that we also removed the `HeroesComponent` from the `directives` array.
`AppComponent` no longer shows heroes; that will be the router's job.
We'll soon remove `<my-heroes>` from the template too.
2016-04-17 11:31:22 -04:00
注意,我们已经从`directives`数组中移除了`HeroesComponent`。`AppComponent`不会再显示英雄,那是路由器的工作。
我们马上也会从模板中移除`<my-heroes>`。
2015-12-23 12:42:57 -05:00
### Add and configure the router
2016-04-17 11:31:22 -04:00
### 添加与配置路由器
2015-12-23 12:42:57 -05:00
The `AppComponent` doesn't have a router yet. We'll use the `@RouteConfig` decorator to simultaneously
(a) assign a router to the component and (b) configure that router with *routes*.
2016-04-17 11:31:22 -04:00
`AppComponent`还没有路由器。我们使用`@RouteConfig`装饰器来同时 (a)为组件指定一个路由器,并 (b) 通过 *routes* 来配置路由器。
2015-12-23 12:42:57 -05:00
*Routes* tell the router which views to display when a user clicks a link or
pastes a URL into the browser address bar.
2016-04-17 11:31:22 -04:00
*routes* 告诉路由器, 当用户点击链接或者把URL粘贴到浏览器地址栏时, 应该显示哪个路由。
2015-12-23 12:42:57 -05:00
Let's define our first route, a route to the `HeroesComponent`.
2016-04-17 11:31:22 -04:00
我们来定义第一个路由 —— 到`HeroesComponent`的路由。
+makeExample('toh-5/ts/app/app.component.2.ts', 'route-config', 'app.component.ts (英雄列表的RouteConfig)')(format=".")
2015-12-23 12:42:57 -05:00
:marked
`@RouteConfig` takes an array of *route definitions*.
We have only one route definition at the moment but rest assured, we'll add more.
2016-04-17 11:31:22 -04:00
`@RouteConfig`有一个 *路由定义* 数组。
此刻我们只有一个路由定义,但别急,我们还会添加更多。
2015-12-23 12:42:57 -05:00
This *route definition* has three parts:
2016-04-17 11:31:22 -04:00
“路由定义”包括三个部分:
2015-12-23 12:42:57 -05:00
* **path**: the router matches this route's path to the URL in the browser address bar (`/heroes`).
2016-04-17 11:31:22 -04:00
* **path**: 路由器会用它来匹配路由中的路径和浏览器地址栏中的路径,如`/heroes`。
2015-12-23 12:42:57 -05:00
* **name**: the official name of the route; it *must* begin with a capital letter to avoid confusion with the *path* (`Heroes`).
2016-04-17 11:31:22 -04:00
* **name**: 路由的正式名字,它必须以大写字母开头儿,以免和 *path* 混淆,如`Heroes`。
2015-12-23 12:42:57 -05:00
* **component**: the component that the router should create when navigating to this route (`HeroesComponent`).
2016-04-17 11:31:22 -04:00
* **component**: 当导航到此路由时,路由器需要创建的组件,如`HeroesComponent`。
2015-12-23 12:42:57 -05:00
.l-sub-section
:marked
Learn more about defining routes with @RouteConfig in the [Routing](../guide/router.html) chapter.
2016-04-17 11:31:22 -04:00
要学习更多使用`@RouteConfig`定义路由的知识,请参见[路由](../guide/router.html)一章。
2015-12-23 12:42:57 -05:00
:marked
### Router Outlet
2016-04-17 11:31:22 -04:00
### 路由插座( Outlet)
2015-12-23 12:42:57 -05:00
If we paste the path, `/heroes`, into the browser address bar,
the router should match it to the `'Heroes'` route and display the `HeroesComponent`.
But where?
2016-04-17 11:31:22 -04:00
如果我们把路径`/heroes`粘贴到浏览器的地址栏中,路由器会匹配到`'Heroes'`路由,并显示`HeroesComponent`组件。
但问题是,把它显示在哪儿呢?
2015-12-23 12:42:57 -05:00
We have to ***tell it where*** by adding `<router-outlet>` marker tags to the bottom of the template.
`RouterOutlet` is one of the `ROUTER_DIRECTIVES`.
The router displays each component immediately below the `<router-outlet>` as we navigate through the application.
2016-04-17 11:31:22 -04:00
我们必须 ***告诉它位置*** ,所以我们把`<router-outlet>`标签添加到模板的底部。
`RouterOutlet`是`ROUTER_DIRECTIVES`常量中的一员。
当我们通过应用导航过来时,路由器立即把每个组件显示在`<router-outlet>`的位置。
2015-12-23 12:42:57 -05:00
### Router Links
2016-04-17 11:31:22 -04:00
### 路由器链接
2015-12-23 12:42:57 -05:00
We don't really expect users to paste a route URL into the address bar.
We add an anchor tag to the template which, when clicked, triggers navigation to the `HeroesComponent`.
2016-04-17 11:31:22 -04:00
我们不可能真等用户把路由的URL粘贴到地址栏中, 我们应该在模板中的什么地方添加一个A链接标签, 点击时, 就会触发导航到`HeroesComponent`组件的操作。
2015-12-23 12:42:57 -05:00
The revised template looks like this:
2016-04-17 11:31:22 -04:00
修改过的模板是这样的:
+makeExample('toh-5/ts/app/app.component.2.ts', 'template', 'app.component.ts (英雄列表模板)')(format=".")
2015-12-23 12:42:57 -05:00
:marked
Notice the `[routerLink]` binding in the anchor tag.
We bind the `RouterLink` directive (another of the `ROUTER_DIRECTIVES`) to an array
that tells the router where to navigate when the user clicks the link.
2016-04-17 11:31:22 -04:00
注意, A标签中的`[routerLink]`绑定。我们把`RouterLink`指令(`ROUTER_DIRECTIVES`中的另一个指令)绑定到一个数组,它将告诉路由器,当用户点击这个链接时,应该导航到那里。
2015-12-23 12:42:57 -05:00
We define a *routing instruction* with a *link parameters array*.
The array only has one element in our little sample, the quoted ***name* of the route** to follow.
Looking back at the route configuration, we confirm that `'Heroes'` is the name of the route to the `HeroesComponent`.
2016-04-17 11:31:22 -04:00
我们通过一个 *链接参数数组* 定义了一个 *路由说明* 。
在我们这个小例子中,该数组只有一个元素,一个放在引号中的 **路由名称** ,用作路标。
回来看路由配置表,我们清楚地看到,这个名称 —— `'Heroes'` 就是指向`HeroesComponent`的那个路由的名称。
2015-12-23 12:42:57 -05:00
.l-sub-section
:marked
2016-02-18 18:32:26 -05:00
Learn about the *link parameters array* in the [Routing](../guide/router.html#link-parameters-array) chapter.
2016-04-17 11:31:22 -04:00
学习关于 *连接参数数组* 的更多知识,参见[路由](../guide/router.html#link-parameters-array)一章。
2015-12-23 12:42:57 -05:00
:marked
Refresh the browser. We see only the app title. We don't see the heroes list.
2016-04-17 11:31:22 -04:00
刷新浏览器。我们只看到了应用标题。英雄列表到哪里去了?
2015-12-23 12:42:57 -05:00
.l-sub-section
:marked
The browser's address bar shows `/`.
The route path to `HeroesComponent` is `/heroes`, not `/`.
We don't have a route that matches the path `/`, so there is nothing to show.
That's something we'll want to fix.
2016-04-17 11:31:22 -04:00
浏览器的地址栏显示的是`/`。到`HeroesComponent`的路由中的路径是`/`,所以,自然没啥可显示的。
接下来我们要修复这个问题。
2015-12-23 12:42:57 -05:00
:marked
We click the "Heroes" navigation link, the browser bar updates to `/heroes`,
and now we see the list of heroes. We are navigating at last!
2016-04-17 11:31:22 -04:00
我们点击“英雄列表( Heroes) ”导航链接, 浏览器地址栏更新为`/heroes`,并且看到了英雄列表。我们终于导航过去了!
2015-12-23 12:42:57 -05:00
At this stage, our `AppComponent` looks like this.
2016-04-17 11:31:22 -04:00
在这个阶段,`AppComponent`看起来是这样的:
2015-12-23 12:42:57 -05:00
+makeExample('toh-5/ts/app/app.component.2.ts',null, 'app/app.component.ts (v2)')
:marked
The *AppComponent* is now attached to a router and displaying routed views.
For this reason and to distinguish it from other kinds of components,
we call this type of component a *Router Component*.
2016-04-17 11:31:22 -04:00
*AppComponent* 现在有了一个路由器,并且能显示路由到的视图。
因此,为了把它从其他种类的组件中区分出来,我们称这类组件为 *路由器组件*。
2015-12-23 12:42:57 -05:00
:marked
## Add a *Dashboard*
2016-04-17 11:31:22 -04:00
## 添加一个 *仪表盘*
2015-12-23 12:42:57 -05:00
Routing only makes sense when we have multiple views. We need another view.
2016-04-17 11:31:22 -04:00
只有在我们有多个视图的时候,路由才有意义。我们需要另一个视图。
2015-12-23 12:42:57 -05:00
Create a placeholder `DashboardComponent` that gives us something to navigate to and from.
2016-04-17 11:31:22 -04:00
先创建一个`DashboardComponent`的占位符,让我们可以导航到它或导航自它。
2015-12-23 12:42:57 -05:00
+makeExample('toh-5/ts/app/dashboard.component.1.ts',null, 'app/dashboard.component.ts (v1)')(format=".")
:marked
We’ ll come back and make it more useful later.
2016-04-17 11:31:22 -04:00
我们先不实现它,稍后,我们再回来,让这个组件更有用。
2015-12-23 12:42:57 -05:00
### Configure the dashboard route
2016-04-17 11:31:22 -04:00
### 配置仪表盘路由
2015-12-23 12:42:57 -05:00
Go back to `app.component.ts` and teach it to navigate to the dashboard.
2016-04-17 11:31:22 -04:00
回到`app.component.ts`文件,教它如何导航到这个仪表盘。
2015-12-23 12:42:57 -05:00
Import the `DashboardComponent` so we can reference it in the dashboard route definition.
2016-04-17 11:31:22 -04:00
导入`DashboardComponent`类,以便我们可以在仪表盘的路由定义中引用它。
2015-12-23 12:42:57 -05:00
Add the following `'Dashboard'` route definition to the `@RouteConfig` array of definitions.
2016-04-17 11:31:22 -04:00
把下列`'Dashboard'`路由的定义添加到`@RouteConfig`数组中去。
+makeExample('toh-5/ts/app/app.component.ts','dashboard-route', 'app.component.ts (仪表盘路由)')(format=".")
2015-12-23 12:42:57 -05:00
.l-sub-section
:marked
**useAsDefault**
We want the app to show the dashboard when it starts and
we want to see a nice URL in the browser address bar that says `/dashboard`.
Remember that the browser launches with `/` in the address bar.
We don't have a route for that path and we'd rather not create one.
2016-04-17 11:31:22 -04:00
我们希望应用在启动的时候就显示仪表盘, 并且我们希望在浏览器的地址栏看到一个好看的URL, 比如`/dashboard`。
记住,浏览器启动时,在地址栏中使用的路径是`/`。我们没有指向这个路径的路由,也不想创建它。
2015-12-23 12:42:57 -05:00
Fortunately we can add the `useAsDefault: true` property to the *route definition* and the
router will display the dashboard when the browser URL doesn't match an existing route.
2016-04-17 11:31:22 -04:00
幸运的是,我们可以把`useAsDefault: true`属性添加到 *路由定义* 上。这样, 如果浏览器中的URL匹配不上任何一个已知路由, 那么路由器将显示这个仪表盘组件。
2015-12-23 12:42:57 -05:00
:marked
Finally, add a dashboard navigation link to the template, just above the *Heroes* link.
2016-04-17 11:31:22 -04:00
最后,在模板上添加一个到仪表盘的导航链接,就在 *英雄(Heroes)* 链接的上方。
2015-12-23 12:42:57 -05:00
2016-04-17 11:31:22 -04:00
+makeExample('toh-5/ts/app/app.component.ts','template', 'app.component.ts (模板)')(format=".")
2015-12-23 12:42:57 -05:00
.l-sub-section
:marked
We nestled the two links within `<nav>` tags.
They don't do anything yet but they'll be convenient when we style the links a little later in the chapter.
2016-04-17 11:31:22 -04:00
我们在`<nav>`标签中放了两个链接。
它们现在还没有作用,但稍后,当我们对这些链接添加样式时,会显得比较方便。
2015-12-23 12:42:57 -05:00
:marked
Refresh the browser. The app displays the dashboard and
we can navigate between the dashboard and the heroes.
2016-04-17 11:31:22 -04:00
刷新浏览器。应用显示出了仪表盘,并且我们可以在仪表盘和英雄列表之间导航了。
2015-12-23 12:42:57 -05:00
## Dashboard Top Heroes
2016-04-17 11:31:22 -04:00
## 仪表盘上的顶尖英雄
2015-12-23 12:42:57 -05:00
Let’ s spice up the dashboard by displaying the top four heroes at a glance.
2016-04-17 11:31:22 -04:00
我们要让仪表盘更有趣,比如:一眼就能看到四个顶尖英雄。
2015-12-23 12:42:57 -05:00
Replace the `template` metadata with a `templateUrl` property that points to a new
2016-03-08 07:45:29 -05:00
template file.
2015-12-23 12:42:57 -05:00
2016-04-17 11:31:22 -04:00
把元数据中的`template`属性替换为`templateUrl`属性,它将指向一个新的模板文件。
2016-03-08 07:45:29 -05:00
+makeExample('toh-5/ts/app/dashboard.component.ts', 'template-url', 'app/dashboard.component.ts (templateUrl)')(format=".")
.l-sub-section
:marked
2016-03-08 18:09:31 -05:00
We specify the path _all the way back to the application root_. Angular doesn't support module-relative paths.
2016-04-17 11:31:22 -04:00
我们指定的所有路径都是相对于该应用的根目录的。Angular不支持使用相对于当前模块的路径。
2016-03-08 07:45:29 -05:00
:marked
2015-12-23 12:42:57 -05:00
Create that file with these contents:
2016-04-17 11:31:22 -04:00
使用下列内容创建文件:
2015-12-23 12:42:57 -05:00
+makeExample('toh-5/ts/app/dashboard.component.html', null, 'dashboard.component.html')(format=".")
:marked
We use `*ngFor` once again to iterate over a list of heroes and display their names.
We added extra `<div>` elements to help with styling later in this chapter.
2016-04-17 11:31:22 -04:00
我们又一次使用`*ngFor`来在英雄列表上迭代,并且显示他们的名字。
我们添加了一个额外的`<div>`元素,来帮助稍后的美化工作。
2015-12-23 12:42:57 -05:00
There's a `(click)` binding to a `gotoDetail` method we haven't written yet and
we're displaying a list of heroes that we don't have.
We have work to do, starting with those heroes.
2016-04-17 11:31:22 -04:00
这里的`(click)`绑定到了`gotoDetail`方法,但我们还没实现它。并且我们也没有要显示的英雄列表数据。
我们有活儿干了,就从那些英雄列表开始吧。
2015-12-23 12:42:57 -05:00
### Share the *HeroService*
2016-04-17 11:31:22 -04:00
### 共享 *HeroService*
2015-12-23 12:42:57 -05:00
We'd like to re-use the `HeroService` to populate the component's `heroes` array.
2016-04-17 11:31:22 -04:00
我们想要重用`HeroService`来存放组件的`heroes`数组。
2015-12-23 12:42:57 -05:00
Recall earlier in the chapter that we removed the `HeroService` from the `providers` array of the `HeroesComponent`
and added it to the `providers` array of the top level `AppComponent`.
2016-04-17 11:31:22 -04:00
回忆一下,在前面的章节中,我们从`HeroesComponent`的`providers`数组中移除了`HeroService`服务,并且把它添加到了顶级组件`AppComponent`的`providers`数组中。
2015-12-23 12:42:57 -05:00
That move created a singleton `HeroService` instance, available to *all* components of the application.
We'll inject and use it here in the `DashboardComponent` .
2016-04-17 11:31:22 -04:00
这个改动创建了一个`HeroService`的单例对象,并且对应用中的 *所有* 组件都有效。
在`DashboardComponent`组件中,我们将把它注入进来,并使用它。
2015-12-23 12:42:57 -05:00
### Get heroes
2016-04-17 11:31:22 -04:00
### 获取英雄数组
2015-12-23 12:42:57 -05:00
Open the `dashboard.component.ts` and add the requisite `import` statements.
2016-04-17 11:31:22 -04:00
打开`dashboard.component.ts`文件,并且把必备的`import`语句加进去。
+makeExample('toh-5/ts/app/dashboard.component.2.ts','imports', 'app/dashboard.component.ts (导入)')(format=".")
2015-12-23 12:42:57 -05:00
:marked
We need `OnInit` interface because we'll initialize the heroes in the `ngOnInit` method as we've done before.
We need the `Hero` and `HeroService` symbols in order to reference those types.
2016-04-17 11:31:22 -04:00
我们得实现`OnInit`接口,因为我们要在`ngOnInit`方法中初始化英雄数组 —— 就像上次一样。
我们需要导入`Hero`和`HeroService`类来引用它们的数据类型。
2015-12-23 12:42:57 -05:00
Now implement the `DashboardComponent` class like this:
2016-04-17 11:31:22 -04:00
现在就来实现`DashboardComponent`类,像这样:
+makeExample('toh-5/ts/app/dashboard.component.2.ts','component', 'app/dashboard.component.ts (类)')
2015-12-23 12:42:57 -05:00
:marked
We saw this kind of logic before in the `HeroesComponent`.
* create a `heroes` array property
* inject the `HeroService` in the constructor and hold it in a private `_heroService` field.
* call the service to get heroes inside the Angular `ngOnInit` lifecycle hook.
2016-04-17 11:31:22 -04:00
在`HeroesComponent`之前,我们也看到过类似的逻辑:
* 创建一个`heroes`数组属性
* 把`HeroService`注入构造函数中,并且把它保存在一个私有的`_heroService`字段中。
* 在Angular的`ngOnInit`生命周期钩子中调用这个服务,并且取得英雄列表。
2015-12-23 12:42:57 -05:00
The noteworthy differences: we cherry-pick four heroes (2nd, 3rd, 4th, and 5th) with *slice*
and stub the `gotoDetail` method until we're ready to implement it.
2016-04-17 11:31:22 -04:00
不同之处在于:我们使用 *slice* 函数挑选四个英雄( 第2、3、4、5个) , 并且先为`gotoDetail`方法提供桩实现 —— 直到我们准备实现它。
2015-12-23 12:42:57 -05:00
Refresh the browser and see four heroes in the new dashboard.
2016-04-17 11:31:22 -04:00
刷新浏览器,并且在新的仪表盘中看到了四个英雄。
2015-12-23 12:42:57 -05:00
.l-main-section
:marked
## Navigate to Hero Details
2016-04-17 11:31:22 -04:00
## 导航到英雄详情
2015-12-23 12:42:57 -05:00
Although we display the details of a selected hero at the bottom of the `HeroesComponent`,
we don't yet *navigate* to the `HeroDetailComponent` in the three ways specified in our requirements:
2016-04-17 11:31:22 -04:00
虽然我们在`HeroesComponent`组件的底部显示了所选英雄的详情,但我们还从没有 *导航* 到`HeroDetailComponent`组件,不管用我们需求中指定的三种方式中的哪一种:
2016-04-20 08:07:39 -04:00
1. from the *Dashboard* to a selected hero.
2016-04-17 11:31:22 -04:00
1. 从 *仪表盘(Dashboard)* 导航到一个选定的英雄。
2016-04-20 08:07:39 -04:00
1. from the *Heroes* list to a selected hero.
2016-04-17 11:31:22 -04:00
1. 从 *英雄列表(Heroes)* 导航到一个选定的英雄。
2016-04-20 08:07:39 -04:00
1. from a "deep link" URL pasted into the browser address bar.
2016-04-17 11:31:22 -04:00
1. 把一个指向他的"深链接"URL粘贴到浏览器的地址栏。
2015-12-23 12:42:57 -05:00
Adding a `'HeroDetail'` route seem an obvious place to start.
2016-04-17 11:31:22 -04:00
添加`'HeroDetail'`路由,是一个显而易见的起点。
2015-12-23 12:42:57 -05:00
### Routing to a hero detail
2016-04-17 11:31:22 -04:00
### 路由到一个英雄详情
2015-12-23 12:42:57 -05:00
We'll add a route to the `HeroDetailComponent` in the `AppComponent` where our other routes are configured.
2016-04-17 11:31:22 -04:00
我们将在`AppComponent`中添加一个到`HeroDetailComponent`的路由,那也是配置其它路由的地方。
2015-12-23 12:42:57 -05:00
The new route is a bit unusual in that we must tell the `HeroDetailComponent` *which hero to show*.
We didn't have to tell the `HeroesComponent` or the `DashboardComponent` anything.
2016-04-17 11:31:22 -04:00
新路由的不寻常之处在于,我们必须告诉`HeroDetailComponent` *该显示哪个英雄* 。
以前的`HeroesComponent`组件和`DashboardComponent`组件都还不曾要求我们告诉它任何东西。
2015-12-23 12:42:57 -05:00
At the moment the parent `HeroesComponent` sets the component's `hero` property to a hero object with a binding like this.
2016-04-17 11:31:22 -04:00
现在,父组件`HeroesComponent`通过数据绑定来把一个英雄对象设置为组件的`hero`属性。就像这样:
2015-12-23 12:42:57 -05:00
code-example(format='').
<my-hero-detail [hero]="selectedHero"></my-hero-detail>
:marked
That clearly won't work in any of our routing scenarios.
Certainly not the last one; we can't embed an entire hero object in the URL! Nor would we want to.
2016-04-17 11:31:22 -04:00
显然,在我们的任何一个路由场景中它都无法工作。
不仅如此, 我们也没法把一个完整的hero对象嵌入到URL中! 其实我们也不想这样。
2015-12-23 12:42:57 -05:00
### Parameterized route
2016-04-17 11:31:22 -04:00
### 参数化路由
2015-12-23 12:42:57 -05:00
We *can* add the hero's `id` to the URL. When routing to the hero whose `id` is 11, we could expect to see an URL such as this:
2016-04-17 11:31:22 -04:00
我们 *可以* 把英雄的`id`添加到URL中。当导航到一个`id`为11的英雄时, 我们期望的URL是这样的:
2015-12-23 12:42:57 -05:00
code-example(format='').
/detail/11
:marked
The `/detail/` part of that URL is constant. The trailing numeric `id` part changes from hero to hero.
We need to represent that variable part of the route with a *parameter* (or *token*) that stands for the hero's `id`.
2016-04-17 11:31:22 -04:00
URL中的`/detail/`部分是不变的。结尾的数字`id`部分会随着英雄的不同而变化。
我们要把路由中可变的那部分表示成一个 *参数(parameter)* 或 *标识(token)* ,用以获取英雄的`id`。
2015-12-23 12:42:57 -05:00
### Configure a Route with a Parameter
2016-04-17 11:31:22 -04:00
### 通过参数来配置路由
2015-12-23 12:42:57 -05:00
Here's the *route definition* we'll use.
2016-04-17 11:31:22 -04:00
下面是我们将使用的 *路由定义*
+makeExample('toh-5/ts/app/app.component.ts','hero-detail-route', 'app/app.component.ts (到HeroDetailComponent的路由)')(format=".")
2015-12-23 12:42:57 -05:00
:marked
The colon (:) in the path indicates that `:id` is a placeholder to be filled with a specific hero `id`
when navigating to the `HeroDetailComponent`.
2016-04-17 11:31:22 -04:00
路径中的冒号(:)标记`:id`是一个占位符,当导航到这个`HeroDetailComponent`组件时,它将被填成一个特定英雄的`id`。
2015-12-23 12:42:57 -05:00
.l-sub-section
:marked
Of course we have to import the `HeroDetailComponent` before we create this route:
2016-04-17 11:31:22 -04:00
当然,在创建这个路由之前,我们必须导入`HeroDetailComponent`类。
2015-12-23 12:42:57 -05:00
+makeExample('toh-5/ts/app/app.component.ts','hero-detail-import')(format=".")
:marked
We're finished with the `AppComponent`.
2016-04-17 11:31:22 -04:00
我们正在完成`AppComponent`组件。
2015-12-23 12:42:57 -05:00
We won't add a `'Hero Detail'` link to the template because users
don't click a navigation *link* to view a particular hero.
They click a *hero* whether that hero is displayed on the dashboard or in the heroes list.
2016-04-17 11:31:22 -04:00
我们没有往模板中添加一个`'英雄详情'`,这是因为用户不会直接点击导航栏中的链接去查看一个特定的英雄。
他们只会从英雄列表或者仪表盘中点击一个英雄。
2015-12-23 12:42:57 -05:00
We'll get to those *hero* clicks later in the chapter.
There's no point in working on them until the `HeroDetailComponent`
is ready to be navigated *to*.
2016-04-17 11:31:22 -04:00
稍后我们会响应这些 *英雄* 的点击事件。
现在对它们做什么都没有意义 —— 除非`HeroDetailComponent`已经做好了,并且能够被导航过去。
2015-12-23 12:42:57 -05:00
That will require an `HeroDetailComponent` overhaul.
2016-04-17 11:31:22 -04:00
那需要对`HeroDetailComponent`做一次大修。
2015-12-23 12:42:57 -05:00
.l-main-section
:marked
## Revise the *HeroDetailComponent*
2016-04-17 11:31:22 -04:00
## 修改 *HeroDetailComponent*
2015-12-23 12:42:57 -05:00
Before we rewrite the `HeroDetailComponent`, let's remember what it looks like now:
2016-04-17 11:31:22 -04:00
在重写`HeroDetailComponent`之前,我们先记住它现在的样子:
+makeExample('toh-4/ts/app/hero-detail.component.ts', null, 'app/hero-detail.component.ts (当前)')
2015-12-23 12:42:57 -05:00
:marked
The template won't change. We'll display a hero the same way. The big changes are driven by how we get the hero.
2016-04-17 11:31:22 -04:00
模板不用修改。我们会用跟以前一样的方式显示英雄。导致这次大修的原因是如何获得这个英雄的数据。
2015-12-23 12:42:57 -05:00
We will no longer receive the hero in a parent component property binding.
The new `HeroDetailComponent` should take the `id` parameter from the router's `RouteParams` service
and use the `HeroService` to fetch the hero with that `id` from storage.
2016-04-17 11:31:22 -04:00
我们不会再从父组件的属性绑定中取得英雄数据。
新的`HeroDetailComponent`应该从路由器的`RouteParams`服务取得`id`参数,并通过`HeroService`服务获取具有这个指定`id`的英雄数据。
2015-12-23 12:42:57 -05:00
We need an import statement to reference the `RouteParams`.
2016-04-17 11:31:22 -04:00
我们需要一个import语句, 来引用`RouteParams`。
2015-12-23 12:42:57 -05:00
+makeExample('toh-5/ts/app/hero-detail.component.ts', 'import-route-params')(format=".")
:marked
We import the `HeroService`so we can fetch a hero`.
2016-04-17 11:31:22 -04:00
我们导入了`HeroService`,现在我们能获取一个英雄了。
2015-12-23 12:42:57 -05:00
+makeExample('toh-5/ts/app/hero-detail.component.ts', 'import-hero-service')(format=".")
:marked
We import the `OnInit` interface because we'll call the `HeroService` inside the `ngOnInit` component lifecycle hook.
2016-04-17 11:31:22 -04:00
我们要导入`OnInit`接口,是因为我们需要在组件的`ngOnInit`生命周期钩子中调用`HeroService`。
2015-12-23 12:42:57 -05:00
+makeExample('toh-5/ts/app/hero-detail.component.ts', 'import-oninit')(format=".")
:marked
We inject the both the `RouteParams` service and the `HeroService` into the constructor as we've done before,
making private variables for both:
2016-04-17 11:31:22 -04:00
像以前一样,我们把`RouteParams`服务和`HeroService`服务注入到构造函数中,让它们成为私有变量。
+makeExample('toh-5/ts/app/hero-detail.component.ts', 'ctor', 'app/hero-detail.component.ts (构造函数)')(format=".")
2016-03-15 08:24:50 -04:00
:marked
We tell the class that we want to implement the `OnInit` interface.
2016-04-17 11:31:22 -04:00
我们告诉这个类,我们要实现`OnInit`接口。
2016-03-15 08:24:50 -04:00
+makeExample('toh-5/ts/app/hero-detail.component.ts', 'implement')(format=".")
2015-12-23 12:42:57 -05:00
:marked
Inside the `ngOnInit` lifecycle hook, extract the `id` parameter value from the `RouteParams` service
and use the `HeroService` to fetch the hero with that `id`.
2016-04-17 11:31:22 -04:00
在`ngOnInit`生命周期钩子中,从`RouteParams`服务中提取`id`参数,并且使用`HeroService`来获得具有这个`id`的英雄数据。
2015-12-23 12:42:57 -05:00
+makeExample('toh-5/ts/app/hero-detail.component.ts', 'ng-oninit', 'app/hero-detail.component.ts (ngOnInit)')(format=".")
:marked
Notice how we extract the `id` by calling the `RouteParams.get` method.
2016-04-17 11:31:22 -04:00
注意我们是如何通过调用`RouteParams.get`方法来获取`id`的。
2015-12-23 12:42:57 -05:00
+makeExample('toh-5/ts/app/hero-detail.component.ts', 'get-id')(format=".")
:marked
The hero `id` is a number. Route parameters are *always strings*.
So we convert the route parameter value to a number with the JavaScript (+) operator.
2016-04-17 11:31:22 -04:00
英雄的`id`是数字。路由参数 *永远是字符串* 。
所以我们需要通过JavaScript的(+)操作符把路由参数的值转成数字。
2015-12-23 12:42:57 -05:00
### Add *HeroService.getHero*
2016-04-17 11:31:22 -04:00
### 添加 *HeroService.getHero*
2015-12-23 12:42:57 -05:00
The problem with this bit of code is that `HeroService` doesn't have a `getHero` method!
We better fix that quickly before someone notices that we broke the app.
2016-04-17 11:31:22 -04:00
这些代码的问题在于`HeroService`并没有一个叫`getHero`的方法,我们最好在有人通知我们应用坏了之前赶快修复它。
2015-12-23 12:42:57 -05:00
Open `HeroService` and add the `getHero` method. It's trivial given that we're still faking data access:
2016-04-17 11:31:22 -04:00
打开`HeroService`,并且添加`getHero`方法进去。对于我们的假数据存取逻辑来说,这点修改是微不足道的:
2015-12-23 12:42:57 -05:00
+makeExample('toh-5/ts/app/hero.service.ts', 'get-hero', 'app/hero.service.ts (getHero)')(format=".")
:marked
Return to the `HeroDetailComponent` to clean up loose ends.
2016-04-17 11:31:22 -04:00
回到`HeroDetailComponent`来完成收尾工作。
2015-12-23 12:42:57 -05:00
### Find our way back
2016-04-17 11:31:22 -04:00
### 回到原路
2015-12-23 12:42:57 -05:00
We can navigate *to* the `HeroDetailComponent` in several ways.
How do we navigate somewhere else when we're done?
2016-04-17 11:31:22 -04:00
我们能用多种方式导航 *到* `HeroDetailComponent`。
但当我们完工时,我们该导航到那里呢?
2015-12-23 12:42:57 -05:00
The user could click one of the two links in the `AppComponent`. Or click the browser's back button.
We'll add a third option, a `goBack` method that navigates backward one step in the browser's history stack
2016-04-17 11:31:22 -04:00
用户可以点击`AppComponent`中的两个链接,或者点击浏览器的“后退”按钮。
我们来添加第三个选项:一个`goBack`方法,来根据浏览器的历史堆栈,往回退一步。
2015-12-23 12:42:57 -05:00
+makeExample('toh-5/ts/app/hero-detail.component.ts', 'go-back', 'app/hero-detail.component.ts (goBack)')(format=".")
.l-sub-section
:marked
Going back too far could take us out of the application.
That's acceptable in a demo. We'd guard against it in a real application,
2016-04-19 20:44:38 -04:00
perhaps with the [*routerCanDeactivate* hook](../api/router/CanDeactivate-interface.html).
2016-04-18 10:59:24 -04:00
回退太多步儿会离开我们的应用。
在Demo中, 这算不上问题。但在真实的应用中, 我们需要对此进行防范。
或许你该用[*routerCanDeactivate* 钩子](/docs/ts/latest/api/router/CanDeactivate-interface.html)。
2015-12-23 12:42:57 -05:00
:marked
Then we wire this method with an event binding to a *Back* button that we add to the bottom of the component template.
2016-04-18 10:59:24 -04:00
然后,我们通过一个事件绑定把此方法绑定到模板底部的 *后退(Back)* 按钮上。
2015-12-23 12:42:57 -05:00
+makeExample('toh-5/ts/app/hero-detail.component.html', 'back-button')(format=".")
:marked
Modifing the template to add this button spurs us to take one more incremental improvement and migrate the template to its own file
called `hero-detail.component.html`
2016-04-18 10:59:24 -04:00
修改模板,添加这个按钮以提醒我们还要做更多的改进,并把模板移到独立的`hero-detail.component.html`文件中去。
2015-12-23 12:42:57 -05:00
+makeExample('toh-5/ts/app/hero-detail.component.html', '', 'app/hero-detail.component.html')(format=".")
:marked
We update the component metadata with a `templateUrl` pointing to the template file that we just created.
2016-04-18 10:59:24 -04:00
然后更新组件的元数据,用一个`templateUrl`属性指向我们刚刚创建的模板文件。
2015-12-23 12:42:57 -05:00
+makeExample('toh-5/ts/app/hero-detail.component.ts', 'template-url', 'app/hero-detail.component.ts (templateUrl)')(format=".")
:marked
Here's the (nearly) finished `HeroDetailComponent`:
2016-04-18 10:59:24 -04:00
下面是(几乎)完成的`HeroDetailComponent`:
+makeExample('toh-5/ts/app/hero-detail.component.ts', 'v2', 'app/hero-detail.component.ts (最新版)')(format=".")
2015-12-23 12:42:57 -05:00
:marked
.l-main-section
:marked
## Select a *Dashboard* Hero
2016-04-18 10:59:24 -04:00
## 选择一个 *仪表盘* 中的英雄
2015-12-23 12:42:57 -05:00
When a user selects a hero in the dashboard, the app should navigate to the `HeroDetailComponent` to view and edit the selected hero..
2016-04-18 10:59:24 -04:00
当用户从仪表盘中选择了一位英雄时,应用应该导航到`HeroDetailComponent`以查看和编辑所选的英雄。
2015-12-23 12:42:57 -05:00
In the dashboard template we bound each hero's click event to the `gotoDetail` method, passing along the selected `hero` entity.
2016-04-18 10:59:24 -04:00
在仪表盘模板中, 我们把每个英雄的click事件都绑定成`gotoDetail`方法,并且传入选中的这个`hero`实体对象。
+makeExample('toh-5/ts/app/dashboard.component.html','click', 'app/dashboard.component.html (click绑定)')(format=".")
2015-12-23 12:42:57 -05:00
:marked
We stubbed the `gotoDetail` method when we rewrote the `DashboardComponent`.
Now we give it a real implementation.
2016-04-18 10:59:24 -04:00
当初我们重写`DashboardComponent`的时候,`gotoDetail`还是一个“桩方法”。
现在,我们给它一个真正的实现。
2015-12-23 12:42:57 -05:00
+makeExample('toh-5/ts/app/dashboard.component.ts','goto-detail', 'app/dashboard.component.ts (gotoDetail)')(format=".")
:marked
The `gotoDetail` method navigates in two steps:
2016-04-18 10:59:24 -04:00
`gotoDetail`方法分两步完成导航:
2016-04-20 08:07:39 -04:00
1. set a route *link parameters array*
2016-04-18 10:59:24 -04:00
1. 生成路由的 *链接参数数组*
2016-04-20 08:07:39 -04:00
1. pass the array to the router's navigate method.
2016-04-18 10:59:24 -04:00
1. 把这个数组传给路由器的navigate方法。
2015-12-23 12:42:57 -05:00
We wrote *link parameters arrays* in the `AppComponent` for the navigation links.
Those arrays had only one element, the name of the destination route.
2016-04-18 10:59:24 -04:00
我们当初在`AppComponent`中生成导航链接的时候曾经写过 *链接参数数组* 。
2015-12-23 12:42:57 -05:00
This array has two elements, the ***name*** of the destination route and a ***route parameter object***
with an `id` field set to the value of the selected hero's `id`.
2016-04-18 10:59:24 -04:00
这个数组有两个元素,目标路由的 ***名称(name)*** ,和一个 ***路由参数对象*** ,其中包括一个`id`字段,它的取值是所选英雄的`id`。
2015-12-23 12:42:57 -05:00
The two array items align with the ***name*** and ***:id*** token in the parameterized `HeroDetail` route configuration we added to `AppComponent` earlier in the chapter.
2016-04-18 10:59:24 -04:00
当初我们在`AppComponent`中添加路由的时候,这两个数组元素以 ***name*** 和 ***:id*** 为代号被参数化在路由配置对象`HeroDetail`中。
+makeExample('toh-5/ts/app/app.component.ts','hero-detail-route', 'app/app.component.ts (英雄详情路由)')(format=".")
2015-12-23 12:42:57 -05:00
:marked
The `DashboardComponent` doesn't have the router yet. We obtain it in the usual way:
`import` the `router` reference and inject it in the constructor (along with the `HeroService`):
2016-04-18 10:59:24 -04:00
`DashboardComponent`还没有路由器。我们使用常规的方式为它加上路由:
`import` `router`对象的引用,并且把它注入到构造函数中(就像`HeroService`那样):
+makeExample('toh-5/ts/app/dashboard.component.ts','import-router', 'app/dashboard.component.ts (节选)')(format=".")
2015-12-23 12:42:57 -05:00
+makeExample('toh-5/ts/app/dashboard.component.ts','ctor')(format=".")
:marked
Refresh the browser and select a hero from the dashboard; the app should navigate directly to that hero’ s details.
2016-04-18 10:59:24 -04:00
刷新浏览器,并且从仪表盘中选择一位英雄;应用就会直接导航到英雄的详情。
2015-12-23 12:42:57 -05:00
.l-main-section
:marked
## Select a Hero in the *HeroesComponent*
2016-04-18 10:59:24 -04:00
## 在 *HeroesComponent* 中选择一位英雄
2015-12-23 12:42:57 -05:00
We'll do something similar in the `HeroesComponent`.
2016-04-18 10:59:24 -04:00
我们要做的事和`HeroesComponent`中很像。
2015-12-23 12:42:57 -05:00
That component's current template exhibits a "master/detail" style with the list of heroes
at the top and details of the selected hero below.
2016-04-18 10:59:24 -04:00
那个组件现在的模板展示了一个主从风格的界面:上方是英雄列表,底下是所选英雄的详情。
+makeExample('toh-4/ts/app/app.component.ts','template', 'app/heroes.component.ts (当前的模板)')(format=".")
2015-12-23 12:42:57 -05:00
:marked
Delete the last line of the template with the `<my-hero-detail>` tags.
2016-04-18 10:59:24 -04:00
删除模板最后带有`<my-hero-detail>`标签的那一行。
2015-12-23 12:42:57 -05:00
We'll no longer show the full `HeroDetailComponent` here.
We're going to display the hero detail on its own page and route to it as we did in the dashboard.
2016-04-18 10:59:24 -04:00
这里我们不再展示完整的`HeroDetailComponent`了。
我们要在它自己的页面中显示英雄详情,并且像我们在仪表盘中所做的那样路由到它。
2015-12-23 12:42:57 -05:00
But we'll throw in a small twist for variety.
When the user selects a hero from the list, we *won't* go to the detail page.
We'll show a *mini-detail* on *this* page instead and make the user click a button to navigate to the *full detail *page.
2016-04-18 10:59:24 -04:00
但是,我们要做一点小小的改动。
当用户从这个列表中选择一个英雄时,我们 *不会* 再跳转到详情页。
而是在本页中显示一个 *Mini版英雄详情* ,并且让用户点击一个按钮,来导航到 *完整版英雄详情* 页。
2015-12-23 12:42:57 -05:00
### Add the *mini-detail*
2016-04-18 10:59:24 -04:00
### 添加 *Mini版英雄详情*
2015-12-23 12:42:57 -05:00
Add the following HTML fragment at the bottom of the template where the `<my-hero-detail>` used to be:
2016-04-18 10:59:24 -04:00
在模板底部原来放`<my-hero-detail>`的地方添加下列HTML片段:
2015-12-23 12:42:57 -05:00
+makeExample('toh-5/ts/app/heroes.component.html','mini-detail')(format=".")
:marked
After clicking a hero, the user should see something like this below the hero list:
2016-04-18 10:59:24 -04:00
点击一个英雄,用户将会在英雄列表的下方看到这些:
2015-12-23 12:42:57 -05:00
figure.image-display
2016-04-18 10:59:24 -04:00
img(src='/resources/images/devguide/toh/mini-hero-detail.png' alt="Mini版英雄详情" height="70")
2015-12-23 12:42:57 -05:00
:marked
### Format with the *UpperCasePipe*
2016-04-18 10:59:24 -04:00
### 使用 *UpperCasePipe* 格式化
2015-12-23 12:42:57 -05:00
2016-03-08 07:53:01 -05:00
Notice that the hero's name is displayed in CAPITAL LETTERS. That's the effect of the `UpperCasePipe`
2015-12-23 12:42:57 -05:00
that we slipped into the interpolation binding. Look for it right after the pipe operator, ( | ).
2016-04-18 10:59:24 -04:00
注意,英雄的名字全被显示成大写字母。那是 `UpperCasePipe`的效果,借助它,我们能插手“插值表达式绑定”的过程。去管道操作符 ( | ) 后面找它。
2015-12-23 12:42:57 -05:00
+makeExample('toh-5/ts/app/heroes.component.html','pipe')(format=".")
:marked
Pipes are a good way to format strings, currency amounts, dates and other display data.
Angular ships with several pipes and we can write our own.
2016-04-18 10:59:24 -04:00
管道擅长做下列工作:格式化字符串、金额、日期和其它显示数据。
Angular自带了好几个管道, 并且我们还可以写自己的管道。
2015-12-23 12:42:57 -05:00
.l-sub-section
:marked
Learn about pipes in the [Pipes](../guide/pipes.html) chapter.
2016-04-18 10:59:24 -04:00
要学习关于管道的更多知识,参见[管道](../guide/pipes.html)一章。
2015-12-23 12:42:57 -05:00
:marked
### Move content out of the component file
2016-04-18 10:59:24 -04:00
### 把内容移出组件文件
2015-12-23 12:42:57 -05:00
We are not done. We still have to update the component class to support navigation to the
`HeroDetailComponent` when the user clicks the *View Details* button.
2016-04-18 10:59:24 -04:00
还没完呢。在用户点击 *查看详情* 按钮时,要让他能导航到 `HeroDetailComponent`,我们仍然不得不修改组件类。
2015-12-23 12:42:57 -05:00
This component file is really big. Most of it is either template or CSS styles.
It's difficult to find the component logic amidst the noise of HTML and CSS.
2016-04-18 10:59:24 -04:00
这个组件文件太大了。它大部分都是模板或css样式。
要想在HTML和CSS的噪音中找出组件的工作逻辑太难了。
2015-12-23 12:42:57 -05:00
Let's migrate the template and the styles to their own files before we make any more changes:
2016-04-18 10:59:24 -04:00
在做更多修改之前,我们先把模板和样式移到它们自己的文件中去:
2016-04-20 08:07:39 -04:00
1. *Cut-and-paste* the template contents into a new `heroes.component.html` file.
2016-04-18 10:59:24 -04:00
1. *剪切并粘贴* 模板内容到新的`heroes.component.html`文件。
2016-04-20 08:07:39 -04:00
1. *Cut-and-paste* the styles contents into a new `heroes.component.css` file.
2016-04-18 10:59:24 -04:00
1. *剪切并粘贴* 样式内容到新的`heroes.component.css`文件。
2016-04-20 08:07:39 -04:00
1. *Set* the component metadata's `templateUrl` and `styleUrls` properties to refer to both files.
2016-04-18 10:59:24 -04:00
1. *设置* 组件元数据的`templateUrl`和`styleUrls`属性,来分别引用这两个文件。
2015-12-23 12:42:57 -05:00
The revised component data looks like this:
2016-04-18 10:59:24 -04:00
修改过的组件数据是这样的:
+makeExample('toh-5/ts/app/heroes.component.ts', 'metadata', 'app/heroes.component.ts (修改过的元数据)')(format=".")
2015-12-23 12:42:57 -05:00
:marked
Now we can see what's going on as we update the component class along the same lines as the dashboard:
2016-04-18 10:59:24 -04:00
现在,我们一下就明白该怎么像仪表盘中那样更新组件类了:
2016-04-20 08:07:39 -04:00
1. Import the `router`
2016-04-18 10:59:24 -04:00
1. 导入`router`
2016-04-20 08:07:39 -04:00
1. Inject the `router` in the constructor (along with the `HeroService`)
2016-04-18 10:59:24 -04:00
1. 把`router`注入到构造函数中(就像`HeroService`那样)
2016-04-20 08:07:39 -04:00
1. Implement the `gotoDetail` method by calling the `router.navigate` method
with a two-part 'HeroDetail' *link parameters array*.
2016-04-18 10:59:24 -04:00
1. 实现`gotoDetail`方法:以`HeroDetail`和 *链接参数数组* 为参数调用`router.navigate`方法。
2015-12-23 12:42:57 -05:00
Here's the revised component class:
2016-04-18 10:59:24 -04:00
下面是修改过的组件类:
+makeExample('toh-5/ts/app/heroes.component.ts', 'class', 'app/heroes.component.ts (类)')
2015-12-23 12:42:57 -05:00
:marked
Refresh the browser and start clicking.
We can navigate around the app, from the dashboard to hero details and back,
for heroes list to the mini-detail to the hero details and back to the heroes again.
We can jump back and forth between the dashboard and the heroes.
2016-04-18 10:59:24 -04:00
刷新浏览器,并且开始点击。
我们能在应用中导航: 从仪表盘到英雄详情再回来, 从英雄列表到Mini版英雄详情到英雄详情, 然后再回到英雄列表。
我们可以在仪表盘和英雄列表之间跳来跳去。
2015-12-23 12:42:57 -05:00
We've met all of the navigational requirements that propelled this chapter.
2016-04-18 10:59:24 -04:00
我们已经达成了本章最初设定的所有导航需求。
2015-12-23 12:42:57 -05:00
.l-main-section
:marked
## Styling the App
2016-04-18 10:59:24 -04:00
## 美化本应用
2015-12-23 12:42:57 -05:00
The app is functional but pretty ugly.
Our creative designer team provided some CSS files to make it look better.
2016-04-18 10:59:24 -04:00
应用的功能已经正常了,但还太丑。
我们富有创意的设计师团队提供了一些CSS文件, 能让它更好看一些。
2015-12-23 12:42:57 -05:00
### A Dashboard with Style
2016-04-18 10:59:24 -04:00
### 具有样式的仪表盘
2015-12-23 12:42:57 -05:00
The designers think we should display the dashboard heroes in a row of rectangles.
They've given us ~60 lines of CSS for this purpose including some simple media queries for responsive design.
2016-04-18 10:59:24 -04:00
设计师认为我们应该把仪表盘的英雄们显示在一排方块中。
他们给了我们大约60行CSS来实现它, 包括一些简单的媒体查询语句以实现响应式设计。
2015-12-23 12:42:57 -05:00
If we paste these ~60 lines into the component `styles` metadata,
they'll completely obscure the component logic.
Let's not do that. It's easier to edit CSS in a separate `*.css` file anyway.
2016-04-18 10:59:24 -04:00
如果我们把这60来行CSS粘贴到组件元数据的`styles`中,它们会完全淹没组件的工作逻辑。
不能那么做。在一个独立的`*.css`文件中编辑CSS当然会更简单。
2015-12-23 12:42:57 -05:00
Add a `dashboard.component.css` file to the `app` folder and reference
that file in the component metadata's `styleUrls` array property like this:
2016-04-18 10:59:24 -04:00
把`dashboard.component.css`文件添加到`app`目录下,并且在组件元数据的`styleUrls`数组属性中引用它。就像这样:
2015-12-23 12:42:57 -05:00
+makeExample('toh-5/ts/app/dashboard.component.ts', 'css', 'app/dashboard.component.ts (styleUrls)')(format=".")
:marked
.l-sub-section
:marked
The `styleUrls` property is an array of style file names (with paths).
We could list multiple style files from different locations if we needed them.
2016-03-08 18:09:31 -05:00
As with `templateUrl`, we must specify the path _all the way back to the application root_.
2016-04-18 10:59:24 -04:00
`styleUrls`属性是一个由样式文件的文件名(包括路径)组成的数组。
如果需要,我们还可以列出来自多个不同位置的样式文件。
和`templateUrl`一样,我们必须指定 _相对于此应用根目录_ 的路径。
2015-12-23 12:42:57 -05:00
:marked
### Stylish Hero Details
2016-04-18 10:59:24 -04:00
### 美化英雄详情
2015-12-23 12:42:57 -05:00
The designers also gave us CSS styles specifically for the `HeroDetailComponent`.
2016-04-18 10:59:24 -04:00
设计师还给了我们`HeroDetailComponent`特有的CSS风格。
2015-12-23 12:42:57 -05:00
Add a `hero-detail.component.css` to the `app` folder and refer to that file inside
the `styleUrls` array as we did for `DashboardComponent`.
2016-04-18 10:59:24 -04:00
在`app`目录下添加`hero-detail.component.css`文件,并且在`styleUrls`数组中引用它 —— 就像当初在`DashboardComponent`中做过的那样。
2015-12-23 12:42:57 -05:00
Here's the content for the aforementioned component CSS files.
2016-04-18 10:59:24 -04:00
上述组件的CSS文件内容如下:
2015-12-23 12:42:57 -05:00
+makeTabs(
`toh-5/ts/app/hero-detail.component.css,
toh-5/ts/app/dashboard.component.css`,
null,
`app/hero-detail.component.css,
app/dashboard.component.css`)
:marked
### Style the Navigation Links
2016-04-18 10:59:24 -04:00
### 美化导航链接
2015-12-23 12:42:57 -05:00
The designers gave us CSS to make the navigation links in our `AppComponent` look more like selectable buttons.
We cooperated by surrounding those links in `<nav>` tags.
2016-04-18 10:59:24 -04:00
设计师还给了我们一些CSS, 用于让`AppComponent`中的导航链接看起来更像可被选择的按钮。
要想让它们协同工作,我们只需要把那些链接包含在`<nav>`标签中。
2015-12-23 12:42:57 -05:00
Add a `app.component.css` file to the `app` folder with the following content.
2016-04-18 10:59:24 -04:00
在`app`目录下添加一个`app.component.css`文件,内容如下:
+makeExample('toh-5/ts/app/app.component.css', 'css', 'app/app.component.css (导航样式)')
2015-12-23 12:42:57 -05:00
.l-sub-section
:marked
**The *router-link-active* class**
2016-04-18 10:59:24 -04:00
** *router-link-active* 类**
2015-12-23 12:42:57 -05:00
The Angular Router adds the `router-link-active` class to the HTML navigation element
whose route matches the active route. All we have to do is define the style for it. Sweet!
2016-04-18 10:59:24 -04:00
Angular路由器会为与当前激活路由匹配的路由所在的导航元素加上`router-link-active`类。
我们唯一要做的就是为它(`.router-link-active`类)定义样式。真好!
2015-12-23 12:42:57 -05:00
:marked
Set the `AppComponent`’ s `styleUrls` property to this CSS file.
2016-04-18 10:59:24 -04:00
设置`AppComponent`的`styleUrls`属性, 指向这个CSS文件。
2015-12-23 12:42:57 -05:00
+makeExample('toh-5/ts/app/app.component.ts','style-urls', 'app/app.component.ts (styleUrls)')(format=".")
:marked
### Global application styles
2016-04-18 10:59:24 -04:00
### 应用的全局样式
2015-12-23 12:42:57 -05:00
When we add styles to a component, we're keeping everything a component needs
— HTML, the CSS, the code — together in one convenient place.
It's pretty easy to package it all up and re-use the component somewhere else.
2016-04-18 10:59:24 -04:00
当我们把样式添加到组件中时,我们假定组件所需的一切 —— HTML、CSS、程序代码 —— 都在紧邻的地方。
这样,把它们打包在一起并在别的组件中复用它都会很容易。
2015-12-23 12:42:57 -05:00
We can also create styles at the *application level* outside of any component.
2016-04-18 10:59:24 -04:00
我们也可以在应用中所有组件之外的地方创建样式。
2015-12-23 12:42:57 -05:00
Our designers provided some basic styles to apply to elements across the entire app.
Add the following to a new file named `styles.css` in the root folder.
2016-04-18 10:59:24 -04:00
我们的设计师提供了一组基础样式,这些样式适用的元素横跨整个应用。
把下面这个名叫`styles.css`的新文件添加到根目录中:
+makeExample('toh-5/ts/styles.1.css', '', 'styles.css (应用级样式)')(format=".")
2015-12-23 12:42:57 -05:00
:marked
Reference this stylesheet within the `index.html` in the traditional manner.
2016-04-18 10:59:24 -04:00
用传统的方式,在`index.html`中引用这个样式表。
2015-12-23 12:42:57 -05:00
+makeExample('toh-5/ts/index.html','css', 'index.html (link ref)')(format=".")
:marked
Look at the app now. Our dashboard, heroes, and navigation links are styling!
2016-04-18 10:59:24 -04:00
看看现在的应用!我们的仪表盘、英雄列表和导航链接都漂亮多了!
2015-12-23 12:42:57 -05:00
figure.image-display
2016-04-18 10:59:24 -04:00
img(src='/resources/images/devguide/toh/dashboard-top-heroes.png' alt="查看导航栏")
2015-12-23 12:42:57 -05:00
.l-main-section
:marked
## Application structure and code
2016-04-18 10:59:24 -04:00
## 应用结构和代码
2015-12-23 12:42:57 -05:00
Review the sample source code [in the live example for this chapter](/resources/live-examples/toh-5/ts/plnkr.html).
Verify that we have the following structure:
2016-04-18 10:59:24 -04:00
在[本章的鲜活范例](/resources/live-examples/toh-5/ts/plnkr.html)中回顾范例代码。请验证一下我们已经有了下列结构:
2015-12-23 12:42:57 -05:00
.filetree
.file angular2-tour-of-heroes
.children
.file app
.children
.file app.component.ts
.file app.component.css
.file dashboard.component.css
.file dashboard.component.html
.file dashboard.component.ts
.file hero.ts
.file hero-detail.component.css
.file hero-detail.component.html
.file hero-detail.component.ts
.file hero.service.ts
.file heroes.component.css
.file heroes.component.html
.file heroes.component.ts
.file main.ts
.file mock-heroes.ts
2016-02-11 18:08:06 -05:00
.file node_modules ...
.file typings ...
2015-12-23 12:42:57 -05:00
.file index.html
.file package.json
2016-02-27 16:48:24 -05:00
.file styles.css
2015-12-23 12:42:57 -05:00
.file tsconfig.json
2016-02-11 18:08:06 -05:00
.file typings.json
2015-12-23 12:42:57 -05:00
:marked
.l-main-section
:marked
## Recap
2016-04-18 10:59:24 -04:00
## 总结
2015-12-23 12:42:57 -05:00
### The Road Behind
2016-04-18 10:59:24 -04:00
### 走过的路
2016-03-15 08:24:50 -04:00
We travelled a great distance in this chapter.
2016-04-18 10:59:24 -04:00
在本章中,我们往前走了很远:
2016-04-20 08:07:39 -04:00
- We added the Angular *Component Router* to navigate among different components.
2016-04-18 10:59:24 -04:00
- 我们添加了Angular *组件路由器* 在各个不同的组件之间导航。
2016-04-20 08:07:39 -04:00
- We learned how to create router links to represent navigation menu items
2016-04-18 10:59:24 -04:00
- 我们学会了如何创建路由链接来表示导航栏的菜单项。
2016-04-20 08:07:39 -04:00
- We used router parameters to navigate to the details of user selected hero
2016-04-18 10:59:24 -04:00
- 我们使用路由参数来导航到用户所选的英雄详情。
2016-04-20 08:07:39 -04:00
- We shared the `HeroService` among multiple components
2016-04-18 10:59:24 -04:00
- 我们在多个组件之间共享了`HeroService`服务。
2016-04-20 08:07:39 -04:00
- We moved HTML and CSS out of the component file and into their own files.
2016-04-18 10:59:24 -04:00
- 我们把HTML和CSS从组件中移出来, 放到它们自己的文件中去。
2016-04-20 08:07:39 -04:00
- We added the `uppercase` pipe to format data
2016-04-18 10:59:24 -04:00
- 我们添加了一个`uppercase`管道,来格式化数据。
2015-12-23 12:42:57 -05:00
### The Road Ahead
2016-04-18 10:59:24 -04:00
### 前方的路
2015-12-23 12:42:57 -05:00
We have much of the foundation we need to build an application.
We're still missing a key piece: remote data access.
2016-04-18 10:59:24 -04:00
我们有了很多用于构建应用的基石。
但我们仍然缺少很关键的一部分:远程数据存取。
2015-12-23 12:42:57 -05:00
In a forthcoming tutorial chapter,
2016-04-17 11:31:22 -04:00
we’ ll replace our mock data with data retrieved from a server using http.
2016-04-18 10:59:24 -04:00
在即将到来的章节中, 我们将从硬编码模拟数据改为使用http服务从服务器获取数据。