parent
654589b972
commit
33292b942c
|
@ -377,68 +377,69 @@ figure
|
|||
The `@Component` decorator takes a required configuration object with the
|
||||
information Angular needs to create and present the component and its view.
|
||||
|
||||
装饰器是一个函数。装饰器通常还带有配置参数。
|
||||
`@Component`装饰器可以接受一个配置对象,Angular会基于这些信息创建和展示组件及其视图。
|
||||
装饰器就是函数,它们通常还带有配置参数。
|
||||
`@Component`装饰器能接受一个配置对象,Angular会基于这些信息创建和展示组件及其视图。
|
||||
|
||||
Here we see a few of the possible `@Component` configuration options:
|
||||
|
||||
这里,我们看到`@Component`中的一些配置项:
|
||||
我们来看下`@Component`中的一些配置项:
|
||||
|
||||
* `selector` - a css selector that tells Angular to create and insert an instance of this component
|
||||
where it finds a `<hero-list>` tag in *parent* HTML.
|
||||
If the template of the application shell (a Component) contained
|
||||
|
||||
* `selector` - 一个css选择器,用来告诉Angular在 *父* HTML中,去寻找一个`<hero-list>`标签,然后创建组件,并插在此标签中。
|
||||
比如,如果应用“壳”组件的模板包含:
|
||||
* `selector` - 一个css选择器,它告诉Angular在*父*HTML中寻找一个`<hero-list>`标签,然后创建组件,并插入此标签中。
|
||||
比如,如果应用“壳”(组件)的模板包含如下代码:
|
||||
<div style="margin-left:30px">
|
||||
code-example(language="html").
|
||||
<hero-list></hero-list>
|
||||
</div>
|
||||
:marked
|
||||
>Angular inserts an instance of the `HeroListComponent` view between those tags.
|
||||
>Angular就会在这些标签中插入一个`HeroListComponent`视图的一个实例。
|
||||
|
||||
>Angular就会在这些标签中插入`HeroListComponent`视图的一个实例。
|
||||
|
||||
* `templateUrl` - the address of this component's template which we showed [above](#template).
|
||||
* `templateUrl` - 组件模板的地址,我们在[前面](#template)看到过。
|
||||
* `templateUrl` - 组件模板的地址,我们在[前面](#template)见过。
|
||||
* `directives` - an array of the Components or Directives that *this* template requires.
|
||||
We saw in the last line of our template that we expect Angular to insert a `HeroDetailComponent`
|
||||
in the space indicated by `<hero-detail>` tags.
|
||||
Angular will do so only if we mention the `HeroDetailComponent` in this `directives` array.
|
||||
* `directives` - 一个数组,包含 *此* 模板需要的组件或指令。
|
||||
看看模板的最后一行,这表示我们希望Angular把`HeroDetailComponent`的实例放在`<hero-detail>`标签中。
|
||||
但,只有当我们在`directives`数组中引用了`HeroDetailComponent`的时候,Angular才会这么做。
|
||||
* `directives` - 一个数组,包含*此*模板需要的组件或指令。
|
||||
看看模板的最后一行,这表示我们期待Angular把`HeroDetailComponent`的实例放在`<hero-detail>`标签中。
|
||||
但是,只有当我们在`directives`数组中引用过`HeroDetailComponent`的时候,Angular才会这么做。
|
||||
* `providers` - an array of **dependency injection providers** for services that the component requires.
|
||||
This is one way to tell Angular that our component's constructor requires a `HeroService`
|
||||
so it can get the list of heroes to display. We'll get to dependency injection in a moment.
|
||||
* `providers` - 一个数组,包含组件所依赖的用于提供服务的 *依赖注入供应者* 。
|
||||
这是我们让Angular知道组件的构造器需要一个`HeroService`服务的方式之一。这让组件能获得英雄的列表数据,并显示出来。
|
||||
接下来我们就开始讲依赖注入。
|
||||
* `providers` - 一个数组,包含组件所依赖的用于提供服务的*依赖注入供应商*。
|
||||
这是我们告诉Angular该组件的构造器需要一个`HeroService`服务的方式之一。所以组件才能获得英雄的列表数据,并显示出来。
|
||||
这样我们就在一瞬间完成了依赖注入。
|
||||
figure
|
||||
img(src="/resources/images/devguide/architecture/template-metadata-component.png" alt="元数据" align="left" style="height:200px; margin-left:-40px;margin-right:10px" )
|
||||
:marked
|
||||
The `@Component` function takes the configuration object and turns it into metadata that it attaches
|
||||
to the component class definition. Angular discovers this metadata at runtime and thus knows how to do "the right thing".
|
||||
|
||||
`@Component`函数接收一个配置对象,并且把它转换为元数据,附加到组件类的定义上。
|
||||
Angular在运行期间会发现这个元数据,并且据此了解到该如何“做正确的事”。
|
||||
`@Component`函数接收一个配置对象,并把它转换成元数据,附加到组件类的定义上。
|
||||
Angular在运行期间会找出这份元数据,并因此知道该如何去“做正确的事”。
|
||||
|
||||
The template, metadata, and component together describe the view.
|
||||
|
||||
模板、元数据和组件加在一起描绘这个视图。
|
||||
模板、元数据和组件共同描绘出这个视图。
|
||||
|
||||
We apply other metadata decorators in a similar fashion to guide Angular behavior.
|
||||
The `@Injectable`, `@Input`, `@Output`, `@RouterConfig` are a few of the more popular decorators
|
||||
we'll master as our Angular knowledge grows.
|
||||
|
||||
我们也会用类似的方式,通过其它的元数据装饰器来指导Angular的行为。
|
||||
我们也会沿用类似的风格,用其它元数据装饰器来指导Angular的行为。
|
||||
`@Injectable`、`@Input`、`@Output`、`@RouterConfig`是一些最常用的装饰器。
|
||||
随着Angular知识的逐步增长,我们将逐步掌握它们。
|
||||
随着对Angular认识的逐步深化,我们也将逐步掌握它们。
|
||||
<br clear="all">
|
||||
:marked
|
||||
The architectural take-away is that we must add metadata to our code
|
||||
so that Angular knows what to do.
|
||||
|
||||
架构所决定的是:我们必须在代码中添加元数据,以便Angular知道该做什么。
|
||||
这种架构所决定的是:我们必须往代码中添加元数据,以便Angular知道该做什么。
|
||||
|
||||
.l-main-section
|
||||
<a id="data-binding"></a>
|
||||
|
@ -449,8 +450,8 @@ figure
|
|||
into actions and value updates. Writing such push/pull logic by hand is tedious, error-prone and a nightmare to
|
||||
read as the experienced jQuery programmer can attest.
|
||||
|
||||
如果没有框架,我们就需要自己把数据值推送到HTML控件中,并且把用户的反馈转换成动作并更新值。
|
||||
如果手动写实现这些推/拉逻辑的代码,肯定会枯燥乏味、容易出错、很难读懂 —— 有经验的jQuery程序员大概对此深有体会。
|
||||
如果没有框架,我们就得自己把数据值推送到HTML控件中,并把用户的反馈转换成动作并更新值。
|
||||
如果手工写代码来实现这些推/拉逻辑,肯定会枯燥乏味、容易出错,读起来简直是噩梦 —— 写过jQuery的程序员大概都对此深有体会。
|
||||
figure
|
||||
img(src="/resources/images/devguide/architecture/databinding.png" alt="数据绑定" style="width:220px; float:left; margin-left:-40px;margin-right:20px" )
|
||||
:marked
|
||||
|
@ -458,13 +459,13 @@ figure
|
|||
a mechanism for coordinating parts of a template with parts of a component.
|
||||
We add binding markup to the template HTML to tell Angular how to connect both sides.
|
||||
|
||||
Angular支持 **数据绑定** ,一种让模板片段与组件片段相互合作的机制。
|
||||
Angular支持**数据绑定**,一种让模板的各部分与组件的各部分相互合作的机制。
|
||||
我们往模板HTML中添加绑定标记,来告诉Angular如何连接两者。
|
||||
|
||||
There are four forms of data binding syntax. Each form has a direction - to the DOM, from the DOM, or in both directions -
|
||||
as indicated by the arrows in the diagram.
|
||||
|
||||
数据绑定的语法有四种形式。每种形式都具有方向 —— 从DOM来、到DOM去、双向,就像图中的箭头所表示那样。
|
||||
数据绑定的语法有四种形式。每种形式都有一个方向 —— 从DOM来、到DOM去、双向,就像图中的箭头所示意的。
|
||||
<br clear="all">
|
||||
:marked
|
||||
We saw three forms of data binding in our [example](#template) template:
|
||||
|
@ -474,23 +475,23 @@ figure
|
|||
:marked
|
||||
* The {{hero.name}} "[interpolation](displaying-data.html#interpolation)"
|
||||
displays the component's `hero.name` property value within the `<div>` tags.
|
||||
* {{hero.name}} "[插值表达式](displaying-data.html#interpolation)"在`<div>`标签中显示了组件的`hero.name`属性的值。
|
||||
* {{hero.name}} "[插值表达式](displaying-data.html#interpolation):"在`<div>`标签中显示了组件的`hero.name`属性的值。
|
||||
|
||||
* The `[hero]` [property binding](template-syntax.html#property-binding) passes the `selectedHero` from
|
||||
the parent `HeroListComponent` to the `hero` property of the child `HeroDetailComponent`.
|
||||
* `[hero]`[属性绑定](template-syntax.html#property-binding)把父组件`HeroListComponent`的`selectedHero`传到子组件`HeroDetailComponent`的`hero`属性中。
|
||||
* `[hero]`[属性绑定](template-syntax.html#property-binding):把父组件`HeroListComponent`的`selectedHero`传到子组件`HeroDetailComponent`的`hero`属性中。
|
||||
|
||||
* The `(click)` [event binding](user-input.html#click) calls the Component's `selectHero` method when the user clicks
|
||||
on a hero's name
|
||||
* `(click)`[事件绑定](user-input.html#click)
|
||||
* `(click)`[事件绑定](user-input.html#click):当用户点击英雄的名字时,会调用组件的`selectHero`方法。
|
||||
|
||||
**Two-way data binding** is an important fourth form
|
||||
* **Two-way data binding** is an important fourth form
|
||||
that combines property and event binding in a single notation using the `ngModel` directive.
|
||||
We didn't have a two-way binding in the `HeroListComponent` template;
|
||||
here's an example from the `HeroDetailComponent` template (not shown):
|
||||
|
||||
**双向数据绑定** 是很重要的第四种绑定形式,它在`ngModel`指令这个单一的标记中同时实现了属性绑定和事件绑定的功能。
|
||||
在`HeroListComponent`模板中,没有双向绑定;下面是一个`HeroDetailComponent`模板中的范例(未显示):
|
||||
* **双向数据绑定**:这是很重要的第四种绑定形式,它在`ngModel`指令这个单一标记中同时实现了属性绑定和事件绑定的功能。
|
||||
在`HeroListComponent`模板中,没有双向绑定,下面是一个来自`HeroDetailComponent`模板的范例(以前没展示过):
|
||||
|
||||
+makeExample('architecture/ts/app/hero-detail.component.html', 'ngModel')(format=".")
|
||||
:marked
|
||||
|
@ -498,12 +499,12 @@ figure
|
|||
The user's changes also flow back to the component, resetting the property to the latest value,
|
||||
as with event binding.
|
||||
|
||||
在双向绑定中,组件中表示数据的属性值会由属性绑定传给输入框。用户的修改也会传回组件,通过事件绑定把最近的值传给属性。
|
||||
在双向绑定中,数据属性的值会从具有属性绑定的组件传到输入框。通过事件绑定把最近的值传给属性,用户的修改也能传回组件。
|
||||
|
||||
Angular processes *all* data bindings once per JavaScript event cycle,
|
||||
depth-first from the root of the application component tree.
|
||||
|
||||
Angular在每次JavaScript事件周期中处理一次 *所有的* 数据绑定,从组件树的根部开始进行深度优先遍历。
|
||||
Angular在每个JavaScript事件周期中一次性处理*所有的*数据绑定,它会从组件树的根部进行深度优先遍历来完成更新。
|
||||
figure
|
||||
img(src="/resources/images/devguide/architecture/component-databinding.png" alt="数据绑定" style="float:left; width:300px; margin-left:-40px;margin-right:10px" )
|
||||
:marked
|
||||
|
@ -511,14 +512,14 @@ figure
|
|||
but it's clear from these examples that data binding plays an important role in communication
|
||||
between a template and its component ...
|
||||
|
||||
虽然我们还没看懂所有细节,但从这些范例中,至少明白了一点:数据绑定在模板与相应组件的通讯中扮演了一个很重要的角色。
|
||||
虽然我们还没看懂所有细节,但从这些范例中至少弄明白一点:数据绑定在模板与相应组件的通讯中扮演了一个很重要的角色。
|
||||
<br clear="all">
|
||||
figure
|
||||
img(src="/resources/images/devguide/architecture/parent-child-binding.png" alt="父/子绑定" style="float:left; width:300px; margin-left:-40px;margin-right:10px" )
|
||||
:marked
|
||||
... ***and*** between parent and child components
|
||||
|
||||
... ***并且*** 在父组件和子组件之间。
|
||||
……在父组件与子组件的通讯中***也同样如此***。
|
||||
<br clear="all">
|
||||
|
||||
.l-main-section
|
||||
|
@ -532,18 +533,18 @@ figure
|
|||
Our Angular templates are *dynamic*. When Angular renders them, it transforms the DOM
|
||||
according to the instructions given by a **directive**.
|
||||
|
||||
我们的Angular模板是 *动态的* 。当Angular渲染它们时,它根据 **指令** 所提供的操作指南去转换DOM。
|
||||
我们的Angular模板是*动态的*。当Angular渲染它们时,它会根据**指令**中提供的操作指南对DOM进行修改。
|
||||
|
||||
A directive is a class with directive metadata. In TypeScript we'd apply the `@Directive` decorator
|
||||
to attach metadata to the class.
|
||||
|
||||
指令是一个带有“指令元数据”的类。在TypeScript中,我们得通过`@Directive`装饰器把元数据附加到类上。
|
||||
指令是一个带有“指令元数据”的类。在TypeScript中,我们要通过`@Directive`装饰器把元数据附加到类上。
|
||||
<br clear="all">
|
||||
:marked
|
||||
We already met one form of directive: the component. A component is a *directive-with-a-template*
|
||||
and the `@Component` decorator is actually a `@Directive` decorator extended with template-oriented features.
|
||||
|
||||
我们已经遇到了指令的一种形式:组件。组件是一个 *带模板的指令* ,而且`@Component`装饰器实际上就是一个`@Directive`装饰器,只是扩展出了面向模板的属性。
|
||||
我们已经遇到过指令的形式之一:组件。组件是一个*带模板的指令*,而且`@Component`装饰器实际上就是一个`@Directive`装饰器,只是扩展了一些面向模板的属性。
|
||||
|
||||
.l-sub-section
|
||||
:marked
|
||||
|
@ -551,20 +552,20 @@ figure
|
|||
it is so distinctive and central to Angular applications that we chose
|
||||
to separate the component from the directive in our architectural overview.
|
||||
|
||||
虽然 **组件从技术角度上说就是一个指令** ,它与众不同,而且在Angular位于中心地位,所以我们选择把它和指令分开画在我们的架构视图中。
|
||||
虽然**组件从技术角度说就是一个指令**,但它是如此与众不同,并在Angular中位于中心地位,以至于我们选择把它和指令分别画在我们的架构视图中。
|
||||
:marked
|
||||
There are two *other* kinds of directives as well that we call "structural" and "attribute" directives.
|
||||
|
||||
有两个 *其它* 类型的指令,我们称之为“结构型”和“属性型”指令。
|
||||
有两种*其它*类型的指令,我们称之为“结构型”指令和“属性型”指令。
|
||||
|
||||
They tend to appear within an element tag like attributes,
|
||||
sometimes by name but more often as the target of an assignment or a binding.
|
||||
|
||||
它们倾向于出现在元素标签中,比如属性(也有时是元素名),但通常还是作为赋值或绑定的目标。
|
||||
它们往往以Attribute的形式出现在元素标签中,偶尔以名字的形式,但多数时候还是作为赋值或绑定的目标。
|
||||
|
||||
**Structural** directives alter layout by adding, removing, and replacing elements in DOM.
|
||||
|
||||
**结构型指令** 通过在DOM中添加、移除和替换元素来修改布局。
|
||||
**结构型指令**通过在DOM中添加、移除和替换元素来修改布局。
|
||||
|
||||
We see two built-in structural directives at play in our [example](#template) template:
|
||||
|
||||
|
@ -741,14 +742,14 @@ figure
|
|||
In brief, we must have previously registered a **provider** of the `HeroService` with the `Injector`.
|
||||
A provider is something that can create or return a service, typically the service class itself.
|
||||
|
||||
简单的说,我们必须有以前通过注入器注册过的`HeroService` **Provider**。
|
||||
Provider就是某些我们用来创建并返回服务的东西,通常是这个服务类本身。
|
||||
简单的说,我们必须有以前通过注入器注册过的`HeroService`**供应商(Provider)**。
|
||||
供应商就是某些我们用来创建并返回服务的东西,通常是这个服务类本身。
|
||||
|
||||
We can register providers at any level of the application component tree.
|
||||
We often do so at the root when we bootstrap the application so that
|
||||
the same instance of a service is available everywhere.
|
||||
|
||||
我们可以在应用的组件树中的任何级别上注册Provider。
|
||||
我们可以在应用的组件树中的任何级别上注册供应商。
|
||||
我们通常在应用启动时注册在根组件上,以便此服务的同一个实例在任何地方都时可用的。
|
||||
+makeExample('architecture/ts/app/main.ts', 'bootstrap','app/main.ts (节选)')(format=".")
|
||||
:marked
|
||||
|
@ -777,12 +778,12 @@ figure
|
|||
* an injector maintains a *container* of service instances that it created.
|
||||
* 注入器负责维护一个用于存放它创建的服务实例的 *容器* 。
|
||||
* an injector can create a new service instance using a *provider*.
|
||||
* 注入器能通过 *Provider* 创建一个新的服务实例。
|
||||
* 注入器能通过*供应商*创建一个新的服务实例。
|
||||
* a *provider* is a recipe for creating a service.
|
||||
* *Provider* 是一个用于创建服务的“菜谱”。
|
||||
* *供应商*是一个用于创建服务的“配方”。
|
||||
|
||||
* we register *providers* with injectors.
|
||||
* 我们通过注入器注册 *供应者* 。
|
||||
* 我们通过注入器注册*供应商*。
|
||||
|
||||
<a id="other-stuff"></a>
|
||||
.l-main-section
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"bold": [
|
||||
"provide"
|
||||
],
|
||||
"description": "<p>以MyAppComponent作为根组件引导应用,并且配置DI的各种provider。</p>\n"
|
||||
"description": "<p>以MyAppComponent作为根组件引导应用,并且配置DI的各种供应商。</p>\n"
|
||||
}
|
||||
],
|
||||
"index": 0
|
||||
|
@ -418,7 +418,7 @@
|
|||
"provide",
|
||||
"useClass"
|
||||
],
|
||||
"description": "<p>把MyService类的Provider设置或改写为MyMockService。</p>\n"
|
||||
"description": "<p>把MyService类的供应商设置或改写为MyMockService。</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "provide(MyService, {useFactory: myFactory})",
|
||||
|
@ -426,7 +426,7 @@
|
|||
"provide",
|
||||
"useFactory"
|
||||
],
|
||||
"description": "<p>把MyService的Provider设置或改写为myFactory工厂函数。</p>\n"
|
||||
"description": "<p>把MyService的供应商设置或改写为myFactory工厂函数。</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "provide(MyValue, {useValue: 41})",
|
||||
|
@ -434,7 +434,7 @@
|
|||
"provide",
|
||||
"useValue"
|
||||
],
|
||||
"description": "<p>把MyValue的Provider设置或改写为值41。</p>\n"
|
||||
"description": "<p>把MyValue的供应商设置或改写为值41。</p>\n"
|
||||
}
|
||||
],
|
||||
"index": 9
|
||||
|
|
|
@ -386,9 +386,9 @@ include ../_util-fns
|
|||
We'll explain what [providers](#providers) are later in this chapter.
|
||||
Before we do, let's see an example of provider registration during bootstrapping:
|
||||
|
||||
我们必须先注册 **Provider** 来配置好注入器,这在创建应用所需的服务时会用到。
|
||||
我们将在本章的稍后部分解释什么是[Provider](#providers)。
|
||||
在此之前,我们先来看一个启动期间的注册Provider的例子。
|
||||
我们必须先注册**供应商**来配置好注入器,这在创建应用所需的服务时会用到。
|
||||
我们将在本章的稍后部分解释什么是[供应商](#providers)。
|
||||
在此之前,我们先来看一个启动期间的注册供应商的例子。
|
||||
// #enddocregion di-configure-injector-2
|
||||
+makeExample('dependency-injection/ts/app/main.1.ts', 'bootstrap')(format='.')
|
||||
// #docregion di-configure-injector-3
|
||||
|
@ -405,20 +405,20 @@ include ../_util-fns
|
|||
preregistered services, such as its routing support.
|
||||
|
||||
当然,我们不禁要问,为什么注释中告诉我们不要这么做。
|
||||
它 *能* 工作,但不是最佳实践。
|
||||
bootstrap函数的Provider选项是用来配置和改写Angular自身的预注册服务的,比如它的路由支持。
|
||||
它*能*工作,但不是最佳实践。
|
||||
bootstrap函数的供应商选项是用来配置和改写Angular自身的预注册服务的,比如它的路由支持。
|
||||
|
||||
The preferred approach is to register application providers in application components.
|
||||
Because the `HeroService` is used within the *Heroes* feature area —
|
||||
and nowhere else — the ideal place to register it is in the top-level `HeroesComponent`.
|
||||
|
||||
首选的方式是在应用组件中注册应用级的Provider。
|
||||
因为`HeroService`是用于 *英雄* 功能区的 —— 并且没别处用它 —— 所以注册它的理想地点就是`HeroesComponent`的顶层。
|
||||
首选的方式是在应用组件中注册应用级的供应商。
|
||||
因为`HeroService`是用于*英雄*功能区的 —— 并且没别处用它 —— 所以注册它的理想地点就是`HeroesComponent`的顶层。
|
||||
// #enddocregion di-configure-injector-3
|
||||
// #docregion di-register-providers-1
|
||||
:marked
|
||||
### Registering providers in a component
|
||||
### 在组件中注册Provider
|
||||
### 在组件中注册供应商
|
||||
Here's a revised `HeroesComponent` that registers the `HeroService`.
|
||||
|
||||
这里是注册了`HeroService`的修改版`HeroesComponent`。
|
||||
|
@ -709,7 +709,7 @@ code-example(format, language="html").
|
|||
EXCEPTION: No provider for Logger! (HeroListComponent -> HeroService -> Logger)
|
||||
|
||||
EXCEPTION: No provider for Logger! (HeroListComponent -> HeroService -> Logger)
|
||||
(异常:Logger类没有Provider!(HeroListComponent -> HeroService -> Logger))
|
||||
(异常:Logger类没有供应商!(HeroListComponent -> HeroService -> Logger))
|
||||
|
||||
// #enddocregion logger-service-3
|
||||
// #docregion logger-service-4
|
||||
|
@ -719,13 +719,13 @@ code-example(format, language="html").
|
|||
`HeroService`, which it needed to
|
||||
create and inject into a new `HeroListComponent`.
|
||||
|
||||
Angular这是在告诉我们,依赖注入器找不到日志服务的 *provider* 。
|
||||
而它需要这个provider来创建一个`Logger`实例,以便注入到一个`HeroService`的新实例中,
|
||||
Angular这是在告诉我们,依赖注入器找不到日志服务的*供应商*。
|
||||
而它需要这个供应商来创建一个`Logger`实例,以便注入到一个`HeroService`的新实例中,
|
||||
而`HeroService`会在创建`HeroListComponent`的新实例时被创建和注入进去。
|
||||
|
||||
The chain of creations started with the `Logger` provider. The *provider* is the subject of our next section.
|
||||
|
||||
这个“创建链”始于`Logger`的provider。这个 *provider* 就是我们下一节的主题。
|
||||
这个“创建链”始于`Logger`的供应商。这个*供应商*就是我们下一节的主题。
|
||||
|
||||
But wait! What if the logger is optional?
|
||||
<a id="optional"></a>
|
||||
|
@ -790,7 +790,7 @@ code-example(format, language="html").
|
|||
as we learn in the next section.
|
||||
|
||||
但关于可选日志的讨论就先到此为止。在我们的范例程序中,`Logger`服务是必选的。
|
||||
我们必须通过 *providers* 往应用的注入器中注册一个`Logger`,就像我们接下来将学到的。
|
||||
我们必须通过*供应商*往应用的注入器中注册一个`Logger`,就像我们接下来将学到的。
|
||||
// #enddocregion logger-service-7
|
||||
|
||||
// #docregion providers-1
|
||||
|
@ -799,18 +799,18 @@ code-example(format, language="html").
|
|||
.l-main-section
|
||||
:marked
|
||||
## Injector providers
|
||||
## 注入器的provider们
|
||||
## 注入器的供应商们
|
||||
|
||||
A provider *provides* the concrete, runtime version of a dependency value.
|
||||
The injector relies on **providers** to create instances of the services
|
||||
that the injector injects into components and other services.
|
||||
|
||||
provider *提供* 所依赖值的一个具体的运行期版本。
|
||||
注入器依靠 **providers** 来创建服务的实例,它会被注入器注入到组件或其它服务中。
|
||||
供应商*提供*所依赖值的一个具体的运行期版本。
|
||||
注入器依靠**供应商们**来创建服务的实例,它会被注入器注入到组件或其它服务中。
|
||||
|
||||
We must register a service *provider* with the injector, or it won't know how to create the service.
|
||||
|
||||
我们必须通过注入器注册一个服务的 *provider* ,否则它就不知道该如何创建此服务。
|
||||
我们必须通过注入器注册一个服务的*供应商*,否则它就不知道该如何创建此服务。
|
||||
|
||||
Earlier we registered the `Logger` service in the `providers` array of the metadata for the `AppComponent` like this:
|
||||
|
||||
|
@ -830,14 +830,14 @@ code-example(format, language="html").
|
|||
In reality it holds an instance of the [Provider](../api/core/Provider-class.html) class that can create that service.
|
||||
|
||||
这个`providers`数组看起来好像保存着一个服务类。
|
||||
但事实上,它保存着一个[Provider](../api/core/Provider-class.html)类的实例,这个实例可以用来创建真正的服务。
|
||||
但事实上,它保存着一个[供应商](../api/core/Provider-class.html)类的实例,这个实例可以用来创建真正的服务。
|
||||
|
||||
There are many ways to *provide* something that #{implements} `Logger`.
|
||||
The `Logger` class itself is an obvious and natural provider — it has the right shape and it's designed to be created.
|
||||
But it's not the only way.
|
||||
|
||||
有很多方式可以 *提供* 一些#{implementsCn} `Logger`类的东西。
|
||||
`Logger`类本身是一个显而易见而且自然而然的provider —— 它有正确的形态,并且它设计出来就是等着被创建的。
|
||||
`Logger`类本身是一个显而易见而且自然而然的供应商 —— 它有正确的形态,并且它设计出来就是等着被创建的。
|
||||
但它不是唯一的方式。
|
||||
|
||||
We can configure the injector with alternative providers that can deliver #{objectlike} a `Logger`.
|
||||
|
@ -845,14 +845,14 @@ code-example(format, language="html").
|
|||
We could give it a provider that calls a logger factory function.
|
||||
Any of these approaches might be a good choice under the right circumstances.
|
||||
|
||||
我们可以使用另外的各种provider来配置这个注入器,只要它们能交付#{objectlikeCn}`Logger`。
|
||||
我们可以使用另外的各种供应商来配置这个注入器,只要它们能交付#{objectlikeCn}`Logger`。
|
||||
我们可以提供一个替身类。#{loggerlikeCn}
|
||||
我们可以它他一个provider,让它调用一个用来创建日志服务的工厂函数。
|
||||
我们可以给它一个供应商,让它调用一个可以创建日志服务的工厂函数。
|
||||
所有这些方法,只要在正确的情境下,都可能是一个好的选择。
|
||||
|
||||
What matters is that the injector has a provider to go to when it needs a `Logger`.
|
||||
|
||||
重点是:当注入器需要一个`Logger`时,它得先有一个provider。
|
||||
重点是:当注入器需要一个`Logger`时,它得先有一个供应商。
|
||||
// #enddocregion providers-2
|
||||
// #docregion providers-provide-1
|
||||
:marked
|
||||
|
@ -862,7 +862,7 @@ code-example(format, language="html").
|
|||
// Don't mention provide function in Dart
|
||||
:marked
|
||||
### The *Provider* class and *provide* function
|
||||
### *Provider* 类和 *provide* 函数
|
||||
### *Provider*类和*provide*函数
|
||||
// #docregion providers-provide-1-1
|
||||
:marked
|
||||
We wrote the `providers` array like this:
|
||||
|
@ -875,7 +875,7 @@ code-example(format, language="html").
|
|||
This is actually a short-hand expression for a provider registration that creates a new instance of the
|
||||
[Provider](../api/core/Provider-class.html) class.
|
||||
|
||||
这实际上是provider注册的一个简写形式,它会创建[Provider](../api/core/Provider-class.html)类的一个新实例。
|
||||
这实际上是供应商注册的一个简写形式,它会创建[Provider](../api/core/Provider-class.html)类的一个新实例。
|
||||
// #enddocregion providers-provide-2
|
||||
+makeExample('dependency-injection/ts/app/providers.component.ts','providers-2')
|
||||
// #docregion providers-provide-3
|
||||
|
@ -899,7 +899,7 @@ code-example(format, language="html").
|
|||
The first is the [token](#token) that serves as the key for both locating a dependency value
|
||||
and registering the provider.
|
||||
|
||||
第一个是[token](#token),它作为键值(key)使用,用于定位依赖值,以及注册这个provider。
|
||||
第一个是[token](#token),它作为键值(key)使用,用于定位依赖值,以及注册这个供应商。
|
||||
// #enddocregion providers-provide-4-2
|
||||
|
||||
// Dart is different here (uses an optional parameter)
|
||||
|
@ -908,14 +908,14 @@ code-example(format, language="html").
|
|||
which we can think of as a *recipe* for creating the dependency value.
|
||||
There are many ways to create dependency values... and many ways to write a recipe.
|
||||
|
||||
第二个是一个provider定义对象。
|
||||
我们可以把它看做一个指导如何创建依赖值的 *菜谱* 。
|
||||
第二个是一个供应商定义对象。
|
||||
我们可以把它看做一个指导如何创建依赖值的*配方*。
|
||||
有很多方式创建依赖值…… 也有很多方式可以写菜谱。
|
||||
// #docregion providers-alternative-1
|
||||
:marked
|
||||
<a id="class-provider"></a>
|
||||
### Alternative class providers
|
||||
### 备件类provider
|
||||
### 另外的类供应商
|
||||
|
||||
Occasionally we'll ask a different class to provide the service.
|
||||
The following code tells the injector
|
||||
|
@ -928,7 +928,7 @@ code-example(format, language="html").
|
|||
// #docregion providers-alternative-2
|
||||
:marked
|
||||
### Class provider with dependencies
|
||||
### 带依赖类provider
|
||||
### 带依赖的类供应商
|
||||
Maybe an `EvenBetterLogger` could display the user name in the log message.
|
||||
This logger gets the user from the injected `UserService`,
|
||||
which happens also to be injected at the application level.
|
||||
|
@ -947,7 +947,7 @@ code-example(format, language="html").
|
|||
// #docregion providers-aliased-1
|
||||
:marked
|
||||
### Aliased class providers
|
||||
### 别名类provider
|
||||
### 别名类供应商
|
||||
|
||||
Suppose an old component depends upon an `OldLogger` class.
|
||||
`OldLogger` has the same interface as the `NewLogger`, but for some reason
|
||||
|
@ -986,7 +986,7 @@ code-example(format, language="html").
|
|||
<a id="value-provider"></a>
|
||||
:marked
|
||||
### Value providers
|
||||
### 值provider
|
||||
### 值供应商
|
||||
// #enddocregion providers-value-1
|
||||
|
||||
// Typescript only
|
||||
|
@ -999,14 +999,14 @@ code-example(format, language="html").
|
|||
Then we register a provider with the `useValue` option,
|
||||
which makes this object play the logger role.
|
||||
|
||||
于是我们可以通过`useValue`选项来注册一个provider,它会让这个对象直接扮演logger的角色。
|
||||
于是我们可以通过`useValue`选项来注册一个供应商,它会让这个对象直接扮演logger的角色。
|
||||
+makeExample('dependency-injection/ts/app/providers.component.ts','providers-7')(format=".")
|
||||
|
||||
// #docregion providers-factory-1
|
||||
<a id="factory-provider"></a>
|
||||
:marked
|
||||
### Factory providers
|
||||
### 工厂provider
|
||||
### 工厂供应商
|
||||
|
||||
Sometimes we need to create the dependent value dynamically,
|
||||
based on information we won't have until the last possible moment.
|
||||
|
@ -1021,7 +1021,7 @@ code-example(format, language="html").
|
|||
|
||||
This situation calls for a **factory provider**.
|
||||
|
||||
这种情况下,请呼叫 **工厂provider** 。
|
||||
这种情况下,请呼叫**工厂供应商**。
|
||||
|
||||
Let's illustrate by adding a new business requirement:
|
||||
The HeroService must hide *secret* heroes from normal users.
|
||||
|
@ -1063,11 +1063,11 @@ code-example(format, language="html").
|
|||
We'll have to take over the creation of new instances of this `HeroService` with a factory provider.
|
||||
|
||||
我们可以注入`Logger`,但是我们不能注入逻辑型的`isAuthorized`。
|
||||
我们不得不通过通过一个工厂provider创建这个`HeroService`的新实例。
|
||||
我们不得不通过通过一个工厂供应商创建这个`HeroService`的新实例。
|
||||
|
||||
A factory provider needs a factory function:
|
||||
|
||||
工程provider需要一个工厂方法:
|
||||
工厂供应商需要一个工厂方法:
|
||||
// #enddocregion providers-factory-2
|
||||
+makeExample('dependency-injection/ts/app/heroes/hero.service.provider.ts','factory', 'app/heroes/hero.service.provider.ts (节选)')(format='.')
|
||||
// #docregion providers-factory-3
|
||||
|
@ -1078,7 +1078,7 @@ code-example(format, language="html").
|
|||
|
||||
We inject both the `Logger` and the `UserService` into the factory provider and let the injector pass them along to the factory function:
|
||||
|
||||
我们同时把`Logger`和`UserService`注入到工厂provider中,并且让注入器把它们传给工厂方法:
|
||||
我们同时把`Logger`和`UserService`注入到工厂供应商中,并且让注入器把它们传给工厂方法:
|
||||
// #enddocregion providers-factory-3
|
||||
+makeExample('dependency-injection/ts/app/heroes/hero.service.provider.ts','provider', 'app/heroes/hero.service.provider.ts (节选)')(format='.')
|
||||
// #docregion providers-factory-4
|
||||
|
@ -1087,14 +1087,14 @@ code-example(format, language="html").
|
|||
The `useFactory` field tells Angular that the provider is a factory function
|
||||
whose implementation is the `heroServiceFactory`.
|
||||
|
||||
`useFactory`字段告诉Angular:这个provider是一个工厂方法,它的实现是`heroServiceFactory`。
|
||||
`useFactory`字段告诉Angular:这个供应商是一个工厂方法,它的实现是`heroServiceFactory`。
|
||||
|
||||
The `deps` property is an array of [provider tokens](#token).
|
||||
The `Logger` and `UserService` classes serve as tokens for their own class providers.
|
||||
The injector resolves these tokens and injects the corresponding services into the matching factory function parameters.
|
||||
|
||||
`deps`属性是一个[provider token](#token)的数组。
|
||||
`Logger`和`UserService`类作为它们本身的provider的token。
|
||||
`deps`属性是一个[供应商token](#token)的数组。
|
||||
`Logger`和`UserService`类作为它们自身供应商的token。
|
||||
注入器解析这些token,并且把相应的服务注入到工厂函数参数中所对应的参数中去。
|
||||
// #enddocregion providers-factory-4
|
||||
// #docregion providers-factory-5
|
||||
|
@ -1108,8 +1108,8 @@ code-example(format, language="html").
|
|||
This extra step makes the factory provider reusable.
|
||||
We can register our `HeroService` with this #{variable} wherever we need it.
|
||||
|
||||
注意,我们在#{anexportedvarCn}中捕获了这个工厂provider:`heroServiceProvider`。
|
||||
这个额外的步骤让工程provider可被复用。
|
||||
注意,我们在#{anexportedvarCn}中捕获了这个工厂供应商:`heroServiceProvider`。
|
||||
这个额外的步骤让工厂供应商可被复用。
|
||||
只要需要,我们就可以使用这个#{variableCn}注册`HeroService`,无论在哪儿。
|
||||
|
||||
In our sample, we need it only in the `HeroesComponent`,
|
||||
|
@ -1138,8 +1138,8 @@ code-example(format, language="html").
|
|||
The injector maintains an internal *token-provider* map that it references when
|
||||
asked for a dependency. The token is the key to the map.
|
||||
|
||||
当我们使用注入器注册一个provider时,实际上是把这个provider和一个DI token关联起来了。
|
||||
注入器维护一个内部的 *token-provider* 映射表,这个映射表会在请求一个依赖时被引用到。
|
||||
当我们使用注入器注册一个供应商时,实际上是把这个供应商和一个DI token关联起来了。
|
||||
注入器维护一个内部的*token-供应商*映射表,这个映射表会在请求一个依赖时被引用到。
|
||||
token就是这个映射表中的键值(key)。
|
||||
|
||||
In all previous examples, the dependency value has been a class *instance*, and
|
||||
|
@ -1201,7 +1201,7 @@ code-example(format, language="html").
|
|||
We don't have a class to serve as a token. There is no `Config` class.
|
||||
|
||||
我们想让这个`config`对象在注入时可用。
|
||||
我们已经知道可以使用一个[值provider](#value-provider)来注册一个对象。
|
||||
我们已经知道可以使用一个[值供应商](#value-provider)来注册一个对象。
|
||||
但是这种情况下我们要把什么用作token呢?
|
||||
我们没办法找一个类来当做token,因为没有`Config`类。
|
||||
|
||||
|
@ -1248,7 +1248,7 @@ p.
|
|||
:marked
|
||||
We register the dependency provider using the `OpaqueToken` object:
|
||||
|
||||
我们使用这个`OpaqueToken`对象注册依赖的provider:
|
||||
我们使用这个`OpaqueToken`对象注册依赖的供应商:
|
||||
+makeExample('dependency-injection/ts/app/providers.component.ts','providers-9b')(format=".")
|
||||
// #docregion tokens-opaque-2
|
||||
- var lang = current.path[1]
|
||||
|
@ -1293,7 +1293,7 @@ p.
|
|||
adding a parameter to a constructor.
|
||||
|
||||
在本章中,我们学会了Angular依赖注入的基础。
|
||||
我们可以注册很多种类的provider,而且我们知道了该如何通过添加构造函数的参数来请求一个被注入对象(比如服务)。
|
||||
我们可以注册很多种类的供应商,而且我们知道了该如何通过添加构造函数的参数来请求一个被注入对象(比如服务)。
|
||||
|
||||
Angular dependency injection is more capable than we've described.
|
||||
We can learn more about its advanced features, beginning with its support for
|
||||
|
|
|
@ -322,13 +322,13 @@ code-example(format="." language="bash").
|
|||
code-example(format="." language="html").
|
||||
EXCEPTION: No provider for HeroService! (AppComponent -> HeroService)
|
||||
|
||||
EXCEPTION: No provider for HeroService! (AppComponent -> HeroService) —— 异常:没有HeroService的提供者(provider)!(AppComponent -> HeroService)
|
||||
EXCEPTION: No provider for HeroService! (AppComponent -> HeroService) —— 异常:没有HeroService的供应商!(AppComponent -> HeroService)
|
||||
:marked
|
||||
We have to teach the *injector* how to make a `HeroService` by registering a `HeroService` **provider**.
|
||||
Do that by adding the following `providers` array property to the bottom of the component metadata
|
||||
in the `@Component` call.
|
||||
|
||||
我们还得注册一个`HeroService`**Provider**,来告诉*注入器*如何创建`HeroService`。
|
||||
我们还得注册一个`HeroService`**供应商**,来告诉*注入器*如何创建`HeroService`。
|
||||
要做到这一点,我们应该在`@Component`组件的元数据底部添加`providers`数组属性如下:
|
||||
+makeExample('toh-4/ts/app/app.component.1.ts', 'providers', 'app.component.ts (提供HeroService)')
|
||||
:marked
|
||||
|
@ -588,7 +588,7 @@ code-example(format="." language="html").
|
|||
* We used the `ngOnInit` Lifecycle Hook to get our heroes when our `AppComponent` activates
|
||||
* 我们使用`ngOnInit`生命周期钩子,以便在`AppComponent`激活时获取英雄数据。
|
||||
* We defined our `HeroService` as a provider for our `AppComponent`
|
||||
* 我们把`HeroService`定义为`AppComponent`的一个供应商(provider)
|
||||
* 我们把`HeroService`定义为`AppComponent`的一个供应商
|
||||
* We created mock hero data and imported them into our service
|
||||
* 我们创建了一个模拟的英雄数据,并把它导入我们的服务中
|
||||
* We designed our service to return a promise and our component to get our data from the promise
|
||||
|
@ -648,7 +648,7 @@ code-example(format="." language="html").
|
|||
into the `HeroDetailComponent`, *we must not add a providers array* to the `HeroDetailComponent` metadata.
|
||||
|
||||
我们在[前面](#child-component)说过,如果在父组件`AppComponent`中把`HeroService`服务注入到`HeroDetailComponent`,
|
||||
*我们就不应该在`HeroDetailComponent`的元数据中再添加一个providers数组*。
|
||||
*我们就不应该在`HeroDetailComponent`的元数据中再添加一个`providers`数组*。
|
||||
|
||||
Why? Because that tells Angular to create a new instance of the `HeroService` at the `HeroDetailComponent` level.
|
||||
The `HeroDetailComponent` doesn't want its *own* service instance; it wants its *parent's* service instance.
|
||||
|
@ -656,9 +656,9 @@ code-example(format="." language="html").
|
|||
|
||||
为什么呢?因为那会告诉Angular在`HeroDetailComponent`这一层创建一个新的`HeroService`实例。
|
||||
显然,在这个例子中,`HeroDetailComponent`不会希望创建*自己的*服务实例,它想要的就是来自父组件的服务实例。
|
||||
给组件添加一个`providers`数组(即:注册provider),就会创建一个新的服务实例,而它会遮蔽父组件中的同名实例。
|
||||
给组件添加一个`providers`数组,就会创建一个新的服务实例,而它会遮蔽父组件中的同名实例。
|
||||
|
||||
Think carefully about where and when to register a provider.
|
||||
Understand the scope of that registration. Be careful not to create a new service instance at the wrong level.
|
||||
|
||||
务必想清楚,在哪里、在什么时候注册Provider。要理解注册的有效范围。小心点!不要在错误的级别上创建新的服务实例。
|
||||
务必想清楚,在哪里、在什么时候注册供应商。要理解注册的有效范围。小心点!不要在错误的级别上创建新的服务实例。
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
- “基础知识”和“烹饪书”已经完成了初译。
|
||||
- “开发人员指南”正在翻译中。
|
||||
- “API参考”尚未开始翻译。
|
||||
- 由于技术限制,“API小抄”尚无法进行同步翻译,目前取的是rc.0版
|
||||
|
||||
## 支持我们
|
||||
由于我们对翻译质量的极端要求,所以很抱歉,我们暂时无法接受新人加入翻译,否则我们需要花费大量精力进行review。
|
||||
|
|
Loading…
Reference in New Issue