- var _example = 'toh-5';
block includes
include ../_util-fns
- var _appRoutingTsVsAppComp = 'app.module.ts'
- var _RoutesVsAtRouteConfig = 'Routes'
- var _RouterModuleVsRouterDirectives = 'RouterModule'
- var _redirectTo = 'redirectTo'
:marked
We received new requirements for our Tour of Heroes application:
我们收到了《英雄指南》的一些新需求:
* Add a *Dashboard* view.
添加一个*仪表盘*视图。
* Navigate between the *Heroes* and *Dashboard* views.
在*英雄列表*和*仪表盘*视图之间导航。
* Clicking on a hero in either view navigates to a detail view of the selected hero.
无论在哪个视图中点击一个英雄,都会导航到该英雄的详情页。
* Clicking a *deep link* in an email opens the detail view for a particular hero.
在邮件中点击一个*深链接*,会直接打开一个特定英雄的详情视图。
When we’re done, users will be able to navigate the app like this:
完成时,用户就能像这样在应用中导航:
figure.image-display
img(src='/resources/images/devguide/toh/nav-diagram.png' alt="查看导航")
:marked
We'll add Angular’s *Router* to our app to satisfy these requirements.
我们将把 Angular *路由器*加入应用中,以满足这些需求。
(译注:硬件领域中的路由器是用来帮你找到另一台网络设备的,而这里的路由器用于帮你找到一个组件)
.l-sub-section
:marked
The [Routing and Navigation](../guide/router.html) chapter covers the router
in more detail than we will in this tutorial.
更多信息,见[路由和导航](../guide/router.html)。
:marked
Run the
providers
中移除HeroService
:marked
Go back to the `HeroesComponent` and **remove the `HeroService`** from its `providers` array.
We are *promoting* this service from the `HeroesComponent` to the root `NgModule`.
We ***do not want two copies*** of this service at two different levels of our app.
回到`HeroesComponent`,并从`providers`数组中**移除`HeroService`**。
把它从`HeroesComponent`*提升*到根`NgModule`中。
我们不希望在应用的两个不同层次上存在它的***两个副本***。
: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.
应用仍然在运行,并显示着英雄列表。
我们把`AppComponent`重构成了一个新的`AppComponent`和`HeroesComponent`,它们工作得很好!
我们毫发无损的完成了这次重构。
:marked
## Add Routing
## 添加路由
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.
我们已准备好开始下一步。
我们希望在用户点击按钮之后才显示英雄列表,而不是自动显示。
换句话说,我们希望“导航”到英雄列表。
We'll need the Angular *Router*.
我们需要 Angular *路由器*。
block angular-router
:marked
The Angular router is an external, optional Angular NgModule called `RouterModule`.
The router is a combination of multiple provided services (`RouterModule`),
multiple directives (`RouterOutlet, RouterLink, RouterLinkActive`),
and a configuration (`Routes`). We'll configure our routes first.
Angular 路由器是一个可选的外部 Angular NgModule,名叫`RouterModule`。
路由器包含了多种服务(`RouterModule`)、多种指令(`RouterOutlet、RouterLink、RouterLinkActive`)、
和一套配置(`Routes`)。我们将先配置路由。
:marked
a#configure-routes
block router-config-intro
:marked
### Configure routes
### 配置路由
Our application doesn't have any routes yet.
We'll start by creating a configuration for the application routes.
本应用还没有路由。我们来为应用的路由新建一个配置。
:marked
*Routes* tell the router which views to display when a user clicks a link or
pastes a URL into the browser address bar.
*路由*告诉路由器,当用户点击链接或者把 URL 粘贴到浏览器地址栏时,应该显示哪个视图。
Let's define our first route as a route to the heroes component:
我们的第一个路由是指向`HeroesComponent`的。
- var _file = _docsFor == 'dart' ? 'app.component.ts' : 'app.module.2.ts'
+makeExcerpt('src/app/' + _file + ' (heroes route)', 'heroes')
- var _are = _docsFor == 'dart' ? 'takes' : 'are'
- var _routePathPrefix = _docsFor == 'dart' ? '/' : ''
:marked
The `!{_RoutesVsAtRouteConfig}` !{_are} !{_an} !{_array} of *route definitions*.
We have only one route definition at the moment but rest assured, we'll add more.
这个`Routes`是一个*路由定义*的数组。
此时,我们只有一个路由定义,但别急,后面还会添加更多。
This *route definition* has the following parts:
*路由定义*包括以下部分:
- **path**: the router matches this route's path to the URL in the browser address bar (`!{_routePathPrefix}heroes`).
**path**: 路由器会用它来匹配浏览器地址栏中的地址,如`!{_routePathPrefix}heroes`。
- **component**: the component that the router should create when navigating to this route (`HeroesComponent`).
**component**: 导航到此路由时,路由器需要创建的组件(`HeroesComponent`)。
.l-sub-section
:marked
Learn more about defining routes with `!{_RoutesVsAtRouteConfig}` in the [Routing](../guide/router.html) chapter.
关于`Routes`定义的更多信息,见[路由](../guide/router.html)。
+ifDocsFor('ts|js')
:marked
### Make the router available
### 让路由器可用
We've setup the initial route configuration. Now we'll add it to our `AppModule`.
We'll add our configured `RouterModule` to the `AppModule` imports !{_array}.
我们设置了初始路由配置。现在把它添加到`AppModule`里。把配置好的`RouterModule`添加到`AppModule`的`imports`数组中。
+makeExcerpt('src/app/app.module.2.ts (app routing)', '')
.l-sub-section
:marked
We use the `forRoot` method because we're providing a configured router at the _root_ of the application.
The `forRoot` method gives us the Router service providers and directives needed for routing, and
performs the initial navigation based on the current browser URL.
这里使用了`forRoot`方法,因为我们在应用*根部*提供配置的路由器。
`forRoot`方法提供了路由需要的路由服务提供商和指令,并基于当前浏览器 URL 初始化导航。
- var _heroesRoute = _docsFor == 'dart' ? "'Heroes'" : 'heroes'
:marked
### Router Outlet
### 路由插座(Outlet)
If we paste the path, `/heroes`, into the browser address bar,
the router should match it to the `!{_heroesRoute}` route and display the `HeroesComponent`.
But where?
如果我们把路径`/heroes`粘贴到浏览器的地址栏,路由器会匹配到`'Heroes'`路由,并显示`HeroesComponent`组件。
但问题是,该把它显示在哪呢?
We have to ***tell it where*** by adding a `