翻译了一部分未翻译的合并
This commit is contained in:
parent
a4d26e0797
commit
bd29d09085
|
@ -6,8 +6,8 @@
|
|||
},
|
||||
|
||||
"aot-compiler": {
|
||||
"title": "Ahead-of-Time Compilation",
|
||||
"intro": "Learn how to use Ahead-of-time compilation"
|
||||
"title": "预(AoT)编译器",
|
||||
"intro": "学习如何使用预编译器"
|
||||
},
|
||||
|
||||
"a1-a2-quick-reference": {
|
||||
|
|
|
@ -72,9 +72,12 @@ include ../_util-fns
|
|||
* [基于关键帧(Keyframes)的多阶段动画](#multi-step-animations-with-keyframes)
|
||||
|
||||
* [Parallel Animation Groups](#parallel-animation-groups)
|
||||
* [Animation callbacks](#animation-callbacks)
|
||||
|
||||
* [并行动画组(Group)](#parallel-animation-groups)
|
||||
|
||||
* [Animation callbacks](#animation-callbacks)
|
||||
|
||||
* [动画回调](#animation-callbacks)
|
||||
|
||||
.l-sub-section
|
||||
:marked
|
||||
|
|
|
@ -621,7 +621,7 @@ h3#injectable 为何@Injectable()?
|
|||
error when trying to instantiate a class that is not marked as
|
||||
`@Injectable()`.
|
||||
|
||||
**<a href="#{injMetaUrl}">@Injectable()</a>**标志着一个类可以被一个注入器实例化。通常来讲,在试图实例化一个没有被标识为`@Injectable()`的类时候,注入器将会报告错误。
|
||||
**<a href="#{injUrl}">@Injectable()</a>**标志着一个类可以被一个注入器实例化。通常来讲,在试图实例化一个没有被标识为`@Injectable()`的类时候,注入器将会报告错误。
|
||||
|
||||
block injectable-not-always-needed-in-ts
|
||||
.l-sub-section
|
||||
|
@ -664,7 +664,7 @@ block injectable-not-always-needed-in-ts
|
|||
fact `Injectable` #{_decorator}s that
|
||||
identify a class as a target for instantiation by an injector.
|
||||
|
||||
我们**可以**添加它。但是它不是必需的,因为`HerosComponent`已经有`@Component`装饰器了,这个装饰器类(和我们随后将会学到的`@Directive`和`@Pipe`一样)是<a href="#{injMetaUrl}">InjectableMetadata</a>的子类型。实际上,这个`InjectableMetadata`装饰器是把一个类标识为注入器实例化的目标。
|
||||
我们**可以**添加它。但是它不是必需的,因为`HerosComponent`已经有`@Component`装饰器了,这个装饰器类(和我们随后将会学到的`@Directive`和`@Pipe`一样)是<a href="#{injUrl}">InjectableMetadata</a>的子类型。实际上,这个`InjectableMetadata`装饰器是把一个类标识为注入器实例化的目标。
|
||||
|
||||
block ts-any-decorator-will-do
|
||||
.l-sub-section
|
||||
|
@ -693,7 +693,7 @@ block ts-any-decorator-will-do
|
|||
|
||||
注入器使用一个类的构造元数据来决定依赖类型,该构造元数据就是构造函数的参数类型所标识的。
|
||||
TypeScript为任何带有一个装饰器的类生成这样的元数据,任何装饰器都生成。
|
||||
当然,使用一个合适的<a href="#{injMetaUrl}">InjectableMetadata</a>装饰器来标识一个类更加有意义。
|
||||
当然,使用一个合适的<a href="#{injUrl}">Injectable</a>装饰器来标识一个类更加有意义。
|
||||
|
||||
.callout.is-critical
|
||||
header Always include the parentheses
|
||||
|
|
|
@ -290,6 +290,8 @@ include ../_util-fns
|
|||
that matches as the default route. The wildcard route is listed last as it's the most generic route and should be
|
||||
matched **only** if no other routes are matched first.
|
||||
|
||||
**这些路由的定义顺序**是故意如此设计的。路由器使用**先匹配者优先**的策略来匹配路由,所以,具体路由应该放在通用路由的前面。在上面的配置中,带静态路径的路由被放在了前面,后面是空路径路由,因此它会作为默认路由。而通配符路由被放在最后面,这是因为它是最通用的路由,应该**只在**前面找不到其它能匹配的路由时才匹配它。
|
||||
|
||||
:marked
|
||||
We export the `routing` constant so we can import it into our `app.module.ts` file where we'll add
|
||||
a configured *Router* module to our `AppModule` imports.
|
||||
|
@ -1334,6 +1336,8 @@ figure.image-display
|
|||
:marked
|
||||
The **RouterModule.forRoot** should only be provided for the `AppModule`. Since we are in a feature
|
||||
module, we'll use **RouterModule.forChild** method to only register additional routes.
|
||||
|
||||
**RouterModule.forRoot**只能由`AppModule`提供。但我们位于特性模块中,所以使用**RouterModule.forChild**来单独注册附加路由。
|
||||
|
||||
:marked
|
||||
We import our `heroesRouting` token from `heroes.routing.ts` into our `Heroes` module and register the routing.
|
||||
|
@ -1482,37 +1486,65 @@ a#get-route-parameter
|
|||
|
||||
<a id="activated-route"></a>
|
||||
h3#activated-route ActivatedRoute: the one-stop-shop for route information
|
||||
h3#activated-route ActivatedRoute:一站式获得路由信息
|
||||
:marked
|
||||
Each route contains information about its path, data parameters, URL segment and much more.
|
||||
All of this information is available in an injected service provided by the router called the [ActivatedRoute](../api/router/index/ActivatedRoute-interface.html).
|
||||
|
||||
每个路由都包含路径、数据参数、URL片段等很多信息。
|
||||
所有这些信息都可以通过有路由器提供的一个叫[ActivatedRoute](../api/router/index/ActivatedRoute-interface.html)的服务提供商来获取。
|
||||
|
||||
The `ActivatedRoute` contains all the information you need from the current route component as well as ways to get information
|
||||
about other activated routes in the `RouterState`.
|
||||
|
||||
`ActivatedRoute`包含你需要从当前路由组件中获得的全部信息,正如你可以从`RouterState`中获得关于其它激活路由的信息。
|
||||
|
||||
.l-sub-section
|
||||
:marked
|
||||
**`url`**: An `Observable` of the route path(s). The value is provided as an array of strings for each part of the route path.
|
||||
|
||||
**`url`**: 该路由路径的`Observable`对象。它的值是一个由路径中各个部件组成的字符串数组。
|
||||
|
||||
**`data`**: An `Observable` that contains the `data` object provided for the route. Also contains any resolved values from the [resolve guard](#resolve-guard).
|
||||
|
||||
**`data`**: 该路由提供的`data`对象的一个`Observable`对象。还包含从[resolve守卫](#resolve-guard)中解析出来的值。
|
||||
|
||||
**`params`**: An `Observable` that contains the required and [optional parameters](#optional-route-parameters) specific to the route.
|
||||
|
||||
**`params`**: 包含该路由的必选参数和[可选参数](#optional-route-parameters)的`Observable`对象。
|
||||
|
||||
**`queryParams`**: An `Observable` that contains the [query parameters](#query-parameters) available to all routes.
|
||||
|
||||
**`queryParams`**: 一个包含对所有路由都有效的[查询参数](#query-parameters)的`Observable`对象。
|
||||
|
||||
**`fragment`**: An `Observable` of the URL [fragment](#fragment) available to all routes.
|
||||
|
||||
**`fragment`**: 一个包含对所有路由都有效的[片段](#fragment)值的`Observable`对象。
|
||||
|
||||
**`outlet`**: The name of the `RouterOutlet` used to render the route. For an unnamed outlet, the outlet name is **primary**.
|
||||
|
||||
**`outlet`**: `RouterOutlet`的名字,用于指示渲染该路由的位置。对于未命名的`RouterOutlet`,这个名字是**primary**。
|
||||
|
||||
**`routeConfig`**: The route configuration used for the route that contains the origin path.
|
||||
|
||||
**`routeConfig`**: 与该路由的原始路径对应的配置信息。
|
||||
|
||||
**`parent`**: an `ActivatedRoute` that contains the information from the parent route when using [child routes](#child-routing-component).
|
||||
|
||||
**`parent`**: 当使用[子路由](#child-routing-component)时,它是一个包含父路由信息的`ActivatedRoute`对象。
|
||||
|
||||
**`firstChild`**: contains the first `ActivatedRoute` in the list of child routes.
|
||||
|
||||
**`firstChild`**: 包含子路由列表中的第一个`ActivatedRoute`对象。
|
||||
|
||||
**`children`**: contains all the [child routes](#child-routing-component) activated under the current route.
|
||||
|
||||
**`children`**: 包含当前路由下激活的全部[子路由](#child-routing-component)。
|
||||
|
||||
:marked
|
||||
We import the `Router`, `ActivatedRoute`, and `Params` tokens from the router package.
|
||||
|
||||
我们要从路由器(`router`)包中导入`Router`、`ActivatedRoute`和`Params`类。
|
||||
|
||||
+makeExcerpt('app/heroes/hero-detail.component.1.ts (activated route)', 'imports')
|
||||
|
||||
|
@ -1666,141 +1698,232 @@ a#nav-to-list
|
|||
.l-main-section#optional-route-parameters
|
||||
:marked
|
||||
### Route Parameters
|
||||
### 路由参数
|
||||
|
||||
We use [*route parameters*](#route-parameters) to specify a *required* parameter value *within* the route URL
|
||||
as we do when navigating to the `HeroDetailComponent` in order to view-and-edit the hero with *id:15*.
|
||||
|
||||
如果想导航到`HeroDetailComponent`以对id为15的英雄进行查看并编辑,就要在路由的URL中使用[*路由参数*](#route-parameters)来指定*必要*参数值。
|
||||
|
||||
code-example(format="." language="bash").
|
||||
localhost:3000/hero/15
|
||||
:marked
|
||||
Sometimes we wish to add *optional* information to a route request.
|
||||
For example, the `HeroListComponent` doesn't need help to display a list of heroes.
|
||||
But it might be nice if the previously-viewed hero were pre-selected when returning from the `HeroDetailComponent`.
|
||||
|
||||
有时我们希望往路由请求中添加*可选的*信息。
|
||||
例如,`HeroListComponent`虽然不需要借助此信息显示英雄列表,但是如果从`HeroDetailComponent`返回时,它能自动选中刚刚查看过的英雄就好了。
|
||||
|
||||
figure.image-display
|
||||
img(src='/resources/images/devguide/router/selected-hero.png' alt="Selected hero")
|
||||
:marked
|
||||
That becomes possible if we can include hero Magneta's `id` in the URL when we
|
||||
return from the `HeroDetailComponent`, a scenario we'll pursue in a moment.
|
||||
|
||||
如果我们能在从`HeroDetailComponent`返回时在URL中带上英雄Magneta的`id`,不就可以了吗?接下来我们就尝试实现这个场景。
|
||||
|
||||
Optional information takes other forms. Search criteria are often loosely structured, e.g., `name='wind*'`.
|
||||
Multiple values are common — `after='12/31/2015' & before='1/1/2017'` — in no particular order —
|
||||
`before='1/1/2017' & after='12/31/2015'` — in a variety of formats — `during='currentYear'` .
|
||||
|
||||
可选信息有很多种形式。搜索条件通常就不是严格结构化的,比如`name='wind*'`;有多个值也很常见,如`after='12/31/2015'&before='1/1/2017'`;
|
||||
而且顺序无关,如`before='1/1/2017'&after='12/31/2015'`,还可能有很多种变体格式,如`during='currentYear'`。
|
||||
|
||||
These kinds of parameters don't fit easily in a URL *path*. Even if we could define a suitable URL token scheme,
|
||||
doing so greatly complicates the pattern matching required to translate an incoming URL to a named route.
|
||||
|
||||
这么多种参数要放在URL的*路径*中可不容易。即使我们能制定出一个合适的URL方案,实现起来也太复杂了,得通过模式匹配才能把URL翻译成命名路由。
|
||||
|
||||
Optional parameters are the ideal vehicle for conveying arbitrarily complex information during navigation.
|
||||
Optional parameters aren't involved in pattern matching and affords enormous flexibility of expression.
|
||||
|
||||
可选参数是在导航期间传送任意复杂信息的理想载体。
|
||||
可选参数不涉及到模式匹配并在表达上提供了巨大的灵活性。
|
||||
|
||||
The Router supports navigation with optional parameters as well as required route parameters.
|
||||
We define _optional_ parameters in an *object* after we define our required route parameters.
|
||||
|
||||
和必要参数一样,路由器也支持通过可选参数导航。
|
||||
我们在定义完必要参数之后,通过一个*对象*来定义*可选参数*。
|
||||
|
||||
### Route Parameters: Required or Optional?
|
||||
### 路由参数:用必要的还是可选的?
|
||||
|
||||
There is no hard-and-fast rule. In general,
|
||||
|
||||
并没有一劳永逸的规则,通常:
|
||||
|
||||
*prefer a required route parameter when*
|
||||
|
||||
*下列情况下优先使用必要参数*
|
||||
|
||||
* the value is required.
|
||||
* 该值是必须的。
|
||||
* the value is necessary to distinguish one route path from another.
|
||||
* 该值在区分此路由与其它路由时是必要的。
|
||||
|
||||
*prefer an optional parameter when*
|
||||
|
||||
*下列情况下优先使用可选参数*
|
||||
|
||||
* the value is optional, complex, and/or multi-variate.
|
||||
|
||||
* 该值是可选的、复杂的,和/或多变量的。
|
||||
|
||||
<a id="route-parameters-object"></a>
|
||||
### Route parameter
|
||||
### 路由参数
|
||||
|
||||
When navigating to the `HeroDetailComponent` we 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`,把这个`id`作为[*链接参数数组*](#link-parameters-array)的第二个条目。
|
||||
|
||||
+makeExcerpt('app/heroes/hero-list.component.1.ts', 'link-parameters-array')
|
||||
|
||||
:marked
|
||||
The router embedded the `id` value in the navigation URL because we had defined it
|
||||
as a route parameter with an `:id` placeholder token in the route `path`:
|
||||
|
||||
路由器在导航URL中内嵌了`id`的值,这是因为我们把它用一个`:id`占位符当做路由参数定义在了路由的`path`中:
|
||||
|
||||
+makeExcerpt('app/heroes/heroes.routing.ts', 'hero-detail-route')
|
||||
|
||||
:marked
|
||||
When the user clicks the back button, the `HeroDetailComponent` constructs another *link parameters array*
|
||||
which it uses to navigate back to the `HeroListComponent`.
|
||||
|
||||
当用户点击后退按钮时,`HeroDetailComponent`构造了另一个*链接参数数组*,可以用它导航回`HeroListComponent`。
|
||||
|
||||
+makeExcerpt('app/heroes/hero-detail.component.1.ts', 'gotoHeroes')
|
||||
|
||||
:marked
|
||||
This array lacks a route parameter because we had no reason to send information to the `HeroListComponent`.
|
||||
|
||||
该数组缺少一个路由参数,这是因为我们那时没有理由往`HeroListComponent`发送信息。
|
||||
|
||||
Now we have a reason. We'd like to send the id of the current hero with the navigation request so that the
|
||||
`HeroListComponent` can highlight that hero in its list.
|
||||
This is a _nice-to-have_ feature; the list will display perfectly well without it.
|
||||
|
||||
但现在有了。我们要在导航请求中同时发送当前英雄的id,以便`HeroListComponent`可以在列表中高亮这个英雄。
|
||||
这是一个*有更好,没有也无所谓*的特性,就算没有它,列表照样能显示得很完美。
|
||||
|
||||
We do that with an object that contains an _optional_ `id` parameter.
|
||||
For demonstration purposes, we also defined a junk parameter (`foo`) that the `HeroListComponent` should ignore.
|
||||
Here's the revised navigation statement:
|
||||
|
||||
我们通过一个包含*可选*`id`参数的对象来做到这一点。
|
||||
为了演示,我们还定义了一个没用的参数(`foo`),`HeroListComponent`应该忽略它。
|
||||
下面是修改过的导航语句:
|
||||
|
||||
+makeExcerpt('app/heroes/hero-detail.component.ts (go to heroes)', 'gotoHeroes-navigate')
|
||||
|
||||
:marked
|
||||
The application still works. Clicking "back" returns to the hero list view.
|
||||
|
||||
该应用仍然能工作。点击“back”按钮返回英雄列表视图。
|
||||
|
||||
Look at the browser address bar.
|
||||
|
||||
注意浏览器的地址栏。
|
||||
|
||||
.l-sub-section
|
||||
img(src='/resources/images/devguide/plunker-separate-window-button.png' alt="pop out the window" align="right" style="margin-right:-20px")
|
||||
:marked
|
||||
When running in plunker, pop out the preview window by clicking the blue 'X' button in the upper right corner.
|
||||
|
||||
当在plunker中运行时,请点击右上角的蓝色'X'按钮来弹出预览窗口,否则你看不到地址栏的变化。
|
||||
|
||||
:marked
|
||||
It should look something like this, depending on where you run it:
|
||||
It should look something like this, depending on where you run it:
|
||||
|
||||
看起来应该是这样,不过也取决于你在哪里运行它:
|
||||
|
||||
code-example(language="bash").
|
||||
localhost:3000/heroes;id=15;foo=foo
|
||||
|
||||
:marked
|
||||
The `id` value appears in the URL as (`;id=15;foo=foo`), not in the URL path.
|
||||
The path for the "Heroes" route doesn't have an `:id` token.
|
||||
|
||||
`id`的值像这样出现在URL中(`;id=15;foo=foo`),但不在URL的路径部分。
|
||||
“Heroes”路由的路径部分并没有定义`:id`。
|
||||
|
||||
The optional route parameters are not separated by "?" and "&" as they would be in the URL query string.
|
||||
They are **separated by semicolons ";"**
|
||||
This is *matrix URL* notation — something we may not have seen before.
|
||||
|
||||
可选的路由参数没有使用“?”和“&”符号分隔,因为它们将用在URL查询字符串中。
|
||||
它们是**用“;”分隔的**。
|
||||
这是*矩阵URL*标记法 —— 我们以前可能从未见过。
|
||||
|
||||
.l-sub-section
|
||||
:marked
|
||||
*Matrix URL* notation is an idea first floated
|
||||
in a [1996 proposal](http://www.w3.org/DesignIssues/MatrixURIs.html) by the founder of the web, Tim Berners-Lee.
|
||||
|
||||
*Matrix URL*写法首次提出是在[1996提案](http://www.w3.org/DesignIssues/MatrixURIs.html)中,提出者是Web的奠基人:Tim Berners-Lee。
|
||||
|
||||
Although matrix notation never made it into the HTML standard, it is legal and
|
||||
it became popular among browser routing systems as a way to isolate parameters
|
||||
belonging to parent and child routes. The Router is such a system and provides
|
||||
support for the matrix notation across browsers.
|
||||
|
||||
虽然Matrix写法未曾进入过HTML标准,但它是合法的。而且在浏览器的路由系统中,它作为从父路由和子路由中单独隔离出参数的方式而广受欢迎。Angular的路由器正是这样一个路由系统,并支持跨浏览器的Matrix写法。
|
||||
|
||||
The syntax may seem strange to us but users are unlikely to notice or care
|
||||
as long as the URL can be emailed and pasted into a browser address bar
|
||||
as this one can.
|
||||
|
||||
这种语法对我们来说可能有点奇怪,不过用户不会在意这一点,因为该URL可以正常的通过邮件发出去或粘贴到浏览器的地址栏中。
|
||||
|
||||
:marked
|
||||
### Route parameters in the *ActivatedRoute* service
|
||||
|
||||
### *ActivatedRoute*服务中的路由参数
|
||||
|
||||
The list of heroes is unchanged. No hero row is highlighted.
|
||||
|
||||
英雄列表仍没有改变,没有哪个英雄列被加亮显示。
|
||||
|
||||
.l-sub-section
|
||||
:marked
|
||||
The <live-example></live-example> *does* highlight the selected
|
||||
row because it demonstrates the final state of the application which includes the steps we're *about* to cover.
|
||||
At the moment we're describing the state of affairs *prior* to those steps.
|
||||
|
||||
<live-example></live-example>*没有*高亮选中的行,因为它演示的是应用的最终状态,因此包含了我们*即将*示范的步骤。
|
||||
此刻,我们描述的仍是那些步骤*之前*的状态。
|
||||
|
||||
:marked
|
||||
The `HeroListComponent` isn't expecting any parameters at all and wouldn't know what to do with them.
|
||||
Let's change that.
|
||||
|
||||
`HeroListComponent`还完全不需要任何参数,也不知道该怎么处理它们。我们这就改变这一点。
|
||||
|
||||
Previously, when navigating from the `HeroListComponent` to the `HeroDetailComponent`,
|
||||
we subscribed to the route params `Observable` and made it available to the `HeroDetailComponent`
|
||||
in the `ActivatedRoute` service. We injected that service in the constructor of the `HeroDetailComponent`.
|
||||
|
||||
以前,当从`HeroListComponent`导航到`HeroDetailComponent`时,我们通过`ActivatedRoute`服务订阅了路由参数这个`Observable`,并让它能用在`HeroDetailComponent`中。我们把该服务注入到了`HeroDetailComponent`的构造函数中。
|
||||
|
||||
This time we'll be navigating in the opposite direction, from the `HeroDetailComponent` to the `HeroListComponent`.
|
||||
|
||||
这次,我们要进行反向导航,从`HeroDetailComponent`到`HeroListComponent`。
|
||||
|
||||
First we extend the router import statement to include the `ActivatedRoute` service symbol;
|
||||
|
||||
首先,我们扩展该路由的导入语句,以包含进`ActivatedRoute`服务的类;
|
||||
|
||||
+makeExcerpt('app/heroes/hero-list.component.ts (import)', 'import-router')
|
||||
|
||||
:marked
|
||||
Then we use the `ActivatedRoute` to access the `params` _Observable_ so we can subscribe
|
||||
and extract the `id` parameter as the `selectedId`:
|
||||
|
||||
然后,使用`ActivatedRoute`来访问`params`这个`Observable`,以便我们订阅它,并把其中的`id`参数提取到`selectedId`中:
|
||||
|
||||
+makeExcerpt('app/heroes/hero-list.component.ts (constructor)', 'ctor')
|
||||
|
||||
|
@ -1808,8 +1931,14 @@ code-example(language="bash").
|
|||
:marked
|
||||
All route/query parameters are strings.
|
||||
The (+) in front of the `params['id']` expression is a JavaScript trick to convert the string to an integer.
|
||||
|
||||
所有的路由参数或查询参数都是字符串。
|
||||
`params['id']`表达式前面的加号(+)是一个JavaScript的小技巧,用来把字符串转换成整数。
|
||||
|
||||
:marked
|
||||
We add an `isSelected` method that returns true when a hero's id matches the selected id.
|
||||
|
||||
我们添加了一个`isSelected`方法,当英雄的id和选中的id匹配时,它返回真值。
|
||||
|
||||
+makeExcerpt('app/heroes/hero-list.component.ts', 'isSelected')
|
||||
|
||||
|
@ -1817,26 +1946,43 @@ code-example(language="bash").
|
|||
Finally, we update our template with a [Class Binding](template-syntax.html#class-binding) to that `isSelected` method.
|
||||
The binding adds the `selected` CSS class when the method returns `true` and removes it when `false`.
|
||||
Look for it within the repeated `<li>` tag as shown here:
|
||||
|
||||
最后,我们用[CSS类绑定](template-syntax.html#class-binding)更新模板,把它绑定到`isSelected`方法上。
|
||||
如果该方法返回`true`,此绑定就会添加CSS类`selected`,否则就移除它。
|
||||
在`<li>`标记中找到它,就像这样:
|
||||
|
||||
+makeExcerpt('app/heroes/hero-list.component.ts', 'template')
|
||||
|
||||
:marked
|
||||
When the user navigates from the heroes list to the "Magneta" hero and back, "Magneta" appears selected:
|
||||
|
||||
当用户从英雄列表导航到英雄“Magneta”并返回时,“Magneta”看起来是选中的:
|
||||
|
||||
figure.image-display
|
||||
img(src='/resources/images/devguide/router/selected-hero.png' alt="Selected List" )
|
||||
:marked
|
||||
The optional `foo` route parameter is harmless and continues to be ignored.
|
||||
|
||||
这儿可选的`foo`路由参数人畜无害,并继续被忽略。
|
||||
|
||||
h3#route-animation Adding animations to the route component
|
||||
h3#route-animation 为路由组件添加动画
|
||||
:marked
|
||||
Our heroes feature module is almost complete, but what is a feature without some smooth transitions?
|
||||
We already know that Angular supports [animations](../guide/animations.html) and we want to take
|
||||
advantage of them by adding some animation to our *Hero Detail* component.
|
||||
|
||||
我们的“英雄”这个特性模块就要完成了,但这个特性还没有平滑的专场效果。
|
||||
我们知道Angular支持[动画](../guide/animations.html),想要得到这项优点,就要为*英雄详情*组件添加一些动画。
|
||||
|
||||
First, we'll start by importing our animation functions that build our animation triggers,
|
||||
control state and manage transitions between states. We'll use these functions to add transitions
|
||||
to our route component as it moves between states our application view. We'll also import the
|
||||
`HostBinding` decorator for binding to our route component.
|
||||
|
||||
首先,我们从导入动画函数开始,它们用于构建动画触发器,以控制状态和管理状态之间的转场。
|
||||
我们使用这些函数来把转场效果添加到路由组件中,这样当应用视图的多个状态之间发生转移时,就会触发动画。
|
||||
我们还要导入`HostBinding`装饰器来绑定到路由组件。
|
||||
|
||||
+makeExcerpt('app/heroes/hero-detail.component.ts (animation imports)', 'route-animation-imports')
|
||||
|
||||
|
@ -1845,8 +1991,13 @@ h3#route-animation Adding animations to the route component
|
|||
about the choice of the binding name, but since we are controlling route animation, we'll go with `routeAnimation`.
|
||||
The binding value is set to `true` because we only care about the `*` and `void` states which are
|
||||
[entering and leaving](../guide/animations.html#example-entering-and-leaving) animation states.
|
||||
|
||||
接下来,我们将对名叫`@routeAnimation`的路由动画使用**宿主绑定(HostBinding)**。选择绑定名时没什么特别的要求,但是由于我们是在控制路由的动画,所以把它叫做`routeAnimation`。
|
||||
该绑定值被设置为`true`,因为我们只关心`*`和`void`状态,这些动画状态代表[进场和离开](../guide/animations.html#example-entering-and-leaving)。
|
||||
|
||||
We'll also add some display and positioning bindings for styling.
|
||||
|
||||
我们还将为样式添加一些显示和位置绑定。
|
||||
|
||||
+makeExcerpt('app/heroes/hero-detail.component.ts (route animation binding)', 'route-animation-host-binding')
|
||||
|
||||
|
@ -1855,24 +2006,37 @@ h3#route-animation Adding animations to the route component
|
|||
setup. We'll use the **wildcard state** that matches any animation state our route component is in, along with
|
||||
two *transitions*. One transition animates the component as it enters the application view (`void => *`), while the other
|
||||
animates the component as it leaves the application view (`* => void`).
|
||||
|
||||
现在,我们可以构建动画触发器了,我们称之为*routeAnimation*来匹配我们以前定义的绑定。我们的使用**通配符状态**,它们匹配我们这个路由组件的任意动画状态,后面是两个*转场动画*。一个转场动画(`void => *`)在组件进入应用视图时触发,另一个(`* => void`)在离开时触发。
|
||||
|
||||
We could add different transitions to different route components depending on our needs. We'll just animate our `HeroDetailComponent` for this milestone.
|
||||
|
||||
如果需要,我们还可以为其它路由组件添加不同的转场动画。在这个里程碑中我们只为`HeroDetailComponent`添加动画。
|
||||
|
||||
.l-sub-section
|
||||
:marked
|
||||
Using route animations on individual components is something we don't want to do throughout our entire application.
|
||||
It would be better to animate routes based on **route paths**, a topic to cover in a future update to this chapter.
|
||||
|
||||
在整个应用程序中,我们并不想在独立组件中使用路由动画。
|
||||
我们认为基于**路由路径**进行路由动画会更好一些,本章将来的更新中会涉及到这个主题。
|
||||
|
||||
:marked
|
||||
Our route component animation looks as such:
|
||||
|
||||
我们的路由动画看起来像这样:
|
||||
|
||||
+makeExcerpt('app/heroes/hero-detail.component.ts (route animation)', 'route-animation')
|
||||
|
||||
:marked
|
||||
Simply stated, our `HeroDetailComponent` will ease in from the left when routed to and will slide down when navigating away.
|
||||
We could add more complex animations here, but we'll leave our `HeroDetailComponent` as is for now.
|
||||
|
||||
简单的说,当进入路由时,`HerodetailComponent`组件会从左侧弹入,离开时会向下方滑出。
|
||||
这里我们还可以添加更复杂的动画,不过我们现在就先不这么做了。
|
||||
|
||||
h3#merge-hero-routes Import hero module into AppModule
|
||||
h3#merge-hero-routes 把hero模块导入到AppModule中
|
||||
:marked
|
||||
Our heroes feature module is ready, but application doesn't know about our heroes module yet.
|
||||
We'll need to import it into the `AppModule` we defined in `app.module.ts`.
|
||||
|
@ -1903,6 +2067,8 @@ h3#merge-hero-routes Import hero module into AppModule
|
|||
Routes provided by feature modules will be combined together into their imported module's routes by
|
||||
the router. This allows us to continue defining our feature module routes without
|
||||
modifying our main route configuration.
|
||||
|
||||
由特性模块提供的路由将会被路由器和它们导入的模块提供的路由组合在一起。这让我们可以继续定义特性路由,而不用修改主路由配置。
|
||||
|
||||
:marked
|
||||
As a result, the `AppModule` no longer has specific knowledge of the hero feature, its components, or its route details.
|
||||
|
@ -2244,10 +2410,13 @@ a#child-routing-component
|
|||
with a single route containing our `CrisisListComponent`. The `CrisisListComponent` route
|
||||
also has a `children` array with two routes.
|
||||
|
||||
注意,父路由`crisis-center`有一个`children`属性,它有一个包含`CrisisListComponent`的路由。
|
||||
`CrisisListModule`路由还有一个带两个路由的`children`数组。
|
||||
|
||||
These two routes navigate to the two *Crisis Center* child components,
|
||||
`CrisisCenterHomeComponent` and `CrisisDetailComponent`.
|
||||
|
||||
注意,父路由`crisis-center`有一个`children`属性,它是一个带两个路由的数组。
|
||||
这两个路由导航到了*危机中心*的两个子组件:`CrisisCenterHomeComponent`和`CrisisDetailComponent`。
|
||||
|
||||
There are some *important differences* in the treatment of these routes.
|
||||
|
||||
|
@ -2261,25 +2430,45 @@ a#child-routing-component
|
|||
The `CrisisListComponent` contains the crisis list and a `RouterOutlet` to
|
||||
display the `Crisis Center Home` and `Crisis Detail` route components.
|
||||
|
||||
`CrisisListComponent`包含危机列表和一个`RouterOutlet`,用以显示`Crisis Center Home`和`Crisis Detail`这两个路由组件。
|
||||
|
||||
The `Crisis Detail` route is a child of the `Crisis List`. Since the router [reuses components](#reuse)
|
||||
by default, the `Crisis Detail` component will be re-used as we select different crises.
|
||||
|
||||
`Crisis Detail`路由是`Crisis List`的子路由。由于路由器默认会[复用组件](#reuse),因此当我们选择了另一个危机时,`CrisisDetailComponent`会被复用。
|
||||
|
||||
In contrast, back in the `Hero Detail` route, the component was recreated each time we selected a different hero.
|
||||
|
||||
作为对比,回到`Hero Detail`路由时,每当我们选择了不同的英雄时,该组件都会被重新创建。
|
||||
|
||||
At the top level, paths that begin with `/` refer to the root of the application.
|
||||
But these are child routes.
|
||||
They *extend* the path of the parent route.
|
||||
With each step down the route tree, we add a slash followed by the route path (unless the route path is _empty_).
|
||||
|
||||
For example, the parent path to the `CrisisCenterComponent` is `/crisis-center
|
||||
The router appends these child paths to the parent path to the `CrisisCenterComponent` (`/crisis-center).
|
||||
在顶级,以`/`开头的路径指向的总是应用的根。
|
||||
但这里是子路由。
|
||||
它们是在父路由路径的基础上做出的扩展。
|
||||
在路由树中每深入一步,我们就会在该路由的路径上添加一个斜线`/`(除非该路由的路径是*空的*)。
|
||||
|
||||
For example, the parent path to the `CrisisCenterComponent` is `/crisis-center`
|
||||
The router appends these child paths to the parent path to the `CrisisCenterComponent` (`/crisis-center`).
|
||||
|
||||
例如,`CrisisCenterComponent`的路径是`/crisis-center`。
|
||||
路由器就会把这些子路由的路径中添加上到父路由`CrisisCenterComponent`的路径(`/crisis-center`)。
|
||||
|
||||
* to navigate to the `CrisisCenterHomeComponent, the full URL is `/crisis-center` (/crisis-center` + `''` + `''`).
|
||||
|
||||
* 要导航到`CrisisCenterHomeComponent`,完整的URL是`/crisis-center` (/crisis-center` + `''` + `''`)。
|
||||
|
||||
* to navigate to the `CrisisDetailComponent` for a crisis with `id=2`, the full URL is
|
||||
`/crisis-center/2` (/crisis-center` + `''` + `'/2'`).
|
||||
|
||||
* 要导航到`CrisisDetailComponent`以展示`id=2`的危机,完整的URL是`/crisis-center/2` (/crisis-center` + `''` + `'/2'`)。
|
||||
|
||||
The absolute URL for the latter example, including the origin, is
|
||||
|
||||
本例子中的绝对URL,包含源站部分,就是:
|
||||
|
||||
code-example.
|
||||
localhost:3000/crisis-center/2
|
||||
|
@ -2401,32 +2590,55 @@ code-example.
|
|||
|
||||
.l-main-section
|
||||
h2#relative-navigation Relative Navigation
|
||||
h2#relative-navigation 相对导航
|
||||
|
||||
:marked
|
||||
While building out our *Crisis Center* feature, we've navigated to the
|
||||
*Crisis Detail* route using an **absolute path** that begins with a **slash**.
|
||||
This navigation starts from the top of our route configuration to find the
|
||||
matching path to our route.
|
||||
|
||||
当构建*危机中心*特性时,我们将使用以**斜线**开头的**绝对路径**来导航到*危机详情*路由。
|
||||
这次导航会从路由配置的顶部开始查找路由,以匹配路径。
|
||||
|
||||
We could continue to use absolute paths to navigate inside our *Crisis Center*
|
||||
feature, but that makes our links very rigid. If we changed our parent `/crisis-center`
|
||||
path, we would have to change our link parameters array.
|
||||
|
||||
我们可以在*危机中心*特性区继续使用绝对路径进行导航,但这会让我们的链接过于死板。
|
||||
如果更改了父路由路径`/crisis-center`,我们就不得不到处更改链接参数数组。
|
||||
|
||||
We can make our links more flexible by using **relative** navigation with the router.
|
||||
|
||||
通过让路由器使用**相对**导航的方式,我们可以让链接更富有弹性。
|
||||
|
||||
* The full path to the route is not required.
|
||||
* 不再需要到路由的完整路径。
|
||||
* Navigation within our feature area remains intact if the parent route path is changed.
|
||||
* 当修改父路由路径时在我们的特性区中导航时不需要做任何改动。
|
||||
* The *link parameters array* only contains navigation relative to the current URL.
|
||||
* *链接参数数组*只包含到当前URL的相对导航信息。
|
||||
|
||||
.l-sub-section
|
||||
:marked
|
||||
The **link parameters array** supports a directory-like syntax for relative navigation.
|
||||
|
||||
**链接参数数组**通过目录式语法支持相对导航。
|
||||
|
||||
`./` or `no leading slash` is relative to the current level.
|
||||
|
||||
`./`或“无前导斜线”时表示相当于当前级别。
|
||||
|
||||
`../` to go up one level in the route path.
|
||||
|
||||
`../`表示在路由路径中往上走一级。
|
||||
|
||||
The relative navigation syntax can be used in combination with a *path*. If we wanted to navigate
|
||||
from one route path to another sibling route path we could use `../path` convention to go up
|
||||
one level and down to the sibling route path.
|
||||
|
||||
相对导航的语法可以和*路径*组合在一起,如果我们要从一个路由路径导航到一个兄弟路由路径,
|
||||
可以使用`../path`来简便的导航到上一级然后再进入兄弟路由路径。
|
||||
|
||||
:marked
|
||||
In order to navigate relatively using the `Router` service, we use the `ActivatedRoute`
|
||||
|
@ -2435,17 +2647,28 @@ h2#relative-navigation Relative Navigation
|
|||
`router.navigate` method after the *link parameters array* specifying the **relativeTo** property.
|
||||
We set the `relativeTo` property to our `ActivatedRoute` and the router will merge our
|
||||
navigation information into to the current URL.
|
||||
|
||||
要使用`Router`进行相对导航,可以使用`ActivatedRoute`来告诉路由器我们正在*RouterState*中的什么地方,*RouterState*是激活路由组成的树。
|
||||
要做到这一点,我们可以为`router.navigate`方法中*链接参数数组*后的对象型参数指定**relativeTo**属性。
|
||||
只要把这个`relativeTo`属性设置为我们的`ActivatedRoute`,路由器就会把我们的导航信息和当前URL合并在一起。
|
||||
|
||||
.l-sub-section
|
||||
:marked
|
||||
When using router's `navigateByUrl` method, the navigation is **always** absolute.
|
||||
|
||||
当使用路由器的`navigateByUrl`方法时,导航**总是**绝对的。
|
||||
|
||||
:marked
|
||||
### Navigate to Crisis Detail relatively
|
||||
|
||||
### 用相对方式导航到危机详情
|
||||
|
||||
Let's update our *Crisis List* `onSelect` method to use relative navigation so we don't have
|
||||
to start from the top of our route configuration. We've already injected the `ActivatedRoute`
|
||||
into our constructor that we'll need for the relative navigation.
|
||||
|
||||
我们来把*危机列表*中的`onSelect`方法改成相对导航,以便我们不必从路由配置的顶部开始。
|
||||
我们已经把相对导航所需的`ActivatedRoute`注入到了构造函数中。
|
||||
|
||||
+makeExcerpt('app/crisis-center/crisis-list.component.1.ts (constructor)', 'relative-navigation-ctor')
|
||||
|
||||
|
@ -2453,6 +2676,8 @@ h2#relative-navigation Relative Navigation
|
|||
When we visit the *Crisis Center*, our path is `/crisis-center`, so we just want to add the `id` of the *Crisis Center*
|
||||
to our existing path. When the router navigates, it will use the current path `/crisis-center`,
|
||||
adding on our `id`. If our `id` were `1`, the resulting path would be `/crisis-center/1`.
|
||||
|
||||
当我们访问*危机中心*时,当前路径是`/crisis-center`,所以我们只要把*危机*的`id`添加到现有路径中就可以了。当路由器导航时,它使用当前路径`/crisis-center`并追加上此`id`。如果`id`为`1`,结果路径就是`/crisis-center/1`。
|
||||
|
||||
+makeExcerpt('app/crisis-center/crisis-list.component.ts (relative navigation)', 'relative-navigation')
|
||||
|
||||
|
@ -2460,6 +2685,8 @@ h2#relative-navigation Relative Navigation
|
|||
We'll also update the *Crisis Detail* component to navigate back to our *Crisis Center* list. We want to go back up a level
|
||||
in the path, so we use to the `../` syntax. If our current `id` is `1`, the resulting path coming from `/crisis-center/1`
|
||||
would be `/crisis-center`.
|
||||
|
||||
我们还要修改*危机详情*组件以便导航回*危机中心*列表。我们得回到路径的上一级,所以我们使用`../`语法。如果当前`id`是`1`,那么结果路径就会从`/crisis-center/1`变成`/crisis-center`。
|
||||
|
||||
+makeExcerpt('app/crisis-center/crisis-detail.component.1.ts (relative navigation)', 'relative-navigation')
|
||||
|
||||
|
@ -2467,6 +2694,8 @@ h2#relative-navigation Relative Navigation
|
|||
If we are using a `RouterLink` to navigate instead of the `Router` service, we can use the **same**
|
||||
link parameters array, but we don't have to provide the object with the `relativeTo` property. The `ActivatedRoute`
|
||||
is implicit in the `RouterLink` directive.
|
||||
|
||||
如果我们正在使用`RouterLink`进行导航,而不是`Router`服务,仍然可以使用**相同的**链接参数数组,不过我们不用提供带`relativeTo`属性的对象。在`RouterLink`指令中`ActivatedRoute`是默认的。
|
||||
|
||||
+makeExcerpt('app/crisis-center/crisis-list.component.1.ts (relative routerLink)', 'relative-navigation-router-link')
|
||||
|
||||
|
@ -2478,6 +2707,7 @@ h2#guards 路由守卫
|
|||
|
||||
:marked
|
||||
## Milestone #4: Route Guards
|
||||
## 里程碑#4:路由守卫
|
||||
|
||||
At the moment, *any* user can navigate *anywhere* in the application *anytime*.
|
||||
|
||||
|
@ -2657,24 +2887,36 @@ a#can-activate-guard
|
|||
link to be active when we visit that route. We've added an additional binding to our `Dashboard` routerLink,
|
||||
`[routerLinkActiveOptions]="{ exact: true }"` which will only mark the `./` link as active when
|
||||
we navigate the to `/admin` URL and not when we navigate to one the other child routes.
|
||||
|
||||
由于`AdminModule`中管理仪表盘的`RouterLink`是一个空路径的路由,所以它会匹配到管理特性区的任何路由。但我们只有在访问`Dashboard`路由时才希望该链接被激活。所以我们往`Dashboard`这个routerLink上添加了一个额外的绑定`[routerLinkActiveOptions]="{ exact: true }"`,这样就只有当我们导航到`/admin`这个URL时才会激活它,而不会在导航到它的某个子路由时。
|
||||
|
||||
:marked
|
||||
Our initial admin routing configuration:
|
||||
|
||||
我们的初始管理路由配置如下:
|
||||
|
||||
+makeExcerpt('app/admin/admin.routing.1.ts (admin routing)', 'admin-routes')
|
||||
|
||||
h3#component-less-route <i>Component-Less Route</i>: grouping routes without a component
|
||||
h3#component-less-route <i>无组件路由</i>: 不借助组件对路由进行分组
|
||||
:marked
|
||||
Looking at our child route under the `AdminComponent`, we have a route with a **path** and a **children**
|
||||
property but it's not using a **component**. We haven't made a mistake in our configuration, because we can
|
||||
use a **component-less** route.
|
||||
|
||||
来看`AdminComponent`下的子路由,我们有一个带**path**和**children**的子路由,但它没有使用**component**。这并不是配置中的失误,而是在使用**无组件**路由。
|
||||
|
||||
We want to group our `Crisis Center` management routes under the `admin` path, but we don't need a component
|
||||
just to group those routes under an additional `RouterOutlet`. This also allows us to [guard child routes](#can-activate-child-guard).
|
||||
|
||||
虽然我们希望对`admin`路径下的`危机中心`管理类路由进行分组,但并不需要一个仅用来通过额外的`RouterOutlet`分组路由的组件。
|
||||
这同时也允许我们[守卫子路由](#can-activate-child-guard)。
|
||||
|
||||
:marked
|
||||
Next, we'll import the `AdminModule` into our `app.module.ts` and add it to the `imports` array
|
||||
to register our admin routes.
|
||||
|
||||
接下来,我们把`AdminModule`导入到`app.module.ts`中,并把它加入`imports`数组中来注册这些管理类路由。
|
||||
|
||||
+makeExcerpt('app/app.module.3.ts (admin module)', 'admin-module')
|
||||
|
||||
|
@ -2821,27 +3063,41 @@ h3#component-less-route <i>Component-Less Route</i>: grouping routes without a c
|
|||
Guards and the service providers they require **must** be provided at the module-level. This allows
|
||||
the Router access to retrieve these services from the `Injector` during the navigation process.
|
||||
The same rule applies for feature modules loaded [asynchronously](#asynchronous-routing).
|
||||
|
||||
它们所需的守卫和服务提供商**必须**在模块一级提供。这让路由器在导航过程中可以通过`Injector`来取得这些服务。
|
||||
同样的规则也适用于[异步加载](#asynchronous-routing)的特性模块。
|
||||
|
||||
h3#can-activate-child-guard <i>CanActivateChild</i>: guarding child routes
|
||||
h3#can-activate-child-guard <i>CanActivateChild</i>: 守卫子路由
|
||||
:marked
|
||||
As we learned about guarding routes with `CanActivate`, we can also protect child routes with the `CanActivateChild`
|
||||
guard. The `CanActivateChild` guard works similarly to the `CanActivate` guard, but the difference is its run _before_
|
||||
each child route is activated. We protected our admin feature module from unauthorized access, but we could also
|
||||
protect child routes within our feature module.
|
||||
|
||||
就像我们可以通过`CanActivate`来守卫路由一样,我们也能通过`CanActivateChild`守卫来保护子路由。`CanActivateChild`守卫的工作方式和`CanActivate`守卫很相似,不同之处在于它会在每个子路由被激活*之前*运行。我们保护了管理特性模块不受未授权访问,也同样可以在特性模块中保护子路由。
|
||||
|
||||
Let's extend our `AuthGuard` to protect when navigating between our `admin` routes. First we'll open our
|
||||
`auth-guard.service.ts` and add `CanActivateChild` interface to our imported tokens from the router package.
|
||||
|
||||
让我们扩展一下`AuthGuard`,让它能在`admin`路由之间导航时提供保护。首先,打开`auth-guard.serivce.ts`并从router包中导入`CanActiveChild`接口。
|
||||
|
||||
Next, we'll implement the `canActivateChild` method with takes the same arguments as the `canActivate` method,
|
||||
an `ActivatedRouteSnapshot` and `RouterStateSnapshot`. The `canActivateChild` behaves the same way the other
|
||||
guards do, returning an `Observable<boolean>` or `Promise<boolean>` for async checks and `boolean` for sync checks.
|
||||
We'll return a `boolean`
|
||||
We'll return a `boolean`:
|
||||
|
||||
然后,我们实现`canActivateChild`方法,它接收与`canActivate`方法相同的参数:`ActivatedRouteSnapshot`和`RouterStateSnapshot`。
|
||||
`canActivateChild`和其它守卫的行为一样,都返回`Observable<boolean>`或`Promise<boolean>`以支持异步检查,或返回`boolean`来支持同步检查。
|
||||
这里我们直接返回`boolean`:
|
||||
|
||||
+makeExcerpt('app/auth-guard.service.3.ts (excerpt)', 'can-activate-child')
|
||||
|
||||
:marked
|
||||
We add the same `AuthGuard` to our `component-less` admin route to protect all other child routes at one time
|
||||
instead of adding the `AuthGuard` to each route individually.
|
||||
|
||||
我们往“无组件”的管理路由中添加同一个`AuthGuard`以同时保护所有子路由,而不是挨个添加它们。
|
||||
|
||||
+makeExcerpt('app/admin/admin.routing.3.ts (excerpt)', 'can-activate-child')
|
||||
|
||||
|
@ -3324,6 +3580,8 @@ a#fragment
|
|||
If we look closer at the `loadChildren` string, we can see that it maps directly to our `admin.module.ts` file where we previously built
|
||||
out our `Admin` feature area. After the path to the file we use a `#` to denote where our file path ends and to tell the `Router` the name
|
||||
of our `AdminModule`. If we look in our `admin.module.ts` file, we can see it matches name of our exported module class.
|
||||
|
||||
仔细看`loadChildren`字符串,就会发现它直接映射到了我们以前在管理特性区构建的`admin.module.ts`文件
|
||||
|
||||
+makeExcerpt('app/admin/admin.module.ts (export)', 'admin-module-export')
|
||||
|
||||
|
|
Loading…
Reference in New Issue