翻译完了一部分新增英文内容
This commit is contained in:
parent
28fe7d848f
commit
5532c54ff7
|
@ -322,7 +322,7 @@ code-example(format="", language="html").
|
||||||
We bind each `RouterLink` to a string containing the path of a route.
|
We bind each `RouterLink` to a string containing the path of a route.
|
||||||
'/crisis-center' and '/heroes' are the paths of the `Routes` we configured above.
|
'/crisis-center' and '/heroes' are the paths of the `Routes` we configured above.
|
||||||
|
|
||||||
我们用`RouterLink`指令添加了两个A标签。每个`RouterLink`都绑定到了一个包含路由路径的数组上。
|
我们用`RouterLink`指令添加了两个带`RouterLink`和`RouterLinkActive`指令的A标签。每个`RouterLink`都绑定到了一个包含路由路径的字符串上。
|
||||||
'/crisis-center'和'/heroes'都是我们前面配置过的`Routes`中的路径。
|
'/crisis-center'和'/heroes'都是我们前面配置过的`Routes`中的路径。
|
||||||
|
|
||||||
We'll learn to write link expressions — and why they are arrays —
|
We'll learn to write link expressions — and why they are arrays —
|
||||||
|
@ -462,7 +462,7 @@ table
|
||||||
The directive for adding/removing classes from an HTML element when an associated
|
The directive for adding/removing classes from an HTML element when an associated
|
||||||
routerLink contained on or inside the element becomes active/inactive.
|
routerLink contained on or inside the element becomes active/inactive.
|
||||||
p.
|
p.
|
||||||
TODO: 翻译完。当HTML元素的相关routerLink。
|
当HTML元素上或元素内的routerLink变为激活或非激活状态时,该指令为这个HTML元素添加或移除CSS类。
|
||||||
tr
|
tr
|
||||||
td
|
td
|
||||||
p <code>RouterState</code>
|
p <code>RouterState</code>
|
||||||
|
@ -963,7 +963,7 @@ h3#router-link <i>RouterLink</i>绑定
|
||||||
Above the outlet, within the anchor tags, we see [Property Bindings](template-syntax.html#property-binding) to
|
Above the outlet, within the anchor tags, we see [Property Bindings](template-syntax.html#property-binding) to
|
||||||
the `RouterLink` directive that look like `routerLink="..."`. We imported `RouterLink` from the router library.
|
the `RouterLink` directive that look like `routerLink="..."`. We imported `RouterLink` from the router library.
|
||||||
|
|
||||||
在插座上方的A标签中,有一个绑定`RouterLink`指令的[属性绑定](template-syntax.html#property-binding),就像这样:`[routerLink]="[...]"`。我们从路由库中导入了`RouterLink`。
|
在插座上方的A标签中,有一个绑定`RouterLink`指令的[属性绑定](template-syntax.html#property-binding),就像这样:`routerLink="..."`。我们从路由库中导入了`RouterLink`。
|
||||||
|
|
||||||
The links in this example each have a string path, the path of a route that
|
The links in this example each have a string path, the path of a route that
|
||||||
we configured earlier. We don't have route parameters yet.
|
we configured earlier. We don't have route parameters yet.
|
||||||
|
@ -983,22 +983,35 @@ h3#router-link <i>RouterLink</i>绑定
|
||||||
:marked
|
:marked
|
||||||
Learn about the how we can also use the **link parameters array** in the [appendix below](#link-parameters-array).
|
Learn about the how we can also use the **link parameters array** in the [appendix below](#link-parameters-array).
|
||||||
|
|
||||||
|
还可以到[后面的附录](#link-parameters-array)中学习如何使用**链接参数数组**。
|
||||||
|
|
||||||
a#router-link-active
|
a#router-link-active
|
||||||
|
|
||||||
h3#router-link <i>RouterLinkActive</i> binding
|
h3#router-link <i>RouterLinkActive</i> binding
|
||||||
|
|
||||||
|
h3#router-link <i>RouterLinkActive</i>绑定
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
On each anchor tag, we also see [Property Bindings](template-syntax.html#property-binding) to
|
On each anchor tag, we also see [Property Bindings](template-syntax.html#property-binding) to
|
||||||
the `RouterLinkActive` directive that look like `routerLinkActive="..."`.
|
the `RouterLinkActive` directive that look like `routerLinkActive="..."`.
|
||||||
|
|
||||||
|
每个A标签还有一个到`RouterLinkActive`指令的[属性绑定](template-syntax.html#property-binding),就像`routerLinkActive="..."`。
|
||||||
|
|
||||||
The template expression to the right of the equals (=) contains our space-delimited string of CSS classes.
|
The template expression to the right of the equals (=) contains our space-delimited string of CSS classes.
|
||||||
We can also bind to the `RouterLinkActive` directive using an array of classes
|
We can also bind to the `RouterLinkActive` directive using an array of classes
|
||||||
such as `[routerLinkActive]="['...']"`.
|
such as `[routerLinkActive]="['...']"`.
|
||||||
|
|
||||||
|
等号(=)右侧的模板表达式包含用空格分隔的一些CSS类。我们还可以把`RouterLinkActive`指令绑定到一个CSS类组成的数组,如`[routerLinkActive]="['...']"`。
|
||||||
|
|
||||||
The `RouterLinkActive` directive toggles css classes for active `RouterLink`s based on the current `RouterState`.
|
The `RouterLinkActive` directive toggles css classes for active `RouterLink`s based on the current `RouterState`.
|
||||||
This cascades down through each level in our route tree, so parent and child router links can be active at the same time.
|
This cascades down through each level in our route tree, so parent and child router links can be active at the same time.
|
||||||
To override this behavior, we can bind to the `[routerLinkActiveOptions]` input binding with the `{ exact: true }` expression.
|
To override this behavior, we can bind to the `[routerLinkActiveOptions]` input binding with the `{ exact: true }` expression.
|
||||||
By using `{ exact: true }`, a given `RouterLink` will only be active if its URL is an exact match to the current URL.
|
By using `{ exact: true }`, a given `RouterLink` will only be active if its URL is an exact match to the current URL.
|
||||||
|
|
||||||
要学习关于链接参数数组的更多知识,参见[下面的附录](#link-parameters-array)。
|
`RouterLinkActive`指令会基于当前的`RouterState`对象来为激活的`RouterLink`切换CSS类。
|
||||||
|
这会一直沿着路由树往下进行级联处理,所以父路由链接和子路由链接可能会同时激活。
|
||||||
|
要改变这种行为,可以把`[routerLinkActiveOptions]`绑定到`{exact: true}`表达式。
|
||||||
|
如果使用了`{ exact: true }`,那么只有在其URL与当前URL精确匹配时才会激活指定的`RouterLink`。
|
||||||
|
|
||||||
h3#router-directives <i>ROUTER_DIRECTIVES</i>
|
h3#router-directives <i>ROUTER_DIRECTIVES</i>
|
||||||
|
|
||||||
|
@ -1008,7 +1021,7 @@ h3#router-directives <i>ROUTER_DIRECTIVES</i>(路由指令集)
|
||||||
`RouterLink`, `RouterLinkActive` and `RouterOutlet` are directives in the `ROUTER_DIRECTIVES` collection.
|
`RouterLink`, `RouterLinkActive` and `RouterOutlet` are directives in the `ROUTER_DIRECTIVES` collection.
|
||||||
Remember to add them to the `directives` array of the `@Component` metadata.
|
Remember to add them to the `directives` array of the `@Component` metadata.
|
||||||
|
|
||||||
`RouterLink`和`RouterOutlet`是`ROUTER_DIRECTIVES`集合中的指令。
|
`RouterLink`、`RouterLinkActive`和`RouterOutlet`是`ROUTER_DIRECTIVES`集合中的指令。
|
||||||
记住把它们加入`@Component`元数据的`directives`数组中。
|
记住把它们加入`@Component`元数据的`directives`数组中。
|
||||||
|
|
||||||
+makeExample('router/ts/app/app.component.1.ts','directives')(format=".")
|
+makeExample('router/ts/app/app.component.1.ts','directives')(format=".")
|
||||||
|
@ -1380,7 +1393,7 @@ h3#navigate 命令式地导航到英雄详情
|
||||||
with a `RouterLink` if we want to use it in HTML rather than code.
|
with a `RouterLink` if we want to use it in HTML rather than code.
|
||||||
|
|
||||||
它用一个**链接参数数组**调用路由器的**`navigate`**方法。
|
它用一个**链接参数数组**调用路由器的**`navigate`**方法。
|
||||||
该数组与我们[以前](#shell-template)在A标签中用来绑定到`RouterLink`指令的链接参数数组很相似。只是这次它出现在代码而不是HTML中。
|
如果我们想把它用在HTML中,那么也可以把相同的语法用在`RouterLink`中。
|
||||||
|
|
||||||
h3#route-parameters Setting the route parameters in the list view
|
h3#route-parameters Setting the route parameters in the list view
|
||||||
|
|
||||||
|
@ -1582,7 +1595,7 @@ h3#nav-to-list 导航回列表组件
|
||||||
that we can bind to a `[routerLink]` directive.
|
that we can bind to a `[routerLink]` directive.
|
||||||
It holds the **path to the `HeroListComponent`**:
|
It holds the **path to the `HeroListComponent`**:
|
||||||
|
|
||||||
路由的`navigate`方法同样接受一个单条目的*链接参数数组*,我们曾把它绑定到应用壳中“英雄”区的`[routerLink]`指令上。
|
路由的`navigate`方法同样接受一个单条目的*链接参数数组*,我们也可以把它绑定到`[routerLink]`指令上。
|
||||||
它保存着**到`HeroListComponent`组件的路径**:
|
它保存着**到`HeroListComponent`组件的路径**:
|
||||||
|
|
||||||
+makeExample('router/ts/app/heroes/hero-detail.component.1.ts','gotoHeroes')(format=".")
|
+makeExample('router/ts/app/heroes/hero-detail.component.1.ts','gotoHeroes')(format=".")
|
||||||
|
@ -1902,7 +1915,7 @@ h3#child-routing-component 子路由组件
|
||||||
These two routes navigate to the two *Crisis Center* child components,
|
These two routes navigate to the two *Crisis Center* child components,
|
||||||
`CrisisListComponent` and `CrisisDetailComponent`.
|
`CrisisListComponent` and `CrisisDetailComponent`.
|
||||||
|
|
||||||
注意,父路由`/crisis-center`有一个`children`属性,它是一个带两个路由的数组。
|
注意,父路由`crisis-center`有一个`children`属性,它是一个带两个路由的数组。
|
||||||
|
|
||||||
There are some *important differences* in the treatment of these routes.
|
There are some *important differences* in the treatment of these routes.
|
||||||
|
|
||||||
|
@ -2232,7 +2245,7 @@ h3#can-activate-guard <i>CanActivate</i>: 要求认证
|
||||||
This is a general purpose guard — we can imagine other features that require authenticated users —
|
This is a general purpose guard — we can imagine other features that require authenticated users —
|
||||||
so we create an `auth-guard.service.ts` in the application root folder.
|
so we create an `auth-guard.service.ts` in the application root folder.
|
||||||
|
|
||||||
这是一种具有通用性的守护目标(通常会有其它特性需要登录用户才能访问),所以我们在应用的根目录下创建一个`auth.guard.ts`文件。
|
这是一种具有通用性的守护目标(通常会有其它特性需要登录用户才能访问),所以我们在应用的根目录下创建一个`auth-guard.ts`文件。
|
||||||
|
|
||||||
At the moment we're interested in seeing how guards work so our first version does nothing useful.
|
At the moment we're interested in seeing how guards work so our first version does nothing useful.
|
||||||
It simply logs to console and `returns` true immediately, allowing navigation to proceed:
|
It simply logs to console and `returns` true immediately, allowing navigation to proceed:
|
||||||
|
@ -2278,6 +2291,7 @@ h3#can-activate-guard <i>CanActivate</i>: 要求认证
|
||||||
虽然它不会真的进行登录,但足够让我们进行这个讨论了。
|
虽然它不会真的进行登录,但足够让我们进行这个讨论了。
|
||||||
它有一个`isLoggedIn`标志,用来标识是否用户已经登录过了。
|
它有一个`isLoggedIn`标志,用来标识是否用户已经登录过了。
|
||||||
它的`login`方法会仿真一个对外部服务的API调用,返回一个可观察对象(observable)。在短暂的停顿之后,这个可观察对象就会解析成功。
|
它的`login`方法会仿真一个对外部服务的API调用,返回一个可观察对象(observable)。在短暂的停顿之后,这个可观察对象就会解析成功。
|
||||||
|
`redirectUrl`属性将会保存在URL中,以便认证完之后导航到它。
|
||||||
|
|
||||||
Let's revise our `AuthGuard` to call it.
|
Let's revise our `AuthGuard` to call it.
|
||||||
|
|
||||||
|
@ -2584,7 +2598,8 @@ figure.image-display
|
||||||
The Component Router supports navigation with query strings as well as route parameters.
|
The Component Router supports navigation with query strings as well as route parameters.
|
||||||
We define _optional_ query string parameters in an *object* after we define our required route parameters.
|
We define _optional_ query string parameters in an *object* after we define our required route parameters.
|
||||||
|
|
||||||
像路由参数一样,组件路由器也支持使用查询字符串进行导航。同样,我们也在*路由参数对象*中定义查询字符串参数。
|
像路由参数一样,组件路由器也支持使用查询字符串进行导航。
|
||||||
|
在定义了必须的路由参数之后,我们还可以在*路由参数对象*中定义_可选的_查询字符串参数。
|
||||||
|
|
||||||
<a id="route-or-query-parameter"></a>
|
<a id="route-or-query-parameter"></a>
|
||||||
|
|
||||||
|
@ -2759,7 +2774,6 @@ code-example(format="." language="bash").
|
||||||
This time we'll be navigating in the opposite direction, from the `HeroDetailComponent` to the `HeroListComponent`.
|
This time we'll be navigating in the opposite direction, from the `HeroDetailComponent` to the `HeroListComponent`.
|
||||||
|
|
||||||
现在就要进行反向导航了 —— 从`HeroDetailComponent`到`HeroListComponent`。
|
现在就要进行反向导航了 —— 从`HeroDetailComponent`到`HeroListComponent`。
|
||||||
这次我们把`Router`服务注入到`HeroListComponent`的构造函数中。
|
|
||||||
|
|
||||||
First we extend the router import statement to include the `ActivatedRoute` service symbol;
|
First we extend the router import statement to include the `ActivatedRoute` service symbol;
|
||||||
|
|
||||||
|
@ -2771,7 +2785,7 @@ code-example(format="." language="bash").
|
||||||
Then we use the `ActivatedRoute` to access the `params` _Observable_ so we can subscribe
|
Then we use the `ActivatedRoute` to access the `params` _Observable_ so we can subscribe
|
||||||
and extract the `id` parameter as the `selectedId`:
|
and extract the `id` parameter as the `selectedId`:
|
||||||
|
|
||||||
然后,使用`routerState`来访问全局可用的查询参数`Observable`,以便我们能订阅,并把`id`参数提取为`selectedId`属性:
|
然后,使用`ActivatedRoute`来访问可观察对象`params`,以便我们能订阅它,并把`id`参数提取成`selectedId`属性:
|
||||||
|
|
||||||
+makeExample('router/ts/app/heroes/hero-list.component.ts','ctor', 'hero-list.component.ts (constructor)')(format=".")
|
+makeExample('router/ts/app/heroes/hero-list.component.ts','ctor', 'hero-list.component.ts (constructor)')(format=".")
|
||||||
|
|
||||||
|
@ -2824,36 +2838,59 @@ figure.image-display
|
||||||
our route, but what if we wanted optional parameters available to all routes? This is where our
|
our route, but what if we wanted optional parameters available to all routes? This is where our
|
||||||
query parameters come into play and serve a special purpose in our application.
|
query parameters come into play and serve a special purpose in our application.
|
||||||
|
|
||||||
TODO: 翻译
|
在这个[查询参数](#query-parameters)例子中,我们只为路由指定了参数,但是该如何定义一些所有路由中都可用的可选参数呢?
|
||||||
|
要达到这个目的,该“查询参数”大显身手了。
|
||||||
|
|
||||||
Traditional query string parameters (?name=value) **persist** across route navigations. This means we can pass these query params
|
Traditional query string parameters (?name=value) **persist** across route navigations. This means we can pass these query params
|
||||||
around without having to specify them in each navigation method whether it be declaratively or imperatively.
|
around without having to specify them in each navigation method whether it be declaratively or imperatively.
|
||||||
|
|
||||||
|
传统的查询字符串参数(?name=value)在跨路由导航时会**始终存在**。这意味着我们可以传入这些查询参数,而不用被迫在每个导航方法中都指定它们 —— 无论是声明式的(链接)还是命令式的(程序中调用)。
|
||||||
|
|
||||||
[Fragments](https://en.wikipedia.org/wiki/Fragment_identifier) refer to certain elements on the page
|
[Fragments](https://en.wikipedia.org/wiki/Fragment_identifier) refer to certain elements on the page
|
||||||
identified with an `id` attribute.
|
identified with an `id` attribute.
|
||||||
|
|
||||||
|
[片段](https://en.wikipedia.org/wiki/Fragment_identifier)可以引用页面中带有特定`id`属性的元素.
|
||||||
|
|
||||||
We'll update our `AuthGuard` to provide a `session_id` query that will remain after navigating to another route.
|
We'll update our `AuthGuard` to provide a `session_id` query that will remain after navigating to another route.
|
||||||
|
|
||||||
|
接下来,我们将更新`AuthGuard`来提供`session_id`查询参数,在导航到其它路由后,它还会存在。
|
||||||
|
|
||||||
We'll also provide an arbitrary `anchor` fragment, which we would use to jump to a certain point on our page.
|
We'll also provide an arbitrary `anchor` fragment, which we would use to jump to a certain point on our page.
|
||||||
|
|
||||||
|
我们还将随意提供一个锚点片段,它用来跳转到页面中指定的位置。
|
||||||
|
|
||||||
We'll add the extra navigation object to our `router.navigate` method that navigates us to our `/login` route.
|
We'll add the extra navigation object to our `router.navigate` method that navigates us to our `/login` route.
|
||||||
|
|
||||||
|
我们还将为`router.nativate`方法传入一个额外的导航对象参数,用来导航到`/login`路由。
|
||||||
|
|
||||||
+makeExample('router/ts/app/auth-guard.service.ts','', 'auth-guard.service.ts (v.3)')
|
+makeExample('router/ts/app/auth-guard.service.ts','', 'auth-guard.service.ts (v.3)')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Since we'll be navigating to our *Crisis Admin* route after logging in, we'll update it to handle our global
|
Since we'll be navigating to our *Crisis Admin* route after logging in, we'll update it to handle our global
|
||||||
query parameters and fragment.
|
query parameters and fragment.
|
||||||
|
|
||||||
|
由于要在登录后导航到*危机管理*功能区的路由,所以我们还得更新它,来处理这些全局查询参数和片段。
|
||||||
|
|
||||||
+makeExample('router/ts/app/crisis-center/crisis-admin.component.ts','', 'crisis-admin.component.ts (v.2)')
|
+makeExample('router/ts/app/crisis-center/crisis-admin.component.ts','', 'crisis-admin.component.ts (v.2)')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
*Query Parameters* and *Fragments* are available through the `routerState` property in our `Router` service.
|
*Query Parameters* and *Fragments* are available through the `routerState` property in our `Router` service.
|
||||||
Just like our *route parameters*, global query parameters and fragments are provided as an `Observable`.
|
Just like our *route parameters*, global query parameters and fragments are provided as an `Observable`.
|
||||||
For our updated *Crisis Admin* component we'll feed the `Observable` directly into our template using the `AsyncPipe`, which
|
For our updated *Crisis Admin* component we'll feed the `Observable` directly into our template using the `AsyncPipe`, which
|
||||||
will handle _unsubscribing_ from the `Observable` for us when the component is destroyed.
|
will handle _unsubscribing_ from the `Observable` for us when the component is destroyed.
|
||||||
|
|
||||||
|
*查询参数*和*片段*可通过`Router`服务的`routerState`属性使用。和*路由参数*类似,全局查询参数和片段也是`Observable`对象。
|
||||||
|
在更新过的*英雄管理*组件中,我们将直接把`Observable`传给模板,借助`AsyncPipe`在组件被销毁时自动_取消_对`Observable`的订阅。
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
|
|
||||||
img(src='/resources/images/devguide/plunker-separate-window-button.png' alt="pop out the window" align="right" style="margin-right:-20px")
|
img(src='/resources/images/devguide/plunker-separate-window-button.png' alt="pop out the window" align="right" style="margin-right:-20px")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
When running in plunker, pop out the preview window by clicking the blue 'X' button in the upper right corner.
|
When running in plunker, pop out the preview window by clicking the blue 'X' button in the upper right corner.
|
||||||
|
|
||||||
|
当在plunker中运行时,可以点击右上角的蓝色'X'按钮来弹出预览窗口。
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Following the steps in this process, we can click on the *Crisis Admin* button, that takes us to the *Login*
|
Following the steps in this process, we can click on the *Crisis Admin* button, that takes us to the *Login*
|
||||||
page with our provided `query params` and `fragment`. After we click the login button, we notice that
|
page with our provided `query params` and `fragment`. After we click the login button, we notice that
|
||||||
|
@ -2861,6 +2898,10 @@ figure.image-display
|
||||||
these persistent bits of information for things that need to be provided with every page interaction like
|
these persistent bits of information for things that need to be provided with every page interaction like
|
||||||
authentication tokens or session ids.
|
authentication tokens or session ids.
|
||||||
|
|
||||||
|
按照下列步骤试验下:点击*Crisis Admin*按钮,它会带着我们提供的“查询参数”和“片段”跳转到登录页。
|
||||||
|
点击登录按钮,我们就会被带到`Crisis Admin`页,仍然带着上一步提供的“查询参数”和“片段”。
|
||||||
|
我们可以用这些持久化信息来携带需要为每个页面都提供的信息,如认证令牌或会话的ID等。
|
||||||
|
|
||||||
<a id="final-app"></a>
|
<a id="final-app"></a>
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
|
@ -2904,11 +2945,24 @@ figure.image-display
|
||||||
|
|
||||||
We've mentioned the *Link Parameters Array* several times. We've used it several times.
|
We've mentioned the *Link Parameters Array* several times. We've used it several times.
|
||||||
|
|
||||||
|
我们已经数次提及*链接参数数组*,也用过好几次了。
|
||||||
|
|
||||||
A link parameters array holds the ingredients for router navigation:
|
A link parameters array holds the ingredients for router navigation:
|
||||||
|
|
||||||
|
链接参数数组保存路由导航时所需的成分:
|
||||||
|
|
||||||
* the *path* of the route to the destination component
|
* the *path* of the route to the destination component
|
||||||
|
|
||||||
|
* 指向目标组件的那个路由的*路径(path)*
|
||||||
|
|
||||||
* required route parameters and optional query parameters that go into the route URL
|
* required route parameters and optional query parameters that go into the route URL
|
||||||
|
|
||||||
|
* 必须的路由参数和可选的查询参数,它们将进入该路由的URL
|
||||||
|
|
||||||
We can bind the `RouterLink` directive to such an array like this:
|
We can bind the `RouterLink` directive to such an array like this:
|
||||||
|
|
||||||
|
我们可以把`RouterLink`指令绑定到一个数组,就像这样:
|
||||||
|
|
||||||
+makeExample('router/ts/app/app.component.3.ts', 'h-anchor')(format=".")
|
+makeExample('router/ts/app/app.component.3.ts', 'h-anchor')(format=".")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
|
@ -2920,12 +2974,15 @@ figure.image-display
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
We can provide optional query parameters in an object like this:
|
We can provide optional query parameters in an object like this:
|
||||||
|
|
||||||
|
我们可以在对象中提供可选的查询参数,就像这样:
|
||||||
|
|
||||||
+makeExample('router/ts/app/app.component.3.ts', 'cc-query-params')(format=".")
|
+makeExample('router/ts/app/app.component.3.ts', 'cc-query-params')(format=".")
|
||||||
:marked
|
:marked
|
||||||
These three examples cover our needs for an app with one level routing.
|
These three examples cover our needs for an app with one level routing.
|
||||||
The moment we add a child router, such as the *Crisis Center*, we create new link array possibilities.
|
The moment we add a child router, such as the *Crisis Center*, we create new link array possibilities.
|
||||||
|
|
||||||
这两个例子覆盖了我们在单级路由的应用中所需的一切。在添加一个像*危机中心*一样的子路由时,我们创建新链接数组组合。
|
这三个例子覆盖了我们在单级路由的应用中所需的一切。在添加一个像*危机中心*一样的子路由时,我们创建新链接数组组合。
|
||||||
|
|
||||||
Recall that we specified a default child route for *Crisis Center* so this simple `RouterLink` is fine.
|
Recall that we specified a default child route for *Crisis Center* so this simple `RouterLink` is fine.
|
||||||
|
|
||||||
|
@ -2980,7 +3037,6 @@ figure.image-display
|
||||||
|
|
||||||
* 详细的子路由需要一个`id`路由参数。
|
* 详细的子路由需要一个`id`路由参数。
|
||||||
|
|
||||||
* We add `id` of the *Dragon Crisis* as the third item in the array (`1`)
|
|
||||||
* We add `id` of the *Dragon Crisis* as the second item in the array (`1`)
|
* We add `id` of the *Dragon Crisis* as the second item in the array (`1`)
|
||||||
|
|
||||||
* 我们把*巨龙危机*的`id`添加为该数组中的第二个条目(`1`)。
|
* 我们把*巨龙危机*的`id`添加为该数组中的第二个条目(`1`)。
|
||||||
|
|
|
@ -605,38 +605,70 @@ block observables-section
|
||||||
:marked
|
:marked
|
||||||
## Observables
|
## Observables
|
||||||
|
|
||||||
|
## 可观察对象(Observable)
|
||||||
|
|
||||||
Each `Http` method returns an `Observable` of HTTP `Response` objects.
|
Each `Http` method returns an `Observable` of HTTP `Response` objects.
|
||||||
|
|
||||||
|
每个`Http`方法都返回一个Http `Response`对象的`Observable`实例。
|
||||||
|
|
||||||
Our `HeroService` converts that `Observable` into a `Promise` and returns the promise to the caller.
|
Our `HeroService` converts that `Observable` into a `Promise` and returns the promise to the caller.
|
||||||
In this section we learn to return the `Observable` directly and discuss when and why that might be
|
In this section we learn to return the `Observable` directly and discuss when and why that might be
|
||||||
a good thing to do.
|
a good thing to do.
|
||||||
|
|
||||||
|
我们的`HeroService`中把那个`Observable`对象转换成了`Promise`(承诺),并把这个承诺返回给了调用者。
|
||||||
|
这一节,我们将学会直接返回`Observable`,并且讨论何时以及为何那样做会更好。
|
||||||
|
|
||||||
### Background
|
### Background
|
||||||
|
|
||||||
|
### 背景
|
||||||
|
|
||||||
An *observable* is a stream of events that we can process with array-like operators.
|
An *observable* is a stream of events that we can process with array-like operators.
|
||||||
|
|
||||||
|
一个*可观察对象*是一个事件流,我们可以用数组型操作符(函数)来处理它。
|
||||||
|
|
||||||
Angular core has basic support for observables. We developers augment that support with
|
Angular core has basic support for observables. We developers augment that support with
|
||||||
operators and extensions from the [RxJS Observables](http://reactivex.io/rxjs/) library.
|
operators and extensions from the [RxJS Observables](http://reactivex.io/rxjs/) library.
|
||||||
We'll see how shortly.
|
We'll see how shortly.
|
||||||
|
|
||||||
|
Angular内核中提供了对可观察对象的基本支持。而我们这些开发人员可以自己从[RxJS可观察对象](http://reactivex.io/rxjs/)库中引入操作符和扩展。
|
||||||
|
我们会简短的讲解下如何做。
|
||||||
|
|
||||||
Recall that our `HeroService` quickly chained the `toPromise` operator to the `Observable` result of `http.get`.
|
Recall that our `HeroService` quickly chained the `toPromise` operator to the `Observable` result of `http.get`.
|
||||||
That operator converted the `Observable` into a `Promise` and we passed that promise back to the caller.
|
That operator converted the `Observable` into a `Promise` and we passed that promise back to the caller.
|
||||||
|
|
||||||
|
快速回忆一下`HeroService`,它在`http.get`返回的`Observable`后面串联了一个`toPromise`操作符。
|
||||||
|
该操作符把`Observable`转换成了`Promise`(承诺),并且我们把那个“承诺”返回给了调用者。
|
||||||
|
|
||||||
Converting to a promise is often a good choice. We typically ask `http` to fetch a single chunk of data.
|
Converting to a promise is often a good choice. We typically ask `http` to fetch a single chunk of data.
|
||||||
When we receive the data, we're done.
|
When we receive the data, we're done.
|
||||||
A single result in the form of a promise is easy for the calling component to consume
|
A single result in the form of a promise is easy for the calling component to consume
|
||||||
and it helps that promises are widely understood by JavaScript programmers.
|
and it helps that promises are widely understood by JavaScript programmers.
|
||||||
|
|
||||||
|
转换成承诺通常是更好地选择,我们通常要求`http`获取单块数据。只要接收到数据,就算完成。
|
||||||
|
使用承诺这种形式的结果是让调用方更容易写,并且承诺已经在JavaScript程序员中被广泛接受了。
|
||||||
|
|
||||||
But requests aren't always "one and done". We may start one request,
|
But requests aren't always "one and done". We may start one request,
|
||||||
then cancel it, and make a different request ... before the server has responded to the first request.
|
then cancel it, and make a different request ... before the server has responded to the first request.
|
||||||
Such a _request-cancel-new-request_ sequence is difficult to implement with *promises*.
|
Such a _request-cancel-new-request_ sequence is difficult to implement with *promises*.
|
||||||
It's easy with *observables* as we'll see.
|
It's easy with *observables* as we'll see.
|
||||||
|
|
||||||
|
但是请求并非总是“一次性”的。我们可以开始一个请求,并且取消它,再开始另一个不同的请求 —— 在服务器对第一个请求作出回应之前。
|
||||||
|
像这样一个_请求-取消-新请求_的序列用*承诺*是很难实现的,但接下来我们会看到,它对于*可观察对象*却很简单。
|
||||||
|
|
||||||
### Search-by-name
|
### Search-by-name
|
||||||
|
|
||||||
|
### 按名搜索
|
||||||
|
|
||||||
We're going to add a *hero search* feature to the Tour of Heroes.
|
We're going to add a *hero search* feature to the Tour of Heroes.
|
||||||
As the user types a name into a search box, we'll make repeated http requests for heroes filtered by that name.
|
As the user types a name into a search box, we'll make repeated http requests for heroes filtered by that name.
|
||||||
|
|
||||||
|
我们要为《英雄指南》添加一个*英雄搜索*特性。
|
||||||
|
当用户在搜索框中输入一个名字时,我们将不断发起http请求,以获得按名字过滤的英雄。
|
||||||
|
|
||||||
We start by creating `HeroSearchService` that sends search queries to our server's web api.
|
We start by creating `HeroSearchService` that sends search queries to our server's web api.
|
||||||
|
|
||||||
|
我们先创建`HeroSearchService`服务,它会把搜索请求发送到我们服务器上的Web API。
|
||||||
|
|
||||||
+makeExample('toh-6/ts/app/hero-search.service.ts', null, 'app/hero-search.service.ts')(format=".")
|
+makeExample('toh-6/ts/app/hero-search.service.ts', null, 'app/hero-search.service.ts')(format=".")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
|
@ -644,48 +676,92 @@ block observables-section
|
||||||
The notable difference: we no longer call `toPromise`.
|
The notable difference: we no longer call `toPromise`.
|
||||||
We simply return the *observable* instead.
|
We simply return the *observable* instead.
|
||||||
|
|
||||||
|
`HeroSearchService`中的`http.get`调用和`HeroService`中的很相似。
|
||||||
|
显著的不同是:我们不再调用`toPromise`,而是直接返回*可观察对象*。
|
||||||
|
|
||||||
### HeroSearchComponent
|
### HeroSearchComponent
|
||||||
|
|
||||||
|
### HeroSearchComponent
|
||||||
|
|
||||||
Let's create a new `HeroSearchComponent` that calls this new `HeroSearchService`.
|
Let's create a new `HeroSearchComponent` that calls this new `HeroSearchService`.
|
||||||
|
|
||||||
|
我们再创建一个新的`HeroSearchComponent`来调用这个新的`HeroSearchService`。
|
||||||
|
|
||||||
The component template is simple - just a textbox and a list of matching search results.
|
The component template is simple - just a textbox and a list of matching search results.
|
||||||
|
|
||||||
|
组件模板很简单,就是一个输入框和一个相匹配的搜索结果列表。
|
||||||
|
|
||||||
+makeExample('toh-6/ts/app/hero-search.component.html', null,'hero-search.component.html')
|
+makeExample('toh-6/ts/app/hero-search.component.html', null,'hero-search.component.html')
|
||||||
:marked
|
:marked
|
||||||
As the user types in the search box, a *keyup* event binding calls the component's `search` with the new search box value.
|
As the user types in the search box, a *keyup* event binding calls the component's `search` with the new search box value.
|
||||||
|
|
||||||
|
当用户在搜索框中输入时,一个*keyup*事件绑定会调用该组件的`search`方法,并传入新的搜索框的值。
|
||||||
|
|
||||||
The `*ngFor` repeats *hero* objects from the component's `heroes` property. No surprise there.
|
The `*ngFor` repeats *hero* objects from the component's `heroes` property. No surprise there.
|
||||||
|
|
||||||
|
`*ngFor`为该组件的`heroes`属性重复*hero*对象。这也没啥特别的。
|
||||||
|
|
||||||
But, as we'll soon see, the `heroes` property returns an `Observable` of heroes, not an array of heroes.
|
But, as we'll soon see, the `heroes` property returns an `Observable` of heroes, not an array of heroes.
|
||||||
The `*ngFor` can't do anything with an observable until we flow it through the `AsyncPipe` (`heroes | async`).
|
The `*ngFor` can't do anything with an observable until we flow it through the `AsyncPipe` (`heroes | async`).
|
||||||
The `AsyncPipe` subscribes to the observable and produces the array of heroes to `*ngFor`.
|
The `AsyncPipe` subscribes to the observable and produces the array of heroes to `*ngFor`.
|
||||||
|
|
||||||
|
但是,接下来我们看到`heroes`属性返回了一个英雄们的`Observable`对象,不是英雄们的数组。
|
||||||
|
`*ngFor`不能利用可观察对象做任何事,除非我们在它后面跟一个`AsyncPipe`(`heroes | async`)。
|
||||||
|
`AsyncPipe`会订阅到这个可观察对象,并且为`*ngFor`生产一个英雄们的数组。
|
||||||
|
|
||||||
Time to create the `HeroSearchComponent` class and metadata.
|
Time to create the `HeroSearchComponent` class and metadata.
|
||||||
|
|
||||||
|
该创建`HeroSearchComponent`类及其元数据了。
|
||||||
|
|
||||||
+makeExample('toh-6/ts/app/hero-search.component.ts', null,'hero-search.component.ts')
|
+makeExample('toh-6/ts/app/hero-search.component.ts', null,'hero-search.component.ts')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Focus on the `searchSubject`.
|
Focus on the `searchSubject`.
|
||||||
|
|
||||||
|
仔细看`searchSubject`。
|
||||||
|
|
||||||
+makeExample('toh-6/ts/app/hero-search.component.ts', 'searchSubject')(format=".")
|
+makeExample('toh-6/ts/app/hero-search.component.ts', 'searchSubject')(format=".")
|
||||||
:marked
|
:marked
|
||||||
A `Subject` is a producer of an _observable_ event stream.
|
A `Subject` is a producer of an _observable_ event stream.
|
||||||
This `searchSubject` produces an `Observable` of strings, the filter criteria for the name search.
|
This `searchSubject` produces an `Observable` of strings, the filter criteria for the name search.
|
||||||
|
|
||||||
|
`Subject`(主体)是一个_可观察的_事件流中的生产者。
|
||||||
|
这里的`searchSubject`生产一些字符串的`Observable`,用于作为按名搜索时的过滤条件。
|
||||||
|
|
||||||
Each call to `search` puts a new string into this subject's _observable_ stream by calling `next`.
|
Each call to `search` puts a new string into this subject's _observable_ stream by calling `next`.
|
||||||
|
|
||||||
|
每次到`search`的调用都会调用`next`来把新的字符串放进该主体的_可观察_流中。
|
||||||
|
|
||||||
A `Subject` is also an `Observable`.
|
A `Subject` is also an `Observable`.
|
||||||
We're going to access that `Observable` and turn the stream
|
We're going to access that `Observable` and turn the stream
|
||||||
of strings into a stream of `Hero[]` arrays, the `heroes` property.
|
of strings into a stream of `Hero[]` arrays, the `heroes` property.
|
||||||
|
|
||||||
|
`Subject`也是一个`Observable`对象。
|
||||||
|
我们将访问`Observable`并且把字符串数组组成的流转换成`Hero[]`数组组成的流,也就是`heroes`属性。
|
||||||
|
|
||||||
+makeExample('toh-6/ts/app/hero-search.component.ts', 'search')(format=".")
|
+makeExample('toh-6/ts/app/hero-search.component.ts', 'search')(format=".")
|
||||||
:marked
|
:marked
|
||||||
If we passed every user keystroke directly to the `HeroSearchService`, we'd unleash a storm of http requests.
|
If we passed every user keystroke directly to the `HeroSearchService`, we'd unleash a storm of http requests.
|
||||||
Bad idea. We don't want to tax our server resources and burn through our cellular network data plan.
|
Bad idea. We don't want to tax our server resources and burn through our cellular network data plan.
|
||||||
|
|
||||||
|
如果我们直接把每一次用户按键都直接传给`HeroSearchService`,就会发起一场Http请求的风暴。
|
||||||
|
这可不好玩。我们不希望占用服务器资源,不想也耗尽网络带宽。
|
||||||
|
|
||||||
Fortunately we can chain `Observable` operators to the string `Observable` that reduce the request flow.
|
Fortunately we can chain `Observable` operators to the string `Observable` that reduce the request flow.
|
||||||
We'll make fewer calls to the `HeroSearchService` and still get timely results. Here's how:
|
We'll make fewer calls to the `HeroSearchService` and still get timely results. Here's how:
|
||||||
|
|
||||||
|
幸运的是,我们可以在字符串的`Observable`后面串联一个`Observable`操作符,来归并这些请求。
|
||||||
|
我们将对`HeroSearchService`发起更少的调用,并且仍然获得足够及时的响应。做法如下:
|
||||||
|
|
||||||
* The `asObservable` operator casts the `Subject` as an `Observable` of filter strings.
|
* The `asObservable` operator casts the `Subject` as an `Observable` of filter strings.
|
||||||
|
|
||||||
|
* `asObservable`操作符把`Subject`转换成过滤字符串组成的`Observable`。
|
||||||
|
|
||||||
* `debounceTime(300)` waits until the flow of new string events pauses for 300 milliseconds
|
* `debounceTime(300)` waits until the flow of new string events pauses for 300 milliseconds
|
||||||
before passing along the latest string. We'll never make requests more frequently than 300ms.
|
before passing along the latest string. We'll never make requests more frequently than 300ms.
|
||||||
|
|
||||||
|
* 在传出最终字符串之前,`debounceTime(300)`将会等待,直到新增字符串的事件暂停了300毫秒。我们实际发起请求的间隔永远不会小于300ms。
|
||||||
|
|
||||||
* `distinctUntilChanged` ensures that we only send a request if the filter text changed.
|
* `distinctUntilChanged` ensures that we only send a request if the filter text changed.
|
||||||
There's no point in repeating a request for the same search term.
|
There's no point in repeating a request for the same search term.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue