From 8baa278399bd03a7860718c0746cd4e96f176582 Mon Sep 17 00:00:00 2001 From: Zhicheng Wang Date: Sat, 6 May 2017 21:46:57 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BF=BB=E8=AF=91=E4=BA=86=E4=B8=80=E9=83=A8?= =?UTF-8?q?=E5=88=86=E8=B7=AF=E7=94=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/docs/ts/latest/guide/router.jade | 422 +++++++++++++++++------- 1 file changed, 298 insertions(+), 124 deletions(-) diff --git a/public/docs/ts/latest/guide/router.jade b/public/docs/ts/latest/guide/router.jade index 26eb93ce7b..779e782774 100644 --- a/public/docs/ts/latest/guide/router.jade +++ b/public/docs/ts/latest/guide/router.jade @@ -371,7 +371,7 @@ include ../../../_includes/_see-addr-bar .l-main-section - + a#basics :marked ## The Basics @@ -517,7 +517,7 @@ a#basics-router-outlet _after_ a `RouterOutlet` that you've placed in the host view's HTML. 有了这份配置,当本应用在浏览器中的URL变为`/heroes`时,路由器就会匹配到`path`为`heroes`的`Route`,并在宿主视图中的*`RouterOutlet`*之后显示`HeroListComponent`组件。 - + code-example(language="html"). <router-outlet></router-outlet> <!-- Routed views go here --> @@ -599,7 +599,9 @@ a#basics-summary 下面是一些*路由器*中的关键词汇及其含义: -style td, th {vertical-align: top} +style + td, th { vertical-align: top } + table tr th @@ -818,7 +820,7 @@ figure.image-display Select one hero and the app takes you to a hero editing screen. 选择其中之一,该应用就会把我们带到此英雄的编辑页面。 - + figure.image-display img(src='/resources/images/devguide/router/hero-detail.png' alt="Crisis Center Detail" width="250") @@ -839,7 +841,7 @@ figure.image-display Now click the *Crisis Center* link for a list of ongoing crises. 现在,点击*危机中心*链接,前往*危机*列表页。 - + figure.image-display img(src='/resources/images/devguide/router/crisis-center-list.png' alt="Crisis Center List" width="250") @@ -855,7 +857,7 @@ figure.image-display 修改危机的名称。 注意,危机列表中的相应名称**并没有**修改。 - + figure.image-display img(src='/resources/images/devguide/router/crisis-center-detail.png' alt="Crisis Center Detail" width="250") @@ -910,7 +912,7 @@ figure.image-display Begin with a simple version of the app that navigates between two empty views. 开始本应用的一个简版,它在两个空路由之间导航。 - + figure.image-display img(src='/resources/images/devguide/router/router-1-anim.gif' alt="App in action" width="250") @@ -1219,7 +1221,7 @@ a#wildcard To test this feature, add a button with a `RouterLink` to the `HeroListComponent` template and set the link to `"/sidekicks"`. 要测试本特性,请往`HeroListComponent`的模板中添加一个带`RouterLink`的按钮,并且把它的链接设置为`"/sidekicks"`。 - + +makeExcerpt('src/app/hero-list.component.ts') :marked @@ -1230,14 +1232,14 @@ a#wildcard Instead of adding the `"/sidekicks"` route, define a `wildcard` route instead and have it navigate to a simple `PageNotFoundComponent`. 不要添加`"/sidekicks"`路由,而是定义一个"通配符"路由,让它直接导航到`PageNotFoundComponent`组件。 - + +makeExcerpt('src/app/app.module.1.ts', 'wildcard') :marked Create the `PageNotFoundComponent` to display when users visit invalid URLs. 创建`PageNotFoundComponent`,以便在用户访问无效网址时显示它。 - + +makeExcerpt('src/app/not-found.component.ts (404 component)', '') :marked @@ -1422,21 +1424,21 @@ a#redirect 下面是当前里程碑中讨论过的文件列表: +makeTabs( - `router/ts/src/app/app.component.1.ts, - router/ts/src/app/app.module.1.ts, - router/ts/src/main.ts, - router/ts/src/app/hero-list.component.ts, - router/ts/src/app/crisis-list.component.ts, - router/ts/src/app/not-found.component.ts, - router/ts/src/index.html`, - ',,,,', - `app.component.ts, - app.module.ts, - main.ts, - hero-list.component.ts, - crisis-list.component.ts, - not-found.component.ts, - index.html`) +`router/ts/src/app/app.component.1.ts, +router / ts / src / app / app.module.1.ts, +router / ts / src / main.ts, +router / ts / src / app / hero - list.component.ts, +router / ts / src / app / crisis - list.component.ts, +router / ts / src / app / not - found.component.ts, +router / ts / src / index.html`, +',,,,', +`app.component.ts, +app.module.ts, +main.ts, +hero - list.component.ts, +crisis - list.component.ts, +not - found.component.ts, +index.html`) .l-main-section#routing-module :marked @@ -1505,7 +1507,7 @@ a#routing-refactor After these steps, the file should look like this. 做完这些之后,该文件变成了这样: - + +makeExample('src/app/app-routing.module.1.ts') :marked @@ -1515,7 +1517,7 @@ a#routing-refactor 接下来,修改`app.module.ts`文件,首先从`app-routing.module.ts`中导入新创建的`AppRoutingModule`, 然后把`imports`数组中的`RouterModule.forRoot`替换为`AppRoutingModule`。 - + +makeExample('src/app/app.module.2.ts') .l-sub-section :marked @@ -1757,7 +1759,7 @@ a#hero-routing-module Import the hero components from their new locations in the `src/app/heroes/` folder, define the two hero routes, and export the `HeroRoutingModule` class. - 从新位置`src/app/heroes/`目录中导入英雄相关的组件,定义两个英雄路由,并导出`HeroRoutingModule`类。 + 从新位置`src/app/heroes/`目录中导入英雄相关的组件,定义两个"英雄管理"路由,并导出`HeroRoutingModule`类。 Now that you have routes for the `Heroes` module, register them with the `Router` via the `RouterModule` _almost_ as you did in the `AppRoutingModule`. @@ -1780,7 +1782,7 @@ a#hero-routing-module 只在根模块`AppRoutingModule`中调用`RouterModule.forRoot`(如果在`AppModule`中注册应用的顶级路由,那就在`AppModule`中调用)。 在其它模块中,我们就必须调用**`RouterModule.forChild`**方法来注册附属路由。 - + a#adding-routing-module :marked ### Add the routing module to the _HeroesModule_ @@ -1806,7 +1808,7 @@ a#remove-duplicate-hero-routes :marked ### Remove duplicate hero routes - ### 移除重复的英雄路由 + ### 移除重复的"英雄管理"路由 The hero routes are currently defined in _two_ places: in the `HeroesRoutingModule`, by way of the `HeroesModule`, and in the `AppRoutingModule`. @@ -1832,57 +1834,87 @@ a#remove-duplicate-hero-routes +makeExcerpt('src/app/app-routing.module.2.ts (v2)', '') -a#merge-hero-routes +a#merge-hero-routes :marked ### Import hero module into AppModule - ### 把英雄模块导入到AppModule + ### 把"英雄管理"模块导入到AppModule The heroes feature module is ready, but the application doesn't know about the `HeroesModule` yet. Open `app.module.ts` and revise it as follows. - + 英雄这个特性模块已经就绪,但应用仍然不知道`HeroesModule`的存在。 + 打开`app.module.ts`,并按照下述步骤修改它。 Import the `HeroesModule` and add it to the `imports` array in the `@NgModule` metadata of the `AppModule`. + 导入`HeroesModule`并且把它加到根模块`APPModule`的`@NgModule`元数据中的`imports`数组中。 + Remove the `HeroListComponent` from the `AppModule`'s `declarations` because it's now provided by the `HeroesModule`. This is important. There can be only _one_ owner for a declared component. In this case, the `Heroes` module is the owner of the `Heroes` components and is making them available to components in the `AppModule` via the `HeroesModule`. + + 从`AppModule`的`declarations`中移除`HeroListComponent`,因为它现在已经改由`HeroesModule`提供了。 + 这一步很重要!因为一个组件只能声明在*一个*属主模块中。 + 这个例子中,`Heroes`模块就是`Heroes`组件的属主模块,而`AppModule`要通过导入`HeroesModule`才能使用这些组件。 As a result, the `AppModule` no longer has specific knowledge of the hero feature, its components, or its route details. You can evolve the hero feature with more components and different routes. That's a key benefit of creating a separate module for each feature area. + + 最终,`AppModule`不再了解那些特定于"英雄"特性的知识,比如它的组件、路由细节等。 + 我们可以让"英雄"特性独立演化,添加更多的组件或各种各样的路由。 + 这是我们为每个特性区创建独立模块后获得的核心优势。 After these steps, the `AppModule` should look like this: + + 经过这些步骤,`AppModule`变成了这样: +makeExample('src/app/app.module.3.ts','','src/app/app.module.ts') a#routing-module-order :marked ### Module import order matters + + ### 导入模块的顺序很重要 Look at the module `imports` array. Notice that the `AppRoutingModule` is _last_. Most importantly, it comes _after_ the `HeroesModule`. + + 看看该模块的`imports`数组。注意,`AppRoutingModule`是*最后一个*。最重要的是,它位于`HeroesModule`之后。 + +makeExample('src/app/app.module.3.ts','module-imports','src/app/app.module.ts (module-imports)')(format='.') :marked The order of route configuration matters. The router accepts the first route that matches a navigation request path. + + 路由配置的顺序很重要。 + 路由器会接受第一个匹配上导航所要求的路径的那个路由。 When all routes were in one `AppRoutingModule`, you put the default and [wildcard](#wildcard) routes last, after the `/heroes` route, so that the router had a chance to match a URL to the `/heroes` route _before_ hitting the wildcard route and navigating to "Page not found". + + 当所有路由都在同一个`AppRoutingModule`时,我们要把默认路由和[通配符路由](#wildcard)放在最后(这里是在`/heroes`路由后面), + 这样路由器才有机会匹配到`/heroes`路由,否则它就会先遇到并匹配上该通配符路由,并导航到"页面未找到"路由。 The routes are no longer in one file. They are distributed across two modules, `AppRoutingModule` and `HeroesRoutingModule`. + + 这些路由不再位于单一文件中。他们分布在两个不同的模块中:`AppRoutingModule`和`HeroesRoutingModule`。 Each routing module augments the route configuration _in the order of import_. If you list `AppRoutingModule` first, the wildcard route will be registered _before_ the hero routes. The wildcard route — which matches _every_ URL — will intercept the attempt to navigate to a hero route. + + 每个路由模块都会根据*导入的顺序*把自己的路由配置追加进去。 + 如果我们先列出了`AppRoutingModule`,那么通配符路由就会被注册在"英雄管理"路由*之前*。 + 通配符路由(它匹配*任意*URL)将会拦截住每一个到"英雄管理"路由的导航,因此事实上屏蔽了所有"英雄管理"路由。 .l-sub-section :marked @@ -1890,6 +1922,9 @@ a#routing-module-order a click of the heroes link results in "Page not found". Learn about inspecting the runtime router configuration [below](#inspect-config "Inspect the router config"). + + 反转路由模块的导入顺序,我们就会看到当点击英雄相关的链接时被导向了"页面未找到"路由。 + 要学习如何在运行时查看路由器配置,参见[稍后的内容](#inspect-config "Inspect the router config")。 a#route-def-with-parameter :marked @@ -1991,6 +2026,8 @@ a#route-parameters :marked ### Setting the route parameters in the list view + ### 在列表视图中设置路由参数 + After navigating to the `HeroDetailComponent`, you expect to see the details of the selected hero. You need *two* pieces of information: the routing path to the component and the hero's `id`. @@ -2027,9 +2064,8 @@ a#route-parameters a#activated-route :marked ### ActivatedRoute: the one-stop-shop for route information - - 每个路由都包含路径、数据参数、URL片段等很多信息。 - 所有这些信息都可以通过有路由器提供的一个叫[ActivatedRoute](../api/router/index/ActivatedRoute-interface.html)的服务提供商来获取。 + + ### ActivatedRoute:一站式获取路由信息 The route path and parameters are available through an injected router service called the [ActivatedRoute](../api/router/index/ActivatedRoute-interface.html). @@ -2089,6 +2125,8 @@ a#activated-route :marked Import the `switchMap` operator because you need it later to process the `Observable` route parameters. + + 这里导入`switchMap`操作符是因为我们稍后将会处理路由参数的可观察对象`Observable`。 +makeExcerpt('src/app/heroes/hero-detail.component.ts (switchMap operator import)', 'rxjs-operator-import') @@ -2112,14 +2150,21 @@ a#hero-detail-ctor Put this data access logic in the `ngOnInit` method rather than inside the constructor to improve the component's testability. Angular calls the `ngOnInit` method shortly after creating an instance of the `HeroDetailComponent` so the hero will be retrieved in time to use it. + + 把数据访问逻辑放进`ngOnInit`方法中,而不是构造函数中可以提升组件的可测试性。 + Angular会在创建完`HeroDetailComponent`的实例之后调用`ngOnInit`方法,因此该英雄会在即将使用时接收到。 Learn more about the `ngOnInit` method and other component lifecycle hooks in the [Lifecycle Hooks](lifecycle-hooks.html) guide. + + 要了解关于`ngOnInit`方法和其它组件生命周期钩子的更多知识,参见[生命周期钩子](lifecycle-hooks.html)一章。 +makeExcerpt('src/app/heroes/hero-detail.component.ts (ngOnInit)', 'ngOnInit') :marked Since the parameters are provided as an `Observable`, you use the `switchMap` operator to provide them for the `id` parameter by name and tell the `HeroService` to fetch the hero with that `id`. + + 由于参数是作为`Observable`提供的,所以我们得用`switchMap`操作符来根据名字取得`id`参数,并告诉`HeroService`来获取带有那个`id`的英雄。 The `switchMap` operator allows you to perform an action with the current value of the `Observable`, and map it to a new `Observable`. As with many `rxjs` operators, `switchMap` handles @@ -2181,13 +2226,23 @@ a#reuse :marked When subscribing to an observable in a component, you almost always arrange to unsubscribe when the component is destroyed. + 当在组件中订阅一个可观察对象时,我们通常总是要在组件销毁时取消这个订阅。 + There are a few exceptional observables where this is not necessary. The `ActivatedRoute` observables are among the exceptions. + + 但是也有少数例外情况不需要取消订阅。 + `ActivateRoute`中的各种可观察对象就是属于这种情况。 The `ActivatedRoute` and its observables are insulated from the `Router` itself. The `Router` destroys a routed component when it is no longer needed and the injected `ActivatedRoute` dies with it. + + `ActivateRoute`及其可观察对象都是由`Router`本身负责管理的。 + `Router`会在不再需要时销毁这个路由组件,而注入进去的`ActivateRoute`也随之销毁了。 Feel free to unsubscribe anyway. It is harmless and never a bad practice. + + 不过,我们仍然可以随意取消订阅,这不会造成任何损害,而且也不是一项坏的实践。 a#snapshot :marked @@ -2262,7 +2317,7 @@ a#nav-to-list as you do when navigating to the `HeroDetailComponent` in order to view the hero with *id*15: 如果想导航到`HeroDetailComponent`以对id为15的英雄进行查看并编辑,就要在路由的URL中使用[*路由参数*](#route-parameters)来指定*必要*参数值。 - + code-example(format="nocode"). localhost:3000/hero/15 @@ -2317,9 +2372,13 @@ figure.image-display a#optionally-selecting :marked ### Heroes list: optionally selecting a hero + + ### 英雄列表:选定一个英雄(也可不选) When navigating to the `HeroDetailComponent` you specified the _required_ `id` of the hero-to-edit in the *route parameter* and made it the second item of the [_link parameters array_](#link-parameters-array). + + 当导航到`HeroDetailComponent`时,我们可以在*路由参数*中指定一个所要编辑的英雄`id`,只要把它作为[链接参数数组](#link-parameters-array)中的第二个条目就可以了。 +makeExcerpt('src/app/heroes/hero-list.component.1.ts', 'link-parameters-array') @@ -2535,46 +2594,73 @@ a#route-animation First import `BrowserAnimationsModule`: 首先导入`BrowserAnimationsModule`: - + +makeExcerpt('src/app/app.module.ts', 'animations-module', 'src/app/app.module.ts (@NgModule imports excerpt)') :marked Create an `animations.ts` file in the root `src/app/` folder. The contents look like this: 在根目录`src/app/`下创建一个`animations.ts`。内容如下: - + +makeExcerpt('src/app/animations.ts', '', 'src/app/animations.ts') :marked This file does the following: + + 该文件做了如下工作: * Imports the animation symbols that build the animation triggers, control state, and manage transitions between states. + + 导入动画符号以构建动画触发器、控制状态并管理状态之间的过渡。 * Exports a constant named `slideInDownAnimation` set to an animation trigger named *`routeAnimation`*; animated components will refer to this name. + + 导出了一个名叫`slideInDownAnimation`的常量,并把它设置为一个名叫*`routeAnimation`的动画触发器。带动画的组件将会引用这个名字。 * Specifies the _wildcard state_ , `*`, that matches any animation state that the route component is in. + 指定了一个*通配符状态* —— `*`,它匹配该路由组件存在时的任何动画状态。 + * Defines two *transitions*, one to ease the component in from the left of the screen as it enters the application view (`:enter`), the other to animate the component down as it leaves the application view (`:leave`). + + 定义两个*过渡效果*,其中一个(`:enter`)在组件进入应用视图时让它从屏幕左侧缓动进入(ease-in),另一个(`:leave`)在组件离开应用视图时让它向下飞出。 You could create more triggers with different transitions for other route components. This trigger is sufficient for the current milestone. + + 我们可以为其它路由组件用不同的转场效果创建更多触发器。现在这个触发器已经足够当前的里程碑用了。 :marked Back in the `HeroDetailComponent`, import the `slideInDownAnimation` from `'./animations.ts`. Add the `HostBinding` decorator to the imports from `@angular/core`; you'll need it in a moment. + + 返回`HeroDetailComponent`,从`'./animations.ts`中导入`slideInDownAnimation`。 + 从`@angular/core`中导入`HostBinding`装饰器,我们很快就会用到它。 Add an `animations` array to the `@Component` metadata's that contains the `slideInDownAnimation`. + + 把一个包含`slideInDownAnimation`的`animations`数组添加到`@Component`的元数据中。 Then add three `@HostBinding` properties to the class to set the animation and styles for the route component's element. + + 然后把三个`@HostBinding`属性添加到类中以设置这个路由组件元素的动画和样式。 + +makeExcerpt('src/app/heroes/hero-detail.component.ts (host bindings)', 'host-bindings') :marked The `'@routeAnimation'` passed to the first `@HostBinding` matches the name of the `slideInDownAnimation` _trigger_, `routeAnimation`. Set the `routeAnimation` property to `true` because you only care about the `:enter` and `:leave` states. + + 传给了第一个`@HostBinding`的`'@routeAnimation'`匹配了`slideInDownAnimation`*触发器*的名字`routeAnimation`。 + 把`routeAnimation`属性设置为`true`,因为我们只关心`:enter`和`:leave`这两个状态。 The other two `@HostBinding` properties style the display and position of the component. + + 另外两个`@HostBinding`属性指定组建的外观和位置。 The `HeroDetailComponent` will ease in from the left when routed to and will slide down when navigating away. + + 当进入该路由时,`HeroDetailComponent`将会从左侧缓动进入屏幕,而离开路由时,将会向下划出。 .l-sub-section :marked @@ -2586,6 +2672,7 @@ a#route-animation a#milestone-3-wrap-up :marked ### Milestone 3 wrap up + ### 里程碑#3的总结 You've learned how to do the following: @@ -2640,30 +2727,30 @@ a#milestone-3-wrap-up .file tsconfig.json .file node_modules ... .file package.json - + :marked Here are the relevant files for this version of the sample application. 这里是当前版本的范例程序相关文件。 +makeTabs( - `router/ts/src/app/app.component.1.ts, - router/ts/src/app/app.module.3.ts, - router/ts/src/app/app-routing.module.2.ts, - router/ts/src/app/heroes/hero-list.component.ts, - router/ts/src/app/heroes/hero-detail.component.ts, - router/ts/src/app/heroes/hero.service.ts, - router/ts/src/app/heroes/heroes.module.ts, - router/ts/src/app/heroes/heroes-routing.module.ts`, - '', - `app.component.ts, - app.module.ts, - app-routing.module.ts, - hero-list.component.ts, - hero-detail.component.ts, - hero.service.ts, - heroes.module.ts, - heroes-routing.module.ts`) +`router/ts/src/app/app.component.1.ts, +router / ts / src / app / app.module.3.ts, +router / ts / src / app / app - routing.module.2.ts, +router / ts / src / app / heroes / hero - list.component.ts, +router / ts / src / app / heroes / hero - detail.component.ts, +router / ts / src / app / heroes / hero.service.ts, +router / ts / src / app / heroes / heroes.module.ts, +router / ts / src / app / heroes / heroes - routing.module.ts`, +'', +`app.component.ts, +app.module.ts, +app - routing.module.ts, +hero - list.component.ts, +hero - detail.component.ts, +hero.service.ts, +heroes.module.ts, +heroes - routing.module.ts`) a#milestone-4 .l-main-section @@ -2674,14 +2761,31 @@ a#milestone-4 It's time to add real features to the app's current placeholder crisis center. + 是时候往该应用的危机中心(现在是占位符)中添加一些真实的特性了。 + Begin by imitating the heroes feature: + 我们先从模仿"英雄管理"中的特性开始: + * Delete the placeholder crisis center file. + + 删除危机中心的占位文件。 + * Create an `app/crisis-center` folder. + + 创建`app/crisis-center`文件夹。 + * Copy the files from `app/heroes` into the new crisis center folder. + + 把`app/heroes`中的文件复制到新的危机中心文件夹。 + * In the new files, change every mention of "hero" to "crisis", and "heroes" to "crises". + 在这些新文件中,把每一个对"hero"替换为"crisis",并把"heroes"替换为"crises"。 + You'll turn the `CrisisService` into a purveyor of mock crises instead of mock heroes: + + 我们将会把`CrisisService`转换成模拟的危机列表,而不再是模拟的英雄列表: +makeExcerpt('src/app/crisis-center/crisis.service.ts', 'mock-crises') @@ -2689,6 +2793,9 @@ a#milestone-4 The resulting crisis center is a foundation for introducing a new concept—**child routing**. You can leave *Heroes* in its current state as a contrast with the *Crisis Center* and decide later if the differences are worthwhile. + + 最终的危机中心可以作为引入**子路由**这个新概念的基础。 + 我们把*英雄管理*保持在当前状态,以便和*危机中心*进行对比,以后再根据这些差异是否有价值来决定后续行动。 .alert.is-helpful :marked @@ -2696,18 +2803,40 @@ a#milestone-4 *Separation of Concerns* principle, changes to the *Crisis Center* won't affect the `AppModule` or any other feature's component. + + 遵循*关注点分离(Separation of Concerns)*原则, + 对*危机中心*的修改不会影响`AppModule`或其它特性模块中的组件。 + a#crisis-child-routes :marked ### A crisis center with child routes + + ### 带有子路由的危机中心 This section shows you how to organize the crisis center to conform to the following recommended pattern for Angular applications: + + 本节会展示如何组织危机中心,来满足Angular应用所推荐的模式: * Each feature area resides in its own folder. + + 把每个特性放在自己的目录中。 + * Each feature has its own Angular feature module. + + 每个特性都有自己的Angular特性模块。 + * Each area has its own area root component. + + 每个特性区都有自己的根组件。 + * Each area root component has its own router outlet and child routes. + + 每个特性区的根组件中都有自己的路由插座及其子路由。 + * Feature area routes rarely (if ever) cross with routes of other features. + + 特性区的路由很少(或完全不)与其它特性区的路由交叉。 If your app had many feature areas, the app component trees might look like this: @@ -2731,22 +2860,37 @@ a#child-routing-component :marked The `CrisisCenterComponent` has the following in common with the `AppComponent`: + `CrisisCenterComponent`和`AppComponent`有下列共同点: + * It is the *root* of the crisis center area, just as `AppComponent` is the root of the entire application. + + 它是危机中心特性区的*根*,正如`AppComponent`是整个应用的根。 + * It is a *shell* for the crisis management feature area, just as the `AppComponent` is a shell to manage the high-level workflow. + + 它是危机管理特性区的*壳*,正如`AppComponent`是管理高层工作流的壳。 Like most shells, the `CrisisCenterComponent` class is very simple, simpler even than `AppComponent`: it has no business logic, and its template has no links, just a title and `` for the crisis center child views. + + 就像大多数的壳一样,`CrisisCenterComponent`类也非常简单,甚至比`AppComponent`更简单: + 它没有业务逻辑,它的模板中没有链接,只有一个标题和用于放置危机中心的子视图的``。 Unlike `AppComponent`, and most other components, it _lacks a selector_. It doesn't _need_ one since you don't *embed* this component in a parent template, instead you use the router to *navigate* to it. + + 与`AppComponent`和大多数其它组件不同的是,它甚至都*没有指定选择器`selector`*。 + 它不*需要*选择器,因为我们不会把这个组件嵌入到某个父模板中,而是使用路由器*导航*到它。 a#child-route-config :marked ### Child route configuration + + ### 子路由配置 The `CrisisCenterComponent` is a *routing component* like the `AppComponent`. It has its own `RouterOutlet` and its own child routes. @@ -2816,6 +2960,8 @@ a#child-route-config 在路由树中每深入一步,我们就会在该路由的路径上添加一个斜线`/`(除非该路由的路径是*空的*)。 Apply that logic to navigation within the crisis center for which the parent path is `/crisis-center`. + + 如果把该逻辑应用到危机中心中的导航,那么父路径就是`/crisis-center`。 * To navigate to the `CrisisCenterHomeComponent`, the full URL is `/crisis-center` (`/crisis-center` + `''` + `''`). @@ -2829,7 +2975,7 @@ a#child-route-config The absolute URL for the latter example, including the `localhost` origin, is 本例子中包含站点部分的绝对URL,就是: - + code-example. localhost:3000/crisis-center/2 @@ -2840,9 +2986,11 @@ code-example. +makeExcerpt('src/app/crisis-center/crisis-center-routing.module.1.ts', '') -a#import-crisis-module +a#import-crisis-module :marked ### Import crisis center module into the *AppModule* routes + + ### 把危机中心模块导入到`AppModule`的路由中 As with the `HeroesModule`, you must add the `CrisisCenterModule` to the `imports` array of the `AppModule` _before_ the `AppRoutingModule`: @@ -2855,9 +3003,10 @@ a#import-crisis-module Remove the initial crisis center route from the `app-routing.module.ts`. The feature routes are now provided by the `HeroesModule` and the `CrisisCenter` modules. + 我们还从`app.routing.ts`中移除了危机中心的初始路由。我们的路由现在是由`HeroesModule`和`CrisisCenter`特性模块提供的。 + The `app-routing.module.ts` file retains the top-level application routes such as the default and wildcard routes. - 我们还从`app.routing.ts`中移除了危机中心的初始路由。我们的路由现在是由`HeroesModule`和`CrisisCenter`特性模块提供的。 我们将保持`app.routing.ts`文件中只有通用路由,本章稍后会讲解它。 +makeExcerpt('src/app/app-routing.module.3.ts (v3)') @@ -2871,44 +3020,69 @@ a#relative-navigation While building out the crisis center feature, you navigated to the crisis detail route using an **absolute path** that begins with a _slash_. + + 虽然构建出了危机中心特性区,我们却仍在使用以斜杠开头的**绝对路径**来导航到危机详情的路由。 The router matches such _absolute_ paths to routes starting from the top of the route configuration. + + 路由器会从路由配置的顶层来匹配像这样的*绝对路径*。 You could continue to use absolute paths like this to navigate inside the *Crisis Center* feature, but that pins the links to the parent routing structure. If you changed the parent `/crisis-center` path, you would have to change the link parameters array. + + 我们固然可以继续像*危机中心*特性区一样使用绝对路径,但是那样会把链接钉死在特定的父路由结构上。 + 如果我们修改了父路径`/crisis-center`,那就不得不修改每一个链接参数数组。 You can free the links from this dependency by defining paths that are **relative** to the current URL segment. Navigation _within_ the feature area remains intact even if you change the parent route path to the feature. + + 通过改成定义*相对于*当前URL的路径,我们可以把链接从这种依赖中解放出来。 + 当我们修改了该特性区的父路由路径时,该特性区*内部*的导航仍然完好无损。 Here's an example: + + 例子如下: .l-sub-section :marked The router supports directory-like syntax in a _link parameters list_ to help guide route name lookup: + + 在*链接参数数组*中,路由器支持"目录式"语法来指导我们如何查询路由名: `./` or `no leading slash` is relative to the current level. + + `./`或`无前导斜线`形式是相对于当前级别的。 `../` to go up one level in the route path. + + `../`会回到当前路由路径的上一级。 You can combine relative navigation syntax with an ancestor path. If you must navigate to a sibling route, you could use the `../` convention to go up one level, then over and down the sibling route path. + + 我们可以把相对导航语法和一个祖先路径组合起来用。 + 如果不得不导航到一个兄弟路由,我们可以用`../`来回到上一级,然后进入兄弟路由路径中。 :marked To navigate a relative path with the `Router.navigate` method, you must supply the `ActivatedRoute` to give the router knowledge of where you are in the current route tree. + 用`Router.navigate`方法导航到相对路径时,我们必须提供当前的`ActivatedRoute`,来让路由器知道我们现在位于路由树中的什么位置。 + After the _link parameters array_, add an object with a `relativeTo` property set to the `ActivatedRoute`. The router then calculates the target URL based on the active route's location. - - “重定向(redirect)路由”需要一个`pathMatch`属性来告诉路由器如何把URL和路由中的路径进行匹配。 - 本应用中,路由器应该只有在*完整的URL*匹配`''`时才选择指向`CrisisListComponent`的路由,因此,我们把`pathMatch`的值设置为`'full'`。 + + 在*链接参数数组*中,添加一个带有`relativeTo`属性的对象,并把它设置为当前的`ActivatedRoute`。 + 这样路由器就会基于当前激活路由的位置来计算出目标URL。 .l-sub-section :marked **Always** specify the complete _absolute_ path when calling router's `navigateByUrl` method. + + 当调用路由器的`navigateByUrl`时,**总是**要指定完整的*绝对路径*。 a#nav-to-crisis :marked @@ -2992,11 +3166,11 @@ figure.image-display Here's the component and its template: +makeTabs( - `router/ts/src/app/compose-message.component.ts, - router/ts/src/app/compose-message.component.html`, - null, - `src/app/compose-message.component.ts, - src/app/compose-message.component.html`) +`router/ts/src/app/compose-message.component.ts, +router / ts / src / app / compose - message.component.html`, +null, +`src/app/compose-message.component.ts, +src / app / compose - message.component.html`) :marked It looks about the same as any other component you've seen in this guide. @@ -3056,7 +3230,7 @@ a#secondary-route-navigation you should see something like the following URL in the browser address bar. code-example. - http://.../crisis-center(popup:compose) + http://.../crisis-center(popup:compose) :marked The interesting part of the URL follows the `...`: @@ -3068,7 +3242,7 @@ code-example. Click the _Heroes_ link and look at the URL again. code-example. - http://.../heroes(popup:compose) + http://.../heroes(popup:compose) :marked The primary navigation part has changed; the secondary route is the same. @@ -3270,18 +3444,18 @@ a#can-activate-guard 管理特性模块包含`AdminComponent`,它用于在特性模块内的仪表盘路由以及两个尚未完成的用于管理危机和英雄的组件之间进行路由。 +makeTabs( - `router/ts/src/app/admin/admin-dashboard.component.1.ts, - router/ts/src/app/admin/admin.component.ts, - router/ts/src/app/admin/admin.module.ts, - router/ts/src/app/admin/manage-crises.component.ts, - router/ts/src/app/admin/manage-heroes.component.ts +`router/ts/src/app/admin/admin-dashboard.component.1.ts, +router / ts / src / app / admin / admin.component.ts, +router / ts / src / app / admin / admin.module.ts, +router / ts / src / app / admin / manage - crises.component.ts, +router / ts / src / app / admin / manage - heroes.component.ts `, - null, - `src/app/admin/admin-dashboard.component.ts, - src/app/admin/admin.component.ts, - src/app/admin/admin.module.ts, - src/app/admin/manage-crises.component.ts, - src/app/admin/manage-heroes.component.ts +null, +`src/app/admin/admin-dashboard.component.ts, +src / app / admin / admin.component.ts, +src / app / admin / admin.module.ts, +src / app / admin / manage - crises.component.ts, +src / app / admin / manage - heroes.component.ts `) .l-sub-section @@ -3302,7 +3476,7 @@ a#can-activate-guard +makeExcerpt('src/app/admin/admin-routing.module.1.ts (admin routing)', 'admin-routes') -a#component-less-route +a#component-less-route :marked ### Component-less route: grouping routes without a component @@ -3465,14 +3639,14 @@ a#add-login-component 同时在`AppModule`中导入并添加`LoginRoutingModule`。 +makeTabs( - `router/ts/src/app/app.module.ts, - router/ts/src/app/login.component.1.ts, - router/ts/src/app/login-routing.module.ts +`router/ts/src/app/app.module.ts, +router / ts / src / app / login.component.1.ts, +router / ts / src / app / login - routing.module.ts `, - null, - `src/app/app.module.ts, - src/app/login.component.ts, - src/app/login-routing.module.ts +null, +`src/app/app.module.ts, +src / app / login.component.ts, +src / app / login - routing.module.ts `) .l-sub-section @@ -3683,7 +3857,7 @@ a#CanDeactivate 现在,我们已经给了用户一个能保护未保存更改的安全守卫。 -a#resolve-guard +a#resolve-guard :marked ### _Resolve_: pre-fetching component data @@ -3719,7 +3893,7 @@ a#resolve-guard 我们需要`Resolve`守卫。 -a#fetch-before-navigating +a#fetch-before-navigating :marked ### Fetch data before navigating @@ -3789,33 +3963,33 @@ a#fetch-before-navigating 本里程碑中与*危机中心*有关的代码如下: +makeTabs( - `router/ts/src/app/app.component.ts, - router/ts/src/app/crisis-center/crisis-center-home.component.ts, - router/ts/src/app/crisis-center/crisis-center.component.ts, - router/ts/src/app/crisis-center/crisis-center-routing.module.4.ts, - router/ts/src/app/crisis-center/crisis-list.component.ts, - router/ts/src/app/crisis-center/crisis-detail.component.ts, - router/ts/src/app/crisis-center/crisis-detail-resolver.service.ts, - router/ts/src/app/crisis-center/crisis.service.ts +`router/ts/src/app/app.component.ts, +router / ts / src / app / crisis - center / crisis - center - home.component.ts, +router / ts / src / app / crisis - center / crisis - center.component.ts, +router / ts / src / app / crisis - center / crisis - center - routing.module.4.ts, +router / ts / src / app / crisis - center / crisis - list.component.ts, +router / ts / src / app / crisis - center / crisis - detail.component.ts, +router / ts / src / app / crisis - center / crisis - detail - resolver.service.ts, +router / ts / src / app / crisis - center / crisis.service.ts `, - null, - `app.component.ts, - crisis-center-home.component.ts, - crisis-center.component.ts, - crisis-center-routing.module.ts, - crisis-list.component.ts, - crisis-detail.component.ts, - crisis-detail-resolver.service.ts, - crisis.service.ts +null, +`app.component.ts, +crisis - center - home.component.ts, +crisis - center.component.ts, +crisis - center - routing.module.ts, +crisis - list.component.ts, +crisis - detail.component.ts, +crisis - detail - resolver.service.ts, +crisis.service.ts `) +makeTabs( - `router/ts/src/app/auth-guard.service.3.ts, - router/ts/src/app/can-deactivate-guard.service.ts +`router/ts/src/app/auth-guard.service.3.ts, +router / ts / src / app / can - deactivate - guard.service.ts `, - null, - `auth-guard.service.ts, - can-deactivate-guard.service.ts +null, +`auth-guard.service.ts, +can - deactivate - guard.service.ts `) a#query-parameters @@ -4081,14 +4255,14 @@ a#lazy-load-crisis-center 下面是打开预加载之前的模块修改版: +makeTabs( - `router/ts/src/app/app.module.ts, - router/ts/src/app/app-routing.module.6.ts, - router/ts/src/app/crisis-center/crisis-center-routing.module.ts +`router/ts/src/app/app.module.ts, +router / ts / src / app / app - routing.module.6.ts, +router / ts / src / app / crisis - center / crisis - center - routing.module.ts `, - ',preload-v1,', - `app.module.ts, - app-routing.module.ts, - crisis-center-routing.module.ts +',preload-v1,', +`app.module.ts, +app - routing.module.ts, +crisis - center - routing.module.ts `) :marked You could try this now and confirm that the `CrisisCenterModule` loads after you click the "Crisis Center" button. @@ -4102,7 +4276,7 @@ a#lazy-load-crisis-center `RouterModule.forRoot`方法的第二个参数接受一个附加配置选项对象。 `preloadingStrategy`就是其中之一。 把`PreloadAllModules`添加到`forRoot`调用中: - + +makeExcerpt('src/app/app-routing.module.6.ts (preload all)', 'forRoot') :marked This tells the `Router` preloader to immediately load _all_ lazy loaded routes (routes with a `loadChildren` property). @@ -4397,7 +4571,7 @@ code-example(format="nocode"). URLs with hashes. Here's a "hash URL" that routes to the *Crisis Center*. 老旧的浏览器在当前地址的URL变化时总会往服务器发送页面请求……唯一的例外规则是:当这些变化位于“#”(被称为“hash”)后面时不会发送。通过把应用内的路由URL拼接在`#`之后,路由器可以获得这条“例外规则”带来的优点。下面是到*危机中心*路由的“hash URL”: - + code-example(format="nocode"). localhost:3002/src/#/crisis-center/ @@ -4420,7 +4594,7 @@ code-example(format="nocode"). `RouterModule.forRoot`函数把`LocationStrategy`设置成了`PathLocationStrategy`,使其成为了默认策略。 我们可以在启动过程中改写(override)它,来切换到`HashLocationStrategy`风格 —— 如果我们更喜欢这种。 - + .l-sub-section :marked @@ -4428,7 +4602,7 @@ code-example(format="nocode"). [Dependency Injection guide](dependency-injection.html#bootstrap). 要学习关于“提供商”和启动过程的更多知识,参见[依赖注入](dependency-injection.html#bootstrap)一章。 - + :marked ### Which strategy is best?