feat: 自动在中英文之间添加空格,以改善排版
This commit is contained in:
parent
df15324377
commit
545d4b6c69
|
@ -7,12 +7,12 @@
|
|||
_Angular_ is the name for the Angular of today and tomorrow.
|
||||
_AngularJS_ is the name for all v1.x versions of Angular.
|
||||
|
||||
*Angular*这个名字专指现在和未来的Angular版本,而*AngularJS*专指Angular的所有v1.x版本。
|
||||
*Angular*这个名字专指现在和未来的 Angular 版本,而*AngularJS*专指 Angular 的所有 v1.x 版本。
|
||||
|
||||
This guide helps you transition from AngularJS to Angular
|
||||
by mapping AngularJS syntax to the equivalent Angular syntax.
|
||||
|
||||
本章提供了一个快速的参考指南,指出一些常用的AngularJS语法及其在Angular中的等价物。
|
||||
本章提供了一个快速的参考指南,指出一些常用的 AngularJS 语法及其在 Angular 中的等价物。
|
||||
|
||||
**See the Angular syntax in this <live-example name="ajs-quick-reference"></live-example>**.
|
||||
|
||||
|
@ -25,7 +25,7 @@ by mapping AngularJS syntax to the equivalent Angular syntax.
|
|||
Templates are the user-facing part of an Angular application and are written in HTML.
|
||||
The following table lists some of the key AngularJS template features with their equivalent Angular template syntax.
|
||||
|
||||
模板是Angular应用中的门面部分,它是用HTML写的。下表中是一些AngularJS中的关键模板特性及其在Angular中的等价语法。
|
||||
模板是 Angular 应用中的门面部分,它是用 HTML 写的。下表中是一些 AngularJS 中的关键模板特性及其在 Angular 中的等价语法。
|
||||
|
||||
<table width="100%">
|
||||
|
||||
|
@ -71,14 +71,14 @@ The following table lists some of the key AngularJS template features with their
|
|||
This binds the value of the element to a property in the controller
|
||||
associated with this template.
|
||||
|
||||
在AngularJS中,花括号中的表达式代表单向绑定。
|
||||
在 AngularJS 中,花括号中的表达式代表单向绑定。
|
||||
它把元素的值绑定到了与模板相关控制器的属性上。
|
||||
|
||||
When using the `controller as` syntax,
|
||||
the binding is prefixed with the controller alias (`vm` or `$ctrl`) because you
|
||||
have to be specific about the source of the binding.
|
||||
|
||||
当使用`controller as`语法时,该绑定需要用控制器的别名(`vm`)为前缀,这是因为我们不得不通过它来指定绑定源。
|
||||
当使用 `controller as` 语法时,该绑定需要用控制器的别名(`vm`)为前缀,这是因为我们不得不通过它来指定绑定源。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -95,7 +95,7 @@ The following table lists some of the key AngularJS template features with their
|
|||
The context of the binding is implied and is always the
|
||||
associated component, so it needs no reference variable.
|
||||
|
||||
在Angular中,花括号中的模板表达式同样代表单向绑定。
|
||||
在 Angular 中,花括号中的模板表达式同样代表单向绑定。
|
||||
它把元素的值绑定到了组件的属性上。
|
||||
它绑定的上下文变量是隐式的,并且总是关联到组件。
|
||||
所以,它不需要一个引用变量。
|
||||
|
@ -125,11 +125,11 @@ The following table lists some of the key AngularJS template features with their
|
|||
|
||||
To filter output in AngularJS templates, use the pipe character (|) and one or more filters.
|
||||
|
||||
要在AngularJS中过滤输出,使用管道字符(|)以及一个或多个过滤器。
|
||||
要在 AngularJS 中过滤输出,使用管道字符(|)以及一个或多个过滤器。
|
||||
|
||||
This example filters the `title` property to uppercase.
|
||||
|
||||
这个例子中把`title`属性过滤成了大写形式。
|
||||
这个例子中把 `title` 属性过滤成了大写形式。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -145,8 +145,8 @@ The following table lists some of the key AngularJS template features with their
|
|||
Many (but not all) of the built-in filters from AngularJS are
|
||||
built-in pipes in Angular.
|
||||
|
||||
在Angular中,我们使用相似的语法 —— 用管道字符(|)来过滤输出,但是现在直接把它叫做**管道**了。
|
||||
很多(但不是所有)AngularJS中的内置过滤器也成了Angular中的内置管道。
|
||||
在 Angular 中,我们使用相似的语法 —— 用管道字符(|)来过滤输出,但是现在直接把它叫做**管道**了。
|
||||
很多(但不是所有)AngularJS 中的内置过滤器也成了 Angular 中的内置管道。
|
||||
|
||||
For more information, see [Filters/pipes](guide/ajs-quick-reference#filters-pipes) below.
|
||||
|
||||
|
@ -174,7 +174,7 @@ The following table lists some of the key AngularJS template features with their
|
|||
|
||||
Here, `movie` is a user-defined local variable.
|
||||
|
||||
这里的`movie`是一个用户定义的局部变量
|
||||
这里的 `movie` 是一个用户定义的局部变量
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -188,12 +188,12 @@ The following table lists some of the key AngularJS template features with their
|
|||
|
||||
Angular has true template input variables that are explicitly defined using the `let` keyword.
|
||||
|
||||
Angular 有了真正的模板输入变量,它需要使用`let`关键字进行明确定义。
|
||||
Angular 有了真正的模板输入变量,它需要使用 `let` 关键字进行明确定义。
|
||||
|
||||
For more information, see the [ngFor micro-syntax](guide/template-syntax#microsyntax)
|
||||
section of the [Template Syntax](guide/template-syntax) page.
|
||||
|
||||
要了解更多信息,请参见[模板语法](guide/template-syntax)中的[ngFor微语法](guide/template-syntax#microsyntax)部分。
|
||||
要了解更多信息,请参见[模板语法](guide/template-syntax)中的[ngFor 微语法](guide/template-syntax#microsyntax)部分。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -211,7 +211,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
|||
|
||||
AngularJS 为模板提供了七十多个内置指令。
|
||||
在 Angular 中,它们很多都已经不需要了,因为 Angular 有了一个更加强大、快捷的绑定系统。
|
||||
下面是一些AngularJS 中的关键指令及其在 Angular 中的等价物。
|
||||
下面是一些 AngularJS 中的关键指令及其在 Angular 中的等价物。
|
||||
|
||||
<table width="100%">
|
||||
|
||||
|
@ -259,8 +259,8 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
many applications bootstrap declaratively with the `ng-app` directive,
|
||||
giving it the name of the application's module (`movieHunter`).
|
||||
|
||||
虽然可以从代码中引导Angular应用,
|
||||
但很多应用都是通过`ng-app`指令进行声明式引导的,只要给它一个应用模块的名字(`movieHunter`)就可以了。
|
||||
虽然可以从代码中引导 Angular 应用,
|
||||
但很多应用都是通过 `ng-app` 指令进行声明式引导的,只要给它一个应用模块的名字(`movieHunter`)就可以了。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -282,7 +282,7 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
and the application's root component (`AppComponent`) in `app.module.ts`.
|
||||
|
||||
Angular 没有引导指令。
|
||||
总是要通过显式调用一个`bootstrap`函数,并传入应用模块的名字(`AppComponent`)来启动应用。
|
||||
总是要通过显式调用一个 `bootstrap` 函数,并传入应用模块的名字(`AppComponent`)来启动应用。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -307,12 +307,12 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
key of the object defined as a CSS class name, and each value defined as a template expression
|
||||
that evaluates to a Boolean value.
|
||||
|
||||
在AngularJS中,`ng-class`指令会基于一个表达式来包含/排除某些CSS类。该表达式通常是一个“键-值”型的控制对象,
|
||||
对象中的每一个键代表一个CSS类名,每一个值定义为一个返回布尔值的模板表达式。
|
||||
在 AngularJS 中,`ng-class` 指令会基于一个表达式来包含/排除某些 CSS 类。该表达式通常是一个“键-值”型的控制对象,
|
||||
对象中的每一个键代表一个 CSS 类名,每一个值定义为一个返回布尔值的模板表达式。
|
||||
|
||||
In the first example, the `active` class is applied to the element if `isActive` is true.
|
||||
|
||||
在第一个例子中,如果`isActive`为真,则`active`类被应用到那个元素上。
|
||||
在第一个例子中,如果 `isActive` 为真,则 `active` 类被应用到那个元素上。
|
||||
|
||||
You can specify multiple classes, as shown in the second example.
|
||||
|
||||
|
@ -329,12 +329,12 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
In Angular, the `ngClass` directive works similarly.
|
||||
It includes/excludes CSS classes based on an expression.
|
||||
|
||||
在Angular中,`ngClass`指令用类似的方式工作。
|
||||
它根据一个表达式包含/排除某些CSS类。
|
||||
在 Angular 中,`ngClass` 指令用类似的方式工作。
|
||||
它根据一个表达式包含/排除某些 CSS 类。
|
||||
|
||||
In the first example, the `active` class is applied to the element if `isActive` is true.
|
||||
|
||||
在第一个例子中,如果`isActive`为真,则`active`类被应用到那个元素上。
|
||||
在第一个例子中,如果 `isActive` 为真,则 `active` 类被应用到那个元素上。
|
||||
|
||||
You can specify multiple classes, as shown in the second example.
|
||||
|
||||
|
@ -343,12 +343,12 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
Angular also has **class binding**, which is a good way to add or remove a single class,
|
||||
as shown in the third example.
|
||||
|
||||
Angular还有**类绑定**,它是单独添加或移除一个类的好办法 —— 就像第三个例子中展示的。
|
||||
Angular 还有**类绑定**,它是单独添加或移除一个类的好办法 —— 就像第三个例子中展示的。
|
||||
|
||||
For more information see the [Attribute, class, and style bindings](guide/template-syntax#other-bindings)
|
||||
section of the [Template Syntax](guide/template-syntax) page.
|
||||
|
||||
要了解更多信息,参见[模板语法](guide/template-syntax)中的[属性、CSS类和样式绑定](guide/template-syntax#other-bindings)部分。
|
||||
要了解更多信息,参见[模板语法](guide/template-syntax)中的[属性、CSS 类和样式绑定](guide/template-syntax#other-bindings)部分。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -369,16 +369,16 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
|
||||
In AngularJS, the `ng-click` directive allows you to specify custom behavior when an element is clicked.
|
||||
|
||||
在AngularJS中,`ng-click`指令指定当元素被点击时的自定义行为。
|
||||
在 AngularJS 中,`ng-click` 指令指定当元素被点击时的自定义行为。
|
||||
|
||||
In the first example, when the user clicks the button, the `toggleImage()` method in the controller referenced by the `vm` `controller as` alias is executed.
|
||||
|
||||
在第一个例子中,如果用户点击了这个按钮,那么控制器的`toggleImage()`方法就会被执行,这个控制器是被`controller as`中指定的`vm`别名所引用的。
|
||||
在第一个例子中,如果用户点击了这个按钮,那么控制器的 `toggleImage()` 方法就会被执行,这个控制器是被 `controller as` 中指定的 `vm` 别名所引用的。
|
||||
|
||||
The second example demonstrates passing in the `$event` object, which provides details about the event
|
||||
to the controller.
|
||||
|
||||
第二个例子演示了传入`$event`对象,它提供了事件的详情,并被传到控制器。
|
||||
第二个例子演示了传入 `$event` 对象,它提供了事件的详情,并被传到控制器。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -386,14 +386,14 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
|
||||
### Bind to the `click` event
|
||||
|
||||
### 绑定到`click`事件
|
||||
### 绑定到 `click` 事件
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="event-binding" linenums="false"></code-example>
|
||||
|
||||
AngularJS event-based directives do not exist in Angular.
|
||||
Rather, define one-way binding from the template view to the component using **event binding**.
|
||||
|
||||
AngularJS基于事件的指令在Angular中已经不存在了。
|
||||
AngularJS 基于事件的指令在 Angular 中已经不存在了。
|
||||
不过,可以使用**事件绑定**来定义从模板视图到组件的单向数据绑定。
|
||||
|
||||
For event binding, define the name of the target event within parenthesis and
|
||||
|
@ -402,20 +402,20 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
executes the template statement.
|
||||
|
||||
要使用事件绑定,把目标事件的名字放在圆括号中,并且使用等号右侧引号中的模板语句对它赋值。
|
||||
然后Angular为这个目标时间设置事件处理器。当事件被触发时,这个处理器就会执行模板语句。
|
||||
然后 Angular 为这个目标时间设置事件处理器。当事件被触发时,这个处理器就会执行模板语句。
|
||||
|
||||
In the first example, when a user clicks the button, the `toggleImage()` method in the associated component is executed.
|
||||
|
||||
在第一个例子中,当用户点击此按钮时,相关组件中的`toggleImage()`方法就被执行了。
|
||||
在第一个例子中,当用户点击此按钮时,相关组件中的 `toggleImage()` 方法就被执行了。
|
||||
|
||||
The second example demonstrates passing in the `$event` object, which provides details about the event
|
||||
to the component.
|
||||
|
||||
第二个例子演示了如何传入`$event`对象,它为组件提供了此事件的详情。
|
||||
第二个例子演示了如何传入 `$event` 对象,它为组件提供了此事件的详情。
|
||||
|
||||
For a list of DOM events, see: https://developer.mozilla.org/en-US/docs/Web/Events.
|
||||
|
||||
要查看DOM事件的列表,请参见[网络事件](https://developer.mozilla.org/en-US/docs/Web/Events)。
|
||||
要查看 DOM 事件的列表,请参见[网络事件](https://developer.mozilla.org/en-US/docs/Web/Events)。
|
||||
|
||||
For more information, see the [Event binding](guide/template-syntax#event-binding)
|
||||
section of the [Template Syntax](guide/template-syntax) page.
|
||||
|
@ -442,8 +442,8 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
Using the `ng-controller` (or defining the controller as part of the routing) ties the
|
||||
view to the controller code associated with that view.
|
||||
|
||||
在AngularJS中,`ng-controller`指令把控制器附加到视图上。
|
||||
使用`ng-controller`(或把控制器定义为路由的一部分)把视图及其控制器的代码联系在一起。
|
||||
在 AngularJS 中,`ng-controller` 指令把控制器附加到视图上。
|
||||
使用 `ng-controller`(或把控制器定义为路由的一部分)把视图及其控制器的代码联系在一起。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -458,7 +458,7 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
In Angular, the template no longer specifies its associated controller.
|
||||
Rather, the component specifies its associated template as part of the component class decorator.
|
||||
|
||||
在Angular中,模板不用再指定它相关的控制器。
|
||||
在 Angular 中,模板不用再指定它相关的控制器。
|
||||
反过来,组件会在组件类的装饰器中指定与它相关的模板。
|
||||
|
||||
For more information, see [Architecture Overview](guide/architecture#components).
|
||||
|
@ -478,7 +478,7 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
In AngularJS, the `ng-hide` directive shows or hides the associated HTML element based on
|
||||
an expression. For more information, see [ng-show](guide/ajs-quick-reference#ng-show).
|
||||
|
||||
在AngularJS中,`ng-hide`指令会基于一个表达式显示或隐藏相关的HTML元素。
|
||||
在 AngularJS 中,`ng-hide` 指令会基于一个表达式显示或隐藏相关的 HTML 元素。
|
||||
参见[ng-show](guide/ajs-quick-reference#ng-show)了解更多。
|
||||
|
||||
</td>
|
||||
|
@ -487,12 +487,12 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
|
||||
### Bind to the `hidden` property
|
||||
|
||||
### 绑定到`hidden`属性
|
||||
### 绑定到 `hidden` 属性
|
||||
|
||||
In Angular, you use property binding; there is no built-in *hide* directive.
|
||||
For more information, see [ng-show](guide/ajs-quick-reference#ng-show).
|
||||
|
||||
在Angular中,并没有一个内置的*hide*指令,可以改用属性绑定。
|
||||
在 Angular 中,并没有一个内置的*hide*指令,可以改用属性绑定。
|
||||
参见[ng-show](guide/ajs-quick-reference#ng-show)了解更多。
|
||||
|
||||
</td>
|
||||
|
@ -515,11 +515,11 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
can replace the binding expression with the appropriate URL before the browser
|
||||
fetches from that URL.
|
||||
|
||||
`ng-href`指令允许AngularJS对`href`属性进行预处理,以便它能在浏览器获取那个URL之前,使用一个返回适当URL的绑定表达式替换它。
|
||||
`ng-href` 指令允许 AngularJS 对 `href` 属性进行预处理,以便它能在浏览器获取那个 URL 之前,使用一个返回适当 URL 的绑定表达式替换它。
|
||||
|
||||
In AngularJS, the `ng-href` is often used to activate a route as part of navigation.
|
||||
|
||||
在AngularJS 中,`ng-href`通常用来作为导航的一部分,激活一个路由。
|
||||
在 AngularJS 中,`ng-href` 通常用来作为导航的一部分,激活一个路由。
|
||||
|
||||
<code-example hideCopy format="">
|
||||
|
||||
|
@ -529,7 +529,7 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
|
||||
Routing is handled differently in Angular.
|
||||
|
||||
路由在Angular中的处理方式不同。
|
||||
路由在 Angular 中的处理方式不同。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -537,15 +537,15 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
|
||||
### Bind to the `href` property
|
||||
|
||||
### 绑定到`href`属性
|
||||
### 绑定到 `href` 属性
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="href" linenums="false"></code-example>
|
||||
|
||||
Angular uses property binding; there is no built-in *href* directive.
|
||||
Place the element's `href` property in square brackets and set it to a quoted template expression.
|
||||
|
||||
在Angular中,并没有内置的*href*指令,改用属性绑定。
|
||||
我们把元素的`href`属性放在方括号中,并把它设成一个引号中的模板表达式。
|
||||
在 Angular 中,并没有内置的*href*指令,改用属性绑定。
|
||||
我们把元素的 `href` 属性放在方括号中,并把它设成一个引号中的模板表达式。
|
||||
|
||||
For more information see the [Property binding](guide/template-syntax#property-binding)
|
||||
section of the [Template Syntax](guide/template-syntax) page.
|
||||
|
@ -554,14 +554,14 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
|
||||
In Angular, `href` is no longer used for routing. Routing uses `routerLink`, as shown in the following example.
|
||||
|
||||
在Angular中,`href`不再用作路由,而是改用第三个例子中所展示的`routerLink`指令。
|
||||
在 Angular 中,`href` 不再用作路由,而是改用第三个例子中所展示的 `routerLink` 指令。
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="router-link" linenums="false"></code-example>
|
||||
|
||||
For more information on routing, see the [RouterLink binding](guide/router#router-link)
|
||||
section of the [Routing & Navigation](guide/router) page.
|
||||
|
||||
要了解关于路由的更多信息,请参见[路由与导航](guide/router)的[RouterLink绑定](guide/router#router-link)部分。
|
||||
要了解关于路由的更多信息,请参见[路由与导航](guide/router)的[RouterLink 绑定](guide/router#router-link)部分。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -582,11 +582,11 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
In AngularJS, the `ng-if` directive removes or recreates a portion of the DOM,
|
||||
based on an expression. If the expression is false, the element is removed from the DOM.
|
||||
|
||||
在AngularJS中,`ng-if`指令会根据一个表达式来移除或重建DOM中的一部分。如果表达式为假,元素就会被从DOM中移除。
|
||||
在 AngularJS 中,`ng-if` 指令会根据一个表达式来移除或重建 DOM 中的一部分。如果表达式为假,元素就会被从 DOM 中移除。
|
||||
|
||||
In this example, the `<table>` element is removed from the DOM unless the `movies` array has a length greater than zero.
|
||||
|
||||
在这个例子中,除非`movies`数组的长度大于0,否则`<table>`元素就会被从DOM中移除。
|
||||
在这个例子中,除非 `movies` 数组的长度大于 0,否则 `<table>` 元素就会被从 DOM 中移除。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -599,17 +599,17 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
The `*ngIf` directive in Angular works the same as the `ng-if` directive in AngularJS. It removes
|
||||
or recreates a portion of the DOM based on an expression.
|
||||
|
||||
Angular中的`*ngIf`指令与AngularJS中的`ng-if`指令一样,
|
||||
它根据表达式的值移除或重建DOM中的一部分。
|
||||
Angular 中的 `*ngIf` 指令与 AngularJS 中的 `ng-if` 指令一样,
|
||||
它根据表达式的值移除或重建 DOM 中的一部分。
|
||||
|
||||
In this example, the `<table>` element is removed from the DOM unless the `movies` array has a length.
|
||||
|
||||
在这个例子中,除非`movies`数组的长度大于0,否则`<table>`元素就会被从DOM中移除。
|
||||
在这个例子中,除非 `movies` 数组的长度大于 0,否则 `<table>` 元素就会被从 DOM 中移除。
|
||||
|
||||
The (*) before `ngIf` is required in this example.
|
||||
For more information, see [Structural Directives](guide/structural-directives).
|
||||
|
||||
在这个例子中`ngIf`前的星号(*)是必须的。
|
||||
在这个例子中 `ngIf` 前的星号(*)是必须的。
|
||||
要了解更多信息,参见[结构型指令](guide/structural-directives)。
|
||||
|
||||
</td>
|
||||
|
@ -631,7 +631,7 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
In AngularJS, the `ng-model` directive binds a form control to a property in the controller associated with the template.
|
||||
This provides **two-way binding**, whereby any change made to the value in the view is synchronized with the model, and any change to the model is synchronized with the value in the view.
|
||||
|
||||
在Angular1中,`ng-model`指令把一个表单控件绑定到了模板相关控制器的一个属性上。
|
||||
在 Angular1 中,`ng-model` 指令把一个表单控件绑定到了模板相关控制器的一个属性上。
|
||||
这提供了**双向绑定**功能,因此,任何对视图中值的改动,都会同步到模型中,对模型的改动,也会同步到视图中。
|
||||
|
||||
</td>
|
||||
|
@ -645,14 +645,14 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
In Angular, **two-way binding** is denoted by `[()]`, descriptively referred to as a "banana in a box". This syntax is a shortcut for defining both property binding (from the component to the view)
|
||||
and event binding (from the view to the component), thereby providing two-way binding.
|
||||
|
||||
在Angular中,**双向绑定**使用[()]标记出来,它被形象的比作“盒子中的香蕉”。
|
||||
在 Angular 中,**双向绑定**使用[()]标记出来,它被形象的比作“盒子中的香蕉”。
|
||||
这种语法是一个简写形式,用来同时定义一个属性绑定(从组件到视图)和一个事件绑定(从视图到组件),因此,我们得到了双向绑定。
|
||||
|
||||
For more information on two-way binding with `ngModel`, see the [NgModel—Two-way binding to
|
||||
form elements with `[(ngModel)]`](../guide/template-syntax.html#ngModel)
|
||||
section of the [Template Syntax](guide/template-syntax) page.
|
||||
|
||||
要了解使用ngModel进行双向绑定的更多知识,参见[模板语法](guide/template-syntax)中的[NgModel—使用`[(ngModel)]`进行双向绑定](../guide/template-syntax.html#ngModel)部分。
|
||||
要了解使用 ngModel 进行双向绑定的更多知识,参见[模板语法](guide/template-syntax)中的[NgModel—使用 `[(ngModel)]` 进行双向绑定](../guide/template-syntax.html#ngModel)部分。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -673,11 +673,11 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
In AngularJS, the `ng-repeat` directive repeats the associated DOM element
|
||||
for each item in the specified collection.
|
||||
|
||||
在Angular1中,`ng-repeat`指令会为指定集合中的每一个条目重复渲染相关的DOM元素。
|
||||
在 Angular1 中,`ng-repeat` 指令会为指定集合中的每一个条目重复渲染相关的 DOM 元素。
|
||||
|
||||
In this example, the table row (`<tr>`) element repeats for each movie object in the collection of movies.
|
||||
|
||||
在这个例子中,对`movies`集合中的每一个`movie`对象重复渲染了这个表格行元素(`<tr>`)。
|
||||
在这个例子中,对 `movies` 集合中的每一个 `movie` 对象重复渲染了这个表格行元素(`<tr>`)。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -692,9 +692,9 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
More accurately, it turns the defined element (`<tr>` in this example) and its contents into a template and
|
||||
uses that template to instantiate a view for each item in the list.
|
||||
|
||||
Angular中的`*ngFor`指令类似于AngularJS中的`ng-repeat`指令。
|
||||
它为指定集合中的每一个条目重复渲染了相关的DOM元素。
|
||||
更准确的说,它把被界定出来的元素(这个例子中是`<tr>`)及其内容转成了一个模板,并使用那个模板来为列表中的每一个条目实例化一个视图。
|
||||
Angular 中的 `*ngFor` 指令类似于 AngularJS 中的 `ng-repeat` 指令。
|
||||
它为指定集合中的每一个条目重复渲染了相关的 DOM 元素。
|
||||
更准确的说,它把被界定出来的元素(这个例子中是 `<tr>`)及其内容转成了一个模板,并使用那个模板来为列表中的每一个条目实例化一个视图。
|
||||
|
||||
Notice the other syntax differences:
|
||||
The (*) before `ngFor` is required;
|
||||
|
@ -702,7 +702,7 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
the list preposition is `of`, not `in`.
|
||||
|
||||
请注意其它语法上的差异:
|
||||
在`ngFor`前面的星号(*)是必须的;`let`关键字把`movie`标记成一个输入变量;列表中使用的介词是`of`,而不再是`in`。
|
||||
在 `ngFor` 前面的星号(*)是必须的;`let` 关键字把 `movie` 标记成一个输入变量;列表中使用的介词是 `of`,而不再是 `in`。
|
||||
|
||||
For more information, see [Structural Directives](guide/structural-directives).
|
||||
|
||||
|
@ -729,11 +729,11 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
In AngularJS, the `ng-show` directive shows or hides the associated DOM element, based on
|
||||
an expression.
|
||||
|
||||
在AngularJS中,`ng-show`指令根据一个表达式来显示或隐藏相关的DOM元素。
|
||||
在 AngularJS 中,`ng-show` 指令根据一个表达式来显示或隐藏相关的 DOM 元素。
|
||||
|
||||
In this example, the `<div>` element is shown if the `favoriteHero` variable is truthy.
|
||||
|
||||
在这个例子中,如果`favoriteHero`变量为真,`<div>`元素就会显示出来。
|
||||
在这个例子中,如果 `favoriteHero` 变量为真,`<div>` 元素就会显示出来。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -741,24 +741,24 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
|
||||
### Bind to the `hidden` property
|
||||
|
||||
### 绑定到`hidden`属性
|
||||
### 绑定到 `hidden` 属性
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="hidden" linenums="false"></code-example>
|
||||
|
||||
Angular uses property binding; there is no built-in *show* directive.
|
||||
For hiding and showing elements, bind to the HTML `hidden` property.
|
||||
|
||||
在Angular中,并没有内置的*show*指令,可以改用属性绑定。
|
||||
要隐藏或显示一个元素,绑定到它的`hidden`属性就可以了。
|
||||
在 Angular 中,并没有内置的*show*指令,可以改用属性绑定。
|
||||
要隐藏或显示一个元素,绑定到它的 `hidden` 属性就可以了。
|
||||
|
||||
To conditionally display an element, place the element's `hidden` property in square brackets and
|
||||
set it to a quoted template expression that evaluates to the *opposite* of *show*.
|
||||
|
||||
要想有条件的显示一个元素,就把该元素的`hidden`属性放到一个方括号里,并且把它设置为引号中的模板表达式,它的结果应该是与*显示*时*相反*的值。
|
||||
要想有条件的显示一个元素,就把该元素的 `hidden` 属性放到一个方括号里,并且把它设置为引号中的模板表达式,它的结果应该是与*显示*时*相反*的值。
|
||||
|
||||
In this example, the `<div>` element is hidden if the `favoriteHero` variable is not truthy.
|
||||
|
||||
在这个例子中,如果`favoriteHero`变量不是真值,`<div>`元素就会被隐藏。
|
||||
在这个例子中,如果 `favoriteHero` 变量不是真值,`<div>` 元素就会被隐藏。
|
||||
|
||||
For more information on property binding, see the [Property binding](guide/template-syntax#property-binding)
|
||||
section of the [Template Syntax](guide/template-syntax) page.
|
||||
|
@ -785,7 +785,7 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
can replace the binding expression with the appropriate URL before the browser
|
||||
fetches from that URL.
|
||||
|
||||
`ng-src`指令允许AngularJS对`src`属性进行预处理,以便它能够在浏览器获取此URL之前,用一个返回适当URL的绑定表达式替换它。
|
||||
`ng-src` 指令允许 AngularJS 对 `src` 属性进行预处理,以便它能够在浏览器获取此 URL 之前,用一个返回适当 URL 的绑定表达式替换它。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -793,15 +793,15 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
|
||||
### Bind to the `src` property
|
||||
|
||||
### 绑定到`src`属性
|
||||
### 绑定到 `src` 属性
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="src" linenums="false"></code-example>
|
||||
|
||||
Angular uses property binding; there is no built-in *src* directive.
|
||||
Place the `src` property in square brackets and set it to a quoted template expression.
|
||||
|
||||
在Angular中,并没有一个内置的*src*指令,可以使用属性绑定。
|
||||
把`src`属性放到方括号中,并且把它设为一个引号中的绑定表达式。
|
||||
在 Angular 中,并没有一个内置的*src*指令,可以使用属性绑定。
|
||||
把 `src` 属性放到方括号中,并且把它设为一个引号中的绑定表达式。
|
||||
|
||||
For more information on property binding, see the [Property binding](guide/template-syntax#property-binding)
|
||||
section of the [Template Syntax](guide/template-syntax) page.
|
||||
|
@ -829,12 +829,12 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
key of the object defined as a CSS property, and each value defined as an expression
|
||||
that evaluates to a value appropriate for the style.
|
||||
|
||||
在AngularJS中,`ng-style`指令根据一个绑定表达式设置一个HTML元素的CSS样式。
|
||||
该表达式通常是一个“键-值”形式的控制对象,对象的每个键都是一个CSS属性,每个值都是一个能计算为此样式的合适值的表达式。
|
||||
在 AngularJS 中,`ng-style` 指令根据一个绑定表达式设置一个 HTML 元素的 CSS 样式。
|
||||
该表达式通常是一个“键-值”形式的控制对象,对象的每个键都是一个 CSS 属性,每个值都是一个能计算为此样式的合适值的表达式。
|
||||
|
||||
In the example, the `color` style is set to the current value of the `colorPreference` variable.
|
||||
|
||||
在这个例子中,`color`样式被设置为`colorPreference`变量的当前值。
|
||||
在这个例子中,`color` 样式被设置为 `colorPreference` 变量的当前值。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -846,15 +846,15 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
|
||||
In Angular, the `ngStyle` directive works similarly. It sets a CSS style on an HTML element based on an expression.
|
||||
|
||||
在Angular中,`ngStyle`指令的工作方式与此类似。它根据一个表达式设置HTML元素上的CSS样式。
|
||||
在 Angular 中,`ngStyle` 指令的工作方式与此类似。它根据一个表达式设置 HTML 元素上的 CSS 样式。
|
||||
|
||||
In the first example, the `color` style is set to the current value of the `colorPreference` variable.
|
||||
|
||||
在第一个例子中,`color`样式被设置成了`colorPreference`变量的当前值。
|
||||
在第一个例子中,`color` 样式被设置成了 `colorPreference` 变量的当前值。
|
||||
|
||||
Angular also has **style binding**, which is good way to set a single style. This is shown in the second example.
|
||||
|
||||
Angular还有**样式绑定**语法,它是单独设置一个样式的好方法。它展示在第二个例子中。
|
||||
Angular 还有**样式绑定**语法,它是单独设置一个样式的好方法。它展示在第二个例子中。
|
||||
|
||||
For more information on style binding, see the [Style binding](guide/template-syntax#style-binding) section of the
|
||||
[Template Syntax](guide/template-syntax) page.
|
||||
|
@ -864,7 +864,7 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
For more information on the `ngStyle` directive, see [NgStyle](guide/template-syntax#ngStyle)
|
||||
section of the [Template Syntax](guide/template-syntax) page.
|
||||
|
||||
要了解关于`ngStyle`指令的更多知识,参见[模板语法](guide/template-syntax)中的[NgStyle](guide/template-syntax#ngStyle)部分。
|
||||
要了解关于 `ngStyle` 指令的更多知识,参见[模板语法](guide/template-syntax)中的[NgStyle](guide/template-syntax#ngStyle)部分。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -896,17 +896,17 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
In AngularJS, the `ng-switch` directive swaps the contents of
|
||||
an element by selecting one of the templates based on the current value of an expression.
|
||||
|
||||
在Angular1中,`ng-switch`指令根据一个表达式的当前值把元素的内容替换成几个模板之一。
|
||||
在 Angular1 中,`ng-switch` 指令根据一个表达式的当前值把元素的内容替换成几个模板之一。
|
||||
|
||||
In this example, if `favoriteHero` is not set, the template displays "Please enter ...".
|
||||
If `favoriteHero` is set, it checks the movie hero by calling a controller method.
|
||||
If that method returns `true`, the template displays "Excellent choice!".
|
||||
If that methods returns `false`, the template displays "No movie, sorry!".
|
||||
|
||||
在这个例子中,如果`favoriteHero`没有设置,则模板显示“Please enter ...”。
|
||||
如果`favoriteHero`设置过,它就会通过调用一个控制其方法来检查它是否电影里的英雄。
|
||||
如果该方法返回`true`,模板就会显示“Excellent choice!”。
|
||||
如果该方法返回`false`,该模板就会显示“No movie, sorry!”。
|
||||
在这个例子中,如果 `favoriteHero` 没有设置,则模板显示“Please enter ...”。
|
||||
如果 `favoriteHero` 设置过,它就会通过调用一个控制其方法来检查它是否电影里的英雄。
|
||||
如果该方法返回 `true`,模板就会显示“Excellent choice!”。
|
||||
如果该方法返回 `false`,该模板就会显示“No movie, sorry!”。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -919,8 +919,8 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
In Angular, the `ngSwitch` directive works similarly.
|
||||
It displays an element whose `*ngSwitchCase` matches the current `ngSwitch` expression value.
|
||||
|
||||
在Angular中,`ngSwitch`指令的工作方式与此类似。
|
||||
它会显示那个与`ngSwitch`表达式的当前值匹配的那个`*ngSwitchCase`所在的元素。
|
||||
在 Angular 中,`ngSwitch` 指令的工作方式与此类似。
|
||||
它会显示那个与 `ngSwitch` 表达式的当前值匹配的那个 `*ngSwitchCase` 所在的元素。
|
||||
|
||||
In this example, if `favoriteHero` is not set, the `ngSwitch` value is `null`
|
||||
and `*ngSwitchDefault` displays, "Please enter ...".
|
||||
|
@ -928,20 +928,20 @@ AngularJS 为模板提供了七十多个内置指令。
|
|||
If that method returns `true`, the app selects `*ngSwitchCase="true"` and displays: "Excellent choice!"
|
||||
If that methods returns `false`, the app selects `*ngSwitchCase="false"` and displays: "No movie, sorry!"
|
||||
|
||||
在这个例子中,如果`favoriteHero`没有设置,则`ngSwitch`的值是`null`,我们会看到
|
||||
`*ngSwitchDefault`中的段落“Please enter ...”。
|
||||
如果`favoriteHero`被设置了,它就会通过调用一个组件方法来检查电影英雄。
|
||||
如果该方法返回`true`,我们就会看到“Excellent choice!”。
|
||||
如果该方法返回`false`,我们就会看到“No movie, sorry!”。
|
||||
在这个例子中,如果 `favoriteHero` 没有设置,则 `ngSwitch` 的值是 `null`,我们会看到
|
||||
`*ngSwitchDefault` 中的段落“Please enter ...”。
|
||||
如果 `favoriteHero` 被设置了,它就会通过调用一个组件方法来检查电影英雄。
|
||||
如果该方法返回 `true`,我们就会看到“Excellent choice!”。
|
||||
如果该方法返回 `false`,我们就会看到“No movie, sorry!”。
|
||||
|
||||
The (*) before `ngSwitchCase` and `ngSwitchDefault` is required in this example.
|
||||
|
||||
在这个例子中,`ngSwitchCase`和`ngSwitchDefault`前面的星号(*)是必须的。
|
||||
在这个例子中,`ngSwitchCase` 和 `ngSwitchDefault` 前面的星号(*)是必须的。
|
||||
|
||||
For more information, see [The NgSwitch directives](guide/template-syntax#ngSwitch)
|
||||
section of the [Template Syntax](guide/template-syntax) page.
|
||||
|
||||
要了解更多信息,参见[模板语法](guide/template-syntax)中的[NgSwitch指令](guide/template-syntax#ngSwitch)部分。
|
||||
要了解更多信息,参见[模板语法](guide/template-syntax)中的[NgSwitch 指令](guide/template-syntax#ngSwitch)部分。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -959,8 +959,8 @@ Angular **pipes** provide formatting and transformation for data in the template
|
|||
Many of the built-in filters in AngularJS have corresponding pipes in Angular.
|
||||
For more information on pipes, see [Pipes](guide/pipes).
|
||||
|
||||
Angular中的**管道**为模板提供了格式化和数据转换功能,类似于AngularJS中的**过滤器**。
|
||||
AngularJS中的很多内置过滤器在Angular中都有对应的管道。
|
||||
Angular 中的**管道**为模板提供了格式化和数据转换功能,类似于 AngularJS 中的**过滤器**。
|
||||
AngularJS 中的很多内置过滤器在 Angular 中都有对应的管道。
|
||||
要了解管道的更多信息,参见[Pipes](guide/pipes)。
|
||||
|
||||
<table width="100%">
|
||||
|
@ -1015,7 +1015,7 @@ AngularJS中的很多内置过滤器在Angular中都有对应的管道。
|
|||
|
||||
The Angular `currency` pipe is similar although some of the parameters have changed.
|
||||
|
||||
Angular的`currency`管道和1中很相似,只是有些参数变化了。
|
||||
Angular 的 `currency` 管道和 1 中很相似,只是有些参数变化了。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -1047,7 +1047,7 @@ AngularJS中的很多内置过滤器在Angular中都有对应的管道。
|
|||
|
||||
The Angular `date` pipe is similar.
|
||||
|
||||
Angular的`date`管道和它很相似。
|
||||
Angular 的 `date` 管道和它很相似。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -1079,7 +1079,7 @@ AngularJS中的很多内置过滤器在Angular中都有对应的管道。
|
|||
|
||||
For performance reasons, no comparable pipe exists in Angular. Do all your filtering in the component. If you need the same filtering code in several templates, consider building a custom pipe.
|
||||
|
||||
在Angular中,出于性能的考虑,并没有一个类似的管道。
|
||||
在 Angular 中,出于性能的考虑,并没有一个类似的管道。
|
||||
过滤逻辑应该在组件中用代码实现。
|
||||
如果它将被复用在几个模板中,可以考虑构建一个自定义管道。
|
||||
|
||||
|
@ -1101,7 +1101,7 @@ AngularJS中的很多内置过滤器在Angular中都有对应的管道。
|
|||
|
||||
Converts a JavaScript object into a JSON string. This is useful for debugging.
|
||||
|
||||
把一个JavaScript对象转换成一个JSON字符串。这对调试很有用。
|
||||
把一个 JavaScript 对象转换成一个 JSON 字符串。这对调试很有用。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -1113,7 +1113,7 @@ AngularJS中的很多内置过滤器在Angular中都有对应的管道。
|
|||
|
||||
The Angular `json` pipe does the same thing.
|
||||
|
||||
Angular的`json`管道做完全相同的事。
|
||||
Angular 的 `json` 管道做完全相同的事。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -1149,9 +1149,9 @@ AngularJS中的很多内置过滤器在Angular中都有对应的管道。
|
|||
The first parameter is the starting index; the second is the limit.
|
||||
As in AngularJS, coding this operation within the component instead could improve performance.
|
||||
|
||||
`SlicePipe`做同样的事,但是*两个参数的顺序是相反的*,以便于JavaScript中的`slice`方法保持一致。
|
||||
`SlicePipe` 做同样的事,但是*两个参数的顺序是相反的*,以便于 JavaScript 中的 `slice` 方法保持一致。
|
||||
第一个参数是起始索引号,第二个参数是限制的数量。
|
||||
和AngularJS中一样,如果们改用组件中的代码实现此操作,性能将会提升。
|
||||
和 AngularJS 中一样,如果们改用组件中的代码实现此操作,性能将会提升。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -1183,7 +1183,7 @@ AngularJS中的很多内置过滤器在Angular中都有对应的管道。
|
|||
|
||||
The Angular `lowercase` pipe does the same thing.
|
||||
|
||||
Angular的`lowercase`管道和1中的功能完全相同。
|
||||
Angular 的 `lowercase` 管道和 1 中的功能完全相同。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -1217,13 +1217,13 @@ AngularJS中的很多内置过滤器在Angular中都有对应的管道。
|
|||
It provides more functionality when defining
|
||||
the decimal places, as shown in the second example above.
|
||||
|
||||
Angular的`number`管道很相似。
|
||||
Angular 的 `number` 管道很相似。
|
||||
但在指定小数点位置时,它提供了更多的功能,如第二个范例所示。
|
||||
|
||||
Angular also has a `percent` pipe, which formats a number as a local percentage
|
||||
as shown in the third example.
|
||||
|
||||
Angular还有一个`percent`管道,它把一个数组格式化为本地化的(local)百分比格式,如第三个范例所示。
|
||||
Angular 还有一个 `percent` 管道,它把一个数组格式化为本地化的(local)百分比格式,如第三个范例所示。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -1245,7 +1245,7 @@ AngularJS中的很多内置过滤器在Angular中都有对应的管道。
|
|||
In this example, the movie title orders the `movieList`.
|
||||
|
||||
使用表达式中所指定的方式对集合进行排序。
|
||||
在这个例子中,`movieList`被根据movie的title排序了。
|
||||
在这个例子中,`movieList` 被根据 movie 的 title 排序了。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -1258,7 +1258,7 @@ AngularJS中的很多内置过滤器在Angular中都有对应的管道。
|
|||
For performance reasons, no comparable pipe exists in Angular.
|
||||
Instead, use component code to order or sort results. If you need the same ordering or sorting code in several templates, consider building a custom pipe.
|
||||
|
||||
在Angular中,出于性能的考虑,并没有一个类似的管道。
|
||||
在 Angular 中,出于性能的考虑,并没有一个类似的管道。
|
||||
排序逻辑应该在组件中用代码实现。
|
||||
如果它将被复用在几个模板中,可以考虑构建一个自定义管道。
|
||||
|
||||
|
@ -1276,18 +1276,18 @@ AngularJS中的很多内置过滤器在Angular中都有对应的管道。
|
|||
|
||||
In both AngularJS and Angular, modules help you organize your application into cohesive blocks of functionality.
|
||||
|
||||
无论在AngularJS还是Angular中,我们都要借助“模块”来把应用拆分成一些紧密相关的功能块。
|
||||
无论在 AngularJS 还是 Angular 中,我们都要借助“模块”来把应用拆分成一些紧密相关的功能块。
|
||||
|
||||
In AngularJS, you write the code that provides the model and the methods for the view in a **controller**.
|
||||
In Angular, you build a **component**.
|
||||
|
||||
在AngularJS中,我们在**控制器**中写代码,来为视图提供模型和方法。
|
||||
在Angular中,我们创建**组件**。
|
||||
在 AngularJS 中,我们在**控制器**中写代码,来为视图提供模型和方法。
|
||||
在 Angular 中,我们创建**组件**。
|
||||
|
||||
Because much AngularJS code is in JavaScript, JavaScript code is shown in the AngularJS column.
|
||||
The Angular code is shown using TypeScript.
|
||||
|
||||
因为很多AngularJS的代码是用JavaScript写的,所以在AngularJS列显示的是JavaScript代码,而Angular列显示的是TypeScript代码。
|
||||
因为很多 AngularJS 的代码是用 JavaScript 写的,所以在 AngularJS 列显示的是 JavaScript 代码,而 Angular 列显示的是 TypeScript 代码。
|
||||
|
||||
<table width="100%">
|
||||
|
||||
|
@ -1332,7 +1332,7 @@ The Angular code is shown using TypeScript.
|
|||
In AngularJS, an immediately invoked function expression (or IIFE) around controller code
|
||||
keeps it out of the global namespace.
|
||||
|
||||
在AngularJS中,用立即调用的函数表达式(IIFE)来包裹控制器代码可以让控制器代码不会污染全局命名空间。
|
||||
在 AngularJS 中,用立即调用的函数表达式(IIFE)来包裹控制器代码可以让控制器代码不会污染全局命名空间。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -1345,7 +1345,7 @@ The Angular code is shown using TypeScript.
|
|||
This is a nonissue in Angular because ES 2015 modules
|
||||
handle the namespacing for you.
|
||||
|
||||
在Angular中我们不用担心这个问题,因为使用ES 2015的模块,模块会替我们处理命名空间问题。
|
||||
在 Angular 中我们不用担心这个问题,因为使用 ES 2015 的模块,模块会替我们处理命名空间问题。
|
||||
|
||||
For more information on modules, see the [Modules](guide/architecture#modules) section of the
|
||||
[Architecture Overview](guide/architecture).
|
||||
|
@ -1362,7 +1362,7 @@ The Angular code is shown using TypeScript.
|
|||
|
||||
### Angular modules
|
||||
|
||||
### Angular模块
|
||||
### Angular 模块
|
||||
|
||||
<code-example hideCopy>
|
||||
|
||||
|
@ -1373,7 +1373,7 @@ The Angular code is shown using TypeScript.
|
|||
In AngularJS, an Angular module keeps track of controllers, services, and other code.
|
||||
The second argument defines the list of other modules that this module depends upon.
|
||||
|
||||
在AngularJS中,Angular模块用来对控制器、服务和其它代码进行跟踪。第二个参数定义该模块依赖的其它模块列表。
|
||||
在 AngularJS 中,Angular 模块用来对控制器、服务和其它代码进行跟踪。第二个参数定义该模块依赖的其它模块列表。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -1385,7 +1385,7 @@ The Angular code is shown using TypeScript.
|
|||
|
||||
NgModules, defined with the `NgModule` decorator, serve the same purpose:
|
||||
|
||||
Angular的模块用`NgModule`装饰器进行定义,有如下用途:
|
||||
Angular 的模块用 `NgModule` 装饰器进行定义,有如下用途:
|
||||
|
||||
* `imports`: specifies the list of other modules that this module depends upon
|
||||
|
||||
|
@ -1424,7 +1424,7 @@ The Angular code is shown using TypeScript.
|
|||
AngularJS has code in each controller that looks up an appropriate Angular module
|
||||
and registers the controller with that module.
|
||||
|
||||
在AngularJS中,在每个控制器中都有一些代码,用于找到合适的Angular模块并把该控制器注册进去。
|
||||
在 AngularJS 中,在每个控制器中都有一些代码,用于找到合适的 Angular 模块并把该控制器注册进去。
|
||||
|
||||
The first argument is the controller name. The second argument defines the string names of
|
||||
all dependencies injected into this controller, and a reference to the controller function.
|
||||
|
@ -1445,8 +1445,8 @@ The Angular code is shown using TypeScript.
|
|||
The `@Component` decorator declares that the class is a component and provides metadata about
|
||||
that component such as its selector (or tag) and its template.
|
||||
|
||||
在Angular中,我们往组件类上添加了一个装饰器,以提供任何需要的元数据。
|
||||
`@Component`装饰器把该类声明为组件,并提供了关于该组件的元数据,比如它的选择器(或标签)和模板。
|
||||
在 Angular 中,我们往组件类上添加了一个装饰器,以提供任何需要的元数据。
|
||||
`@Component` 装饰器把该类声明为组件,并提供了关于该组件的元数据,比如它的选择器(或标签)和模板。
|
||||
|
||||
This is how you associate a template with logic, which is defined in the component class.
|
||||
|
||||
|
@ -1478,7 +1478,7 @@ The Angular code is shown using TypeScript.
|
|||
|
||||
In AngularJS, you write the code for the model and methods in a controller function.
|
||||
|
||||
在Angular1中,我们在控制器函数中写模型和方法的代码。
|
||||
在 Angular1 中,我们在控制器函数中写模型和方法的代码。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -1492,11 +1492,11 @@ The Angular code is shown using TypeScript.
|
|||
|
||||
In Angular, you create a component class.
|
||||
|
||||
在Angular中,我们写组件类。
|
||||
在 Angular 中,我们写组件类。
|
||||
|
||||
NOTE: If you are using TypeScript with AngularJS, you must use the `export` keyword to export the component class.
|
||||
|
||||
注意:如果你正在用TypeScript写AngularJS,那么必须用`export`关键字来导出组件类。
|
||||
注意:如果你正在用 TypeScript 写 AngularJS,那么必须用 `export` 关键字来导出组件类。
|
||||
|
||||
For more information, see the [Components](guide/architecture#components)
|
||||
section of the [Architecture Overview](guide/architecture) page.
|
||||
|
@ -1526,13 +1526,13 @@ The Angular code is shown using TypeScript.
|
|||
In AngularJS, you pass in any dependencies as controller function arguments.
|
||||
This example injects a `MovieService`.
|
||||
|
||||
在AngularJS中,我们把所有依赖都作为控制器函数的参数。
|
||||
在这个例子中,我们注入了一个`MovieService`。
|
||||
在 AngularJS 中,我们把所有依赖都作为控制器函数的参数。
|
||||
在这个例子中,我们注入了一个 `MovieService`。
|
||||
|
||||
To guard against minification problems, tell Angular explicitly
|
||||
that it should inject an instance of the `MovieService` in the first parameter.
|
||||
|
||||
我们还通过在第一个参数明确告诉Angular它应该注入一个`MovieService`的实例,以防止在最小化时出现问题。
|
||||
我们还通过在第一个参数明确告诉 Angular 它应该注入一个 `MovieService` 的实例,以防止在最小化时出现问题。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -1548,9 +1548,9 @@ The Angular code is shown using TypeScript.
|
|||
This example injects a `MovieService`.
|
||||
The first parameter's TypeScript type tells Angular what to inject, even after minification.
|
||||
|
||||
在Angular中,我们把依赖作为组件构造函数的参数传入。
|
||||
在这个例子中,我们注入了一个`MovieService`。
|
||||
即使在最小化之后,第一个参数的TypeScript类型也会告诉Angular它该注入什么。
|
||||
在 Angular 中,我们把依赖作为组件构造函数的参数传入。
|
||||
在这个例子中,我们注入了一个 `MovieService`。
|
||||
即使在最小化之后,第一个参数的 TypeScript 类型也会告诉 Angular 它该注入什么。
|
||||
|
||||
For more information, see the [Dependency injection](guide/architecture#dependency-injection)
|
||||
section of the [Architecture Overview](guide/architecture).
|
||||
|
@ -1577,9 +1577,9 @@ In Angular, you can still define style sheets for your entire application. But n
|
|||
also encapsulate a style sheet within a specific component.
|
||||
|
||||
样式表美化我们的应用程序。
|
||||
在AngularJS中,我们为整个应用程序指定样式表。
|
||||
在 AngularJS 中,我们为整个应用程序指定样式表。
|
||||
当应用程序成长一段时间之后,应用程序中很多部分的样式会被合并,导致无法预计的后果。
|
||||
在Angular中,我们仍然会为整个应用程序定义样式,不过现在也可以把样式表封装在特定的组件中。
|
||||
在 Angular 中,我们仍然会为整个应用程序定义样式,不过现在也可以把样式表封装在特定的组件中。
|
||||
|
||||
<table width="100%">
|
||||
|
||||
|
@ -1613,7 +1613,7 @@ also encapsulate a style sheet within a specific component.
|
|||
|
||||
### Link tag
|
||||
|
||||
### Link标签
|
||||
### Link 标签
|
||||
|
||||
<code-example hideCopy>
|
||||
|
||||
|
@ -1624,7 +1624,7 @@ also encapsulate a style sheet within a specific component.
|
|||
AngularJS, uses a `link` tag in the head section of the `index.html` file
|
||||
to define the styles for the application.
|
||||
|
||||
在AngularJS中,我们在`index.html`的`head`区使用`link`标签来为应用程序定义样式。
|
||||
在 AngularJS 中,我们在 `index.html` 的 `head` 区使用 `link` 标签来为应用程序定义样式。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -1647,7 +1647,7 @@ also encapsulate a style sheet within a specific component.
|
|||
In Angular, you can use the `styles` or `styleUrls` property of the `@Component` metadata to define
|
||||
a style sheet for a particular component.
|
||||
|
||||
在Angular中,我们可以在`@Component`的元数据中使用`styles`或`styleUrls`属性来为一个特定的组件定义样式表。
|
||||
在 Angular 中,我们可以在 `@Component` 的元数据中使用 `styles` 或 `styleUrls` 属性来为一个特定的组件定义样式表。
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="style-url" linenums="false"></code-example>
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@ user interfaces transition smoothly between states with engaging animations
|
|||
that call attention where it's needed. Well-designed animations can make a UI not only
|
||||
more fun but also easier to use.
|
||||
|
||||
动画是现代Web应用设计中一个很重要的方面。我们希望用户界面能在不同的状态之间更平滑的转场。如果需要,还可以用适当的动画来吸引注意力。
|
||||
设计良好的动画不但会让UI更有趣,还会让它更容易使用。
|
||||
动画是现代 Web 应用设计中一个很重要的方面。我们希望用户界面能在不同的状态之间更平滑的转场。如果需要,还可以用适当的动画来吸引注意力。
|
||||
设计良好的动画不但会让 UI 更有趣,还会让它更容易使用。
|
||||
|
||||
## Overview
|
||||
|
||||
|
@ -18,7 +18,7 @@ Angular's animation system lets you build animations that run with the same kind
|
|||
performance found in pure CSS animations. You can also tightly integrate your
|
||||
animation logic with the rest of your application code, for ease of control.
|
||||
|
||||
Angular的动画系统赋予了制作各种动画效果的能力,以构建出与原生CSS动画性能相同的动画。
|
||||
Angular 的动画系统赋予了制作各种动画效果的能力,以构建出与原生 CSS 动画性能相同的动画。
|
||||
我们也获得了额外的让动画逻辑与其它应用代码紧紧集成在一起的能力,这让动画可以被更容易的触发与控制。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
@ -26,7 +26,7 @@ Angular的动画系统赋予了制作各种动画效果的能力,以构建出
|
|||
Angular animations are built on top of the standard [Web Animations API](https://w3c.github.io/web-animations/)
|
||||
and run natively on [browsers that support it](http://caniuse.com/#feat=web-animation).
|
||||
|
||||
Angular动画是基于标准的[Web动画API(Web Animations API)](https://w3c.github.io/web-animations/)构建的,它们在[支持此API的浏览器中](http://caniuse.com/#feat=web-animation)会用原生方式工作。
|
||||
Angular 动画是基于标准的[Web 动画 API(Web Animations API)](https://w3c.github.io/web-animations/)构建的,它们在[支持此 API 的浏览器中](http://caniuse.com/#feat=web-animation)会用原生方式工作。
|
||||
|
||||
As of Angular 6, If the Web Animations API is not supported natively by the browser, then Angular will use CSS
|
||||
keyframes as a fallback instead (automatically). This means that the polyfill is no longer required unless any
|
||||
|
@ -94,7 +94,7 @@ driven by a model attribute.
|
|||
|
||||
Animations can be defined inside `@Component` metadata.
|
||||
|
||||
动画会被定义在`@Component`元数据中。
|
||||
动画会被定义在 `@Component` 元数据中。
|
||||
|
||||
<code-example path="animations/src/app/hero-list-basic.component.ts" region="imports" title="hero-list-basic.component.ts" linenums="false"></code-example>
|
||||
|
||||
|
@ -102,7 +102,7 @@ With these, you can define an *animation trigger* called `heroState` in the comp
|
|||
metadata. It uses animations to transition between two states: `active` and `inactive`. When a
|
||||
hero is active, the element appears in a slightly larger size and lighter color.
|
||||
|
||||
通过这些,可以在组件元数据中定义一个名叫`heroState`的*动画触发器*。它在两个状态`active`和`inactive`之间进行转场。
|
||||
通过这些,可以在组件元数据中定义一个名叫 `heroState` 的*动画触发器*。它在两个状态 `active` 和 `inactive` 之间进行转场。
|
||||
当英雄处于激活状态时,它会把该元素显示得稍微大一点、亮一点。
|
||||
|
||||
<code-example path="animations/src/app/hero-list-basic.component.ts" region="animationdef" title="hero-list-basic.component.ts (@Component excerpt)" linenums="false"></code-example>
|
||||
|
@ -112,14 +112,14 @@ hero is active, the element appears in a slightly larger size and lighter color.
|
|||
In this example, you are defining animation styles (color and transform) inline in the
|
||||
animation metadata.
|
||||
|
||||
在这个例子中,我们在元数据中用内联的方式定义了动画样式(`color`和`transform`)。在即将到来的一个Angular版本中,还将支持从组件的CSS样式表中提取样式。
|
||||
在这个例子中,我们在元数据中用内联的方式定义了动画样式(`color` 和 `transform`)。在即将到来的一个 Angular 版本中,还将支持从组件的 CSS 样式表中提取样式。
|
||||
|
||||
</div>
|
||||
|
||||
Now, using the `[@triggerName]` syntax, attach the animation that you just defined to
|
||||
one or more elements in the component's template.
|
||||
|
||||
我们刚刚定义了一个动画,但它还没有被用到任何地方。要想使用它,可以在模板中用`[@triggerName]`语法来把它附加到一个或多个元素上。
|
||||
我们刚刚定义了一个动画,但它还没有被用到任何地方。要想使用它,可以在模板中用 `[@triggerName]` 语法来把它附加到一个或多个元素上。
|
||||
|
||||
<code-example path="animations/src/app/hero-list-basic.component.ts" region="template" title="hero-list-basic.component.ts (excerpt)" linenums="false"></code-example>
|
||||
|
||||
|
@ -127,8 +127,8 @@ Here, the animation trigger applies to every element repeated by an `ngFor`. Eac
|
|||
the repeated elements animates independently. The value of the
|
||||
attribute is bound to the expression `hero.state` and is always either `active` or `inactive`.
|
||||
|
||||
这里,我们把该动画触发器添加到了由`ngFor`重复出来的每一个元素上。每个重复出来的元素都有独立的动画效果。
|
||||
然后把`@triggerName`属性(Attribute)的值设置成表达式`hero.state`。这个值应该或者是`inactive`或者是`active`,因为我们刚刚为它们俩定义过动画状态。
|
||||
这里,我们把该动画触发器添加到了由 `ngFor` 重复出来的每一个元素上。每个重复出来的元素都有独立的动画效果。
|
||||
然后把 `@triggerName` 属性(Attribute)的值设置成表达式 `hero.state`。这个值应该或者是 `inactive` 或者是 `active`,因为我们刚刚为它们俩定义过动画状态。
|
||||
|
||||
With this setup, an animated transition appears whenever a hero object changes state.
|
||||
Here's the full component implementation:
|
||||
|
@ -144,7 +144,7 @@ Here's the full component implementation:
|
|||
Angular animations are defined as logical **states** and **transitions**
|
||||
between states.
|
||||
|
||||
Angular动画是由**状态**和**状态之间的转场效果**所定义的。
|
||||
Angular 动画是由**状态**和**状态之间的转场效果**所定义的。
|
||||
|
||||
An animation state is a string value that you define in your application code. In the example
|
||||
above, the states `'active'` and `'inactive'` are based on the logical state of
|
||||
|
@ -152,7 +152,7 @@ hero objects. The source of the state can be a simple object attribute, as it wa
|
|||
or it can be a value computed in a method. The important thing is that you can read it into the
|
||||
component's template.
|
||||
|
||||
动画状态是一个由程序代码中定义的字符串值。在上面的例子中,基于英雄对象的逻辑状态,我们使用了`'active'`和`'inactive'`这两种状态。
|
||||
动画状态是一个由程序代码中定义的字符串值。在上面的例子中,基于英雄对象的逻辑状态,我们使用了 `'active'` 和 `'inactive'` 这两种状态。
|
||||
状态的来源可以是像本例中这样简单的对象属性,也可以是由方法计算出来的值。重点是,我们得能从组件模板中读取它。
|
||||
|
||||
You can define *styles* for each animation state:
|
||||
|
@ -165,7 +165,7 @@ These `state` definitions specify the *end styles* of each state.
|
|||
They are applied to the element once it has transitioned to that state, and stay
|
||||
*as long as it remains in that state*. In effect, you're defining what styles the element has in different states.
|
||||
|
||||
这些`state`具体定义了每个状态的*最终样式*。一旦元素转场到那个状态,该样式就会被应用到此元素上,*当它留在此状态时*,这些样式也会一直保持着。
|
||||
这些 `state` 具体定义了每个状态的*最终样式*。一旦元素转场到那个状态,该样式就会被应用到此元素上,*当它留在此状态时*,这些样式也会一直保持着。
|
||||
从这个意义上讲,这里其实并不只是在定义动画,而是在定义该元素在不同状态时应该具有的样式。
|
||||
|
||||
After you define states, you can define *transitions* between the states. Each transition
|
||||
|
@ -182,14 +182,14 @@ controls the timing of switching between one set of styles and the next:
|
|||
If several transitions have the same timing configuration, you can combine
|
||||
them into the same `transition` definition:
|
||||
|
||||
如果多个转场都有同样的时间线配置,就可以把它们合并进同一个`transition`定义中:
|
||||
如果多个转场都有同样的时间线配置,就可以把它们合并进同一个 `transition` 定义中:
|
||||
|
||||
<code-example path="animations/src/app/hero-list-combined-transitions.component.ts" region="transitions" title="src/app/hero-list-combined-transitions.component.ts" linenums="false"></code-example>
|
||||
|
||||
When both directions of a transition have the same timing, as in the previous
|
||||
example, you can use the shorthand syntax `<=>`:
|
||||
|
||||
如果要对同一个转场的两个方向都使用相同的时间线(就像前面的例子中那样),就可以使用`<=>`这种简写语法:
|
||||
如果要对同一个转场的两个方向都使用相同的时间线(就像前面的例子中那样),就可以使用 `<=>` 这种简写语法:
|
||||
|
||||
<code-example path="animations/src/app/hero-list-twoway.component.ts" region="transitions" title="src/app/hero-list-twoway.component.ts" linenums="false"></code-example>
|
||||
|
||||
|
@ -199,8 +199,8 @@ the element receives one set of styles immediately and is then animated to the n
|
|||
When the transition finishes, none of these styles are kept because they're not
|
||||
defined in a `state`.
|
||||
|
||||
有时希望一些样式只在动画期间生效,但在结束后并不保留它们。这时可以把这些样式内联在`transition`中进行定义。
|
||||
在这个例子中,该元素会立刻获得一组样式,然后动态转场到下一个状态。当转场结束时,这些样式并不会被保留,因为它们并没有被定义在`state`中。
|
||||
有时希望一些样式只在动画期间生效,但在结束后并不保留它们。这时可以把这些样式内联在 `transition` 中进行定义。
|
||||
在这个例子中,该元素会立刻获得一组样式,然后动态转场到下一个状态。当转场结束时,这些样式并不会被保留,因为它们并没有被定义在 `state` 中。
|
||||
|
||||
<code-example path="animations/src/app/hero-list-inline-styles.component.ts" region="transitions" title="src/app/hero-list-inline-styles.component.ts" linenums="false"></code-example>
|
||||
|
||||
|
@ -215,11 +215,11 @@ transitions that apply regardless of which state the animation is in. For exampl
|
|||
|
||||
* The `active => *` transition applies when the element's state changes from `active` to anything else.
|
||||
|
||||
当该元素的状态从`active`变成任何其它状态时,`active => *`转场都会生效。
|
||||
当该元素的状态从 `active` 变成任何其它状态时,`active => *` 转场都会生效。
|
||||
|
||||
* The `* => *` transition applies when *any* change between two states takes place.
|
||||
|
||||
当在*任意*两个状态之间切换时,`* => *`转场都会生效。
|
||||
当在*任意*两个状态之间切换时,`* => *` 转场都会生效。
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/animations/ng_animate_transitions_inactive_active_wildcards.png" alt="The wildcard state can be used to match many different transitions at once" width="400">
|
||||
|
@ -227,20 +227,20 @@ transitions that apply regardless of which state the animation is in. For exampl
|
|||
|
||||
### The `void` state
|
||||
|
||||
### `void`状态
|
||||
### `void` 状态
|
||||
|
||||
The special state called `void` can apply to any animation. It applies
|
||||
when the element is *not* attached to a view, perhaps because it has not yet been
|
||||
added or because it has been removed. The `void` state is useful for defining enter and
|
||||
leave animations.
|
||||
|
||||
有一种叫做`void`的特殊状态,它可以应用在任何动画中。它表示元素*没有*被附加到视图。这种情况可能是由于它尚未被添加进来或者已经被移除了。
|
||||
`void`状态在定义“进场”和“离场”的动画时会非常有用。
|
||||
有一种叫做 `void` 的特殊状态,它可以应用在任何动画中。它表示元素*没有*被附加到视图。这种情况可能是由于它尚未被添加进来或者已经被移除了。
|
||||
`void` 状态在定义“进场”和“离场”的动画时会非常有用。
|
||||
|
||||
For example the `* => void` transition applies when the element leaves the view,
|
||||
regardless of what state it was in before it left.
|
||||
|
||||
比如当一个元素离开视图时,`* => void`转场就会生效,而不管它在离场以前是什么状态。
|
||||
比如当一个元素离开视图时,`* => void` 转场就会生效,而不管它在离场以前是什么状态。
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/animations/ng_animate_transitions_void_in.png" alt="The void state can be used for enter and leave transitions" width="400">
|
||||
|
@ -248,7 +248,7 @@ regardless of what state it was in before it left.
|
|||
|
||||
The wildcard state `*` also matches `void`.
|
||||
|
||||
`*`通配符状态也能匹配`void`。
|
||||
`*` 通配符状态也能匹配 `void`。
|
||||
|
||||
## Example: Entering and leaving
|
||||
|
||||
|
@ -259,7 +259,7 @@ The wildcard state `*` also matches `void`.
|
|||
Using the `void` and `*` states you can define transitions that animate the
|
||||
entering and leaving of elements:
|
||||
|
||||
使用`void`和`*`状态,可以定义元素进场与离场时的转场动画:
|
||||
使用 `void` 和 `*` 状态,可以定义元素进场与离场时的转场动画:
|
||||
|
||||
* Enter: `void => *`
|
||||
|
||||
|
@ -272,7 +272,7 @@ entering and leaving of elements:
|
|||
For example, in the `animations` array below there are two transitions that use
|
||||
the `void => *` and `* => void` syntax to animate the element in and out of the view.
|
||||
|
||||
例如,在下面的`animations`数组中,这两个转场语句使用`void => *`和`* => void`语法来让该元素以动画形式进入和离开当前视图。
|
||||
例如,在下面的 `animations` 数组中,这两个转场语句使用 `void => *` 和 `* => void` 语法来让该元素以动画形式进入和离开当前视图。
|
||||
|
||||
<code-example path="animations/src/app/hero-list-enter-leave.component.ts" region="animationdef" title="hero-list-enter-leave.component.ts (excerpt)" linenums="false"></code-example>
|
||||
|
||||
|
@ -281,7 +281,7 @@ transition definitions, and not in a separate `state(void)` definition. Thus, th
|
|||
are different on enter and leave: the element enters from the left
|
||||
and leaves to the right.
|
||||
|
||||
注意,在这个例子中,这些样式在转场定义中被直接应用到了`void`状态,但并没有一个单独的`state(void)`定义。
|
||||
注意,在这个例子中,这些样式在转场定义中被直接应用到了 `void` 状态,但并没有一个单独的 `state(void)` 定义。
|
||||
这么做是因为希望在进场与离场时使用不一样的转换效果:元素从左侧进场,从右侧离开。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
@ -348,7 +348,7 @@ borders, and many others. The W3C maintains
|
|||
[a list of animatable properties](https://www.w3.org/TR/css3-transitions/#animatable-properties)
|
||||
on its [CSS Transitions page](https://www.w3.org/TR/css3-transitions).
|
||||
|
||||
由于Angular的动画支持是基于Web Animations标准的,所以也能支持浏览器认为可以*参与动画*的任何属性。这些属性包括位置(position)、大小(size)、变换(transform)、颜色(color)、边框(border)等很多属性。W3C维护着
|
||||
由于 Angular 的动画支持是基于 Web Animations 标准的,所以也能支持浏览器认为可以*参与动画*的任何属性。这些属性包括位置(position)、大小(size)、变换(transform)、颜色(color)、边框(border)等很多属性。W3C 维护着
|
||||
[一个“可动”属性列表](https://www.w3.org/TR/css3-transitions/#animatable-properties)。
|
||||
|
||||
For positional properties that have a numeric value, you can define a unit by providing
|
||||
|
@ -368,7 +368,7 @@ If you don't provide a unit when specifying dimension, Angular assumes the defau
|
|||
|
||||
* `50` is the same as saying `'50px'`
|
||||
|
||||
`50`相当于`'50px'`
|
||||
`50` 相当于 `'50px'`
|
||||
|
||||
## Automatic property calculation
|
||||
|
||||
|
@ -381,17 +381,17 @@ For example, elements often have widths and heights that
|
|||
depend on their content and the screen size. These properties are often tricky
|
||||
to animate with CSS.
|
||||
|
||||
有时候,我们想在动画中使用的尺寸类样式,它的值在开始运行之前都是不可知的。比如,元素的宽度和高度往往依赖于它们的内容和屏幕的尺寸。处理这些属性对CSS动画而言通常是相当棘手的。
|
||||
有时候,我们想在动画中使用的尺寸类样式,它的值在开始运行之前都是不可知的。比如,元素的宽度和高度往往依赖于它们的内容和屏幕的尺寸。处理这些属性对 CSS 动画而言通常是相当棘手的。
|
||||
|
||||
In these cases, you can use a special `*` property value so that the value of the
|
||||
property is computed at runtime and then plugged into the animation.
|
||||
|
||||
如果用Angular动画,就可以用一个特殊的`*`属性值来处理这种情况。该属性的值将会在运行期被计算出来,然后插入到这个动画中。
|
||||
如果用 Angular 动画,就可以用一个特殊的 `*` 属性值来处理这种情况。该属性的值将会在运行期被计算出来,然后插入到这个动画中。
|
||||
|
||||
In this example, the leave animation takes whatever height the element has before it
|
||||
leaves and animates from that height to zero:
|
||||
|
||||
这个例子中的“离场”动画会取得该元素在离场前的高度,并且把它从这个高度用动画转场到0高度:
|
||||
这个例子中的“离场”动画会取得该元素在离场前的高度,并且把它从这个高度用动画转场到 0 高度:
|
||||
|
||||
<code-example path="animations/src/app/hero-list-auto.component.ts" region="animationdef" title="src/app/hero-list-auto.component.ts" linenums="false"></code-example>
|
||||
|
||||
|
@ -438,7 +438,7 @@ following the duration. It also has the same format options as the duration:
|
|||
|
||||
* Wait for 100ms and then run for 200ms: `'0.2s 100ms'`
|
||||
|
||||
等待100毫秒,然后运行200毫秒:`'0.2s 100ms'`。
|
||||
等待 100 毫秒,然后运行 200 毫秒:`'0.2s 100ms'`。
|
||||
|
||||
### Easing
|
||||
|
||||
|
@ -450,15 +450,15 @@ the animation to begin relatively slowly but pick up speed as it progresses. You
|
|||
can control the easing by adding it as a *third* value in the string after the duration
|
||||
and the delay (or as the *second* value when there is no delay):
|
||||
|
||||
[缓动函数](http://easings.net/)用于控制动画在运行期间如何加速和减速。比如:使用`ease-in`函数意味着动画开始时相对缓慢,然后在进行中逐步加速。可以通过在这个字符串中的持续时间和延迟后面添加*第三个*值来控制使用哪个缓动函数(如果没有定义延迟就作为*第二个*值)。
|
||||
[缓动函数](http://easings.net/)用于控制动画在运行期间如何加速和减速。比如:使用 `ease-in` 函数意味着动画开始时相对缓慢,然后在进行中逐步加速。可以通过在这个字符串中的持续时间和延迟后面添加*第三个*值来控制使用哪个缓动函数(如果没有定义延迟就作为*第二个*值)。
|
||||
|
||||
* Wait for 100ms and then run for 200ms, with easing: `'0.2s 100ms ease-out'`
|
||||
|
||||
等待100毫秒,然后运行200毫秒,并且带缓动:`'0.2s 100ms ease-out'`
|
||||
等待 100 毫秒,然后运行 200 毫秒,并且带缓动:`'0.2s 100ms ease-out'`
|
||||
|
||||
* Run for 200ms, with easing: `'0.2s ease-in-out'`
|
||||
|
||||
运行200毫秒,并且带缓动:`'0.2s ease-in-out'`
|
||||
运行 200 毫秒,并且带缓动:`'0.2s ease-in-out'`
|
||||
|
||||
<img src="generated/images/guide/animations/animation_timings.gif" alt="Animations with specific timings" class="right" width="220">
|
||||
|
||||
|
@ -470,7 +470,7 @@ Here are a couple of custom timings in action. Both enter and leave last for
|
|||
200 milliseconds, that is `0.2s`, but they have different easings. The leave begins after a
|
||||
slight delay of 10 milliseconds as specified in `'0.2s 10 ease-out'`:
|
||||
|
||||
这里是两个自定义时间线的动态演示。“进场”和“离场”都持续200毫秒,也就是`0.2s`,但它们有不同的缓动函数。“离场”动画会在100毫秒的延迟之后开始,也就是`'0.2s 10 ease-out'`:
|
||||
这里是两个自定义时间线的动态演示。“进场”和“离场”都持续 200 毫秒,也就是 `0.2s`,但它们有不同的缓动函数。“离场”动画会在 100 毫秒的延迟之后开始,也就是 `'0.2s 10 ease-out'`:
|
||||
|
||||
<code-example path="animations/src/app/hero-list-timings.component.ts" region="animationdef" title="hero-list-timings.component.ts (excerpt)" linenums="false"></code-example>
|
||||
|
||||
|
@ -489,7 +489,7 @@ For each keyframe, you specify an *offset* that defines at which point
|
|||
in the animation that keyframe applies. The offset is a number between zero,
|
||||
which marks the beginning of the animation, and one, which marks the end.
|
||||
|
||||
每个关键帧都可以被指定一个*偏移量*,用来定义该关键帧将被用在动画期间的哪个时间点。偏移量是一个介于0(表示动画起点)和1(表示动画终点)之间的数组。
|
||||
每个关键帧都可以被指定一个*偏移量*,用来定义该关键帧将被用在动画期间的哪个时间点。偏移量是一个介于 0(表示动画起点)和 1(表示动画终点)之间的数组。
|
||||
|
||||
This example adds some "bounce" to the enter and leave animations with
|
||||
keyframes:
|
||||
|
@ -502,13 +502,13 @@ Note that the offsets are *not* defined in terms of absolute time. They are rela
|
|||
measures from zero to one. The final timeline of the animation is based on the combination
|
||||
of keyframe offsets, duration, delay, and easing.
|
||||
|
||||
注意,这个偏移量并*不是*用绝对数字定义的时间段,而是在0到1之间的相对值(百分比)。动画的最终时间线会基于关键帧的偏移量、持续时间、延迟和缓动函数计算出来。
|
||||
注意,这个偏移量并*不是*用绝对数字定义的时间段,而是在 0 到 1 之间的相对值(百分比)。动画的最终时间线会基于关键帧的偏移量、持续时间、延迟和缓动函数计算出来。
|
||||
|
||||
Defining offsets for keyframes is optional. If you omit them, offsets with even
|
||||
spacing are automatically assigned. For example, three keyframes without predefined
|
||||
offsets receive offsets `0`, `0.5`, and `1`.
|
||||
|
||||
为关键帧定义偏移量是可选的。如果省略它们,偏移量会自动根据帧数平均分布出来。例如,三个未定义过偏移量的关键帧会分别获得偏移量:`0`、`0.5`和`1`。
|
||||
为关键帧定义偏移量是可选的。如果省略它们,偏移量会自动根据帧数平均分布出来。例如,三个未定义过偏移量的关键帧会分别获得偏移量:`0`、`0.5` 和 `1`。
|
||||
|
||||
## Parallel animation groups
|
||||
|
||||
|
@ -519,13 +519,13 @@ offsets receive offsets `0`, `0.5`, and `1`.
|
|||
You've seen how to animate multiple style properties at the same time:
|
||||
just put all of them into the same `style()` definition.
|
||||
|
||||
我们已经知道该如何在同一时间段进行多个样式的动画了:只要把它们都放进同一个`style()`定义中就行了!
|
||||
我们已经知道该如何在同一时间段进行多个样式的动画了:只要把它们都放进同一个 `style()` 定义中就行了!
|
||||
|
||||
But you may also want to configure different *timings* for animations that happen
|
||||
in parallel. For example, you may want to animate two CSS properties but use a
|
||||
different easing function for each one.
|
||||
|
||||
但我们也可能会希望为同时发生的几个动画配置不同的*时间线*。比如,同时对两个CSS属性做动画,但又得为它们定义不同的缓动函数。
|
||||
但我们也可能会希望为同时发生的几个动画配置不同的*时间线*。比如,同时对两个 CSS 属性做动画,但又得为它们定义不同的缓动函数。
|
||||
|
||||
For this you can use animation *groups*. In this example, using groups both on
|
||||
enter and leave allows for two different timing configurations. Both
|
||||
|
@ -538,7 +538,7 @@ are applied to the same element in parallel, but run independently of each other
|
|||
|
||||
One group animates the element transform and width; the other group animates the opacity.
|
||||
|
||||
其中一个动画组对元素的`transform`和`width`做动画,另一个组则对`opacity`做动画。
|
||||
其中一个动画组对元素的 `transform` 和 `width` 做动画,另一个组则对 `opacity` 做动画。
|
||||
|
||||
## Animation callbacks
|
||||
|
||||
|
@ -551,14 +551,14 @@ A callback is fired when an animation is started and also when it is done.
|
|||
In the keyframes example, you have a `trigger` called `@flyInOut`. You can hook
|
||||
those callbacks like this:
|
||||
|
||||
对于例子中的这个关键帧,我们有一个叫做`@flyInOut`的`trigger`。在那里我们可以挂钩到那些回调,比如:
|
||||
对于例子中的这个关键帧,我们有一个叫做 `@flyInOut` 的 `trigger`。在那里我们可以挂钩到那些回调,比如:
|
||||
|
||||
<code-example path="animations/src/app/hero-list-multistep.component.ts" region="template" title="hero-list-multistep.component.ts (excerpt)" linenums="false"></code-example>
|
||||
|
||||
The callbacks receive an `AnimationEvent` that contains useful properties such as
|
||||
`fromState`, `toState` and `totalTime`.
|
||||
|
||||
这些回调接收一个`AnimationTransitionEvent`参数,它包含一些有用的属性,例如`fromState`,`toState`和`totalTime`。
|
||||
这些回调接收一个 `AnimationTransitionEvent` 参数,它包含一些有用的属性,例如 `fromState`,`toState` 和 `totalTime`。
|
||||
|
||||
Those callbacks will fire whether or not an animation is picked up.
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ This guide explains how to build with the AOT compiler using different compiler
|
|||
|
||||
<a href="https://www.youtube.com/watch?v=kW9cJsvcsGo">Watch compiler author Tobias Bosch explain the Angular Compiler</a> at AngularConnect 2016.
|
||||
|
||||
观看编译器作者Tobias Bosch在AngularConnect 2016大会里,对<a href="http://v.youku.com/v_show/id_XMTc1NTE4NTkwOA==.html?from=y1.7-1.4" target="_blank">Angular编译器</a>的演讲。
|
||||
观看编译器作者 Tobias Bosch 在 AngularConnect 2016 大会里,对<a href="http://v.youku.com/v_show/id_XMTc1NTE4NTkwOA==.html?from=y1.7-1.4" target="_blank">Angular 编译器</a>的演讲。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -66,7 +66,7 @@ See the [CLI documentation](https://github.com/angular/angular-cli/wiki) for det
|
|||
|
||||
## Why compile with AOT?
|
||||
|
||||
## 为什么需要AOT编译?
|
||||
## 为什么需要 AOT 编译?
|
||||
|
||||
*Faster rendering*
|
||||
|
||||
|
@ -75,7 +75,7 @@ See the [CLI documentation](https://github.com/angular/angular-cli/wiki) for det
|
|||
With AOT, the browser downloads a pre-compiled version of the application.
|
||||
The browser loads executable code so it can render the application immediately, without waiting to compile the app first.
|
||||
|
||||
使用AOT,浏览器下载预编译版本的应用程序。
|
||||
使用 AOT,浏览器下载预编译版本的应用程序。
|
||||
浏览器直接加载运行代码,所以它可以立即渲染该应用,而不用等应用完成首次编译。
|
||||
|
||||
*Fewer asynchronous requests*
|
||||
|
@ -85,18 +85,18 @@ The browser loads executable code so it can render the application immediately,
|
|||
The compiler _inlines_ external HTML templates and CSS style sheets within the application JavaScript,
|
||||
eliminating separate ajax requests for those source files.
|
||||
|
||||
编译器把外部HTML模板和CSS样式表内联到了该应用的JavaScript中。
|
||||
消除了用来下载那些源文件的Ajax请求。
|
||||
编译器把外部 HTML 模板和 CSS 样式表内联到了该应用的 JavaScript 中。
|
||||
消除了用来下载那些源文件的 Ajax 请求。
|
||||
|
||||
*Smaller Angular framework download size*
|
||||
|
||||
**需要下载的Angular框架体积更小**
|
||||
**需要下载的 Angular 框架体积更小**
|
||||
|
||||
There's no need to download the Angular compiler if the app is already compiled.
|
||||
The compiler is roughly half of Angular itself, so omitting it dramatically reduces the application payload.
|
||||
|
||||
如果应用已经编译过了,自然不需要再下载Angular编译器了。
|
||||
该编译器差不多占了Angular自身体积的一半儿,所以,省略它可以显著减小应用的体积。
|
||||
如果应用已经编译过了,自然不需要再下载 Angular 编译器了。
|
||||
该编译器差不多占了 Angular 自身体积的一半儿,所以,省略它可以显著减小应用的体积。
|
||||
|
||||
*Detect template errors earlier*
|
||||
|
||||
|
@ -105,7 +105,7 @@ The compiler is roughly half of Angular itself, so omitting it dramatically redu
|
|||
The AOT compiler detects and reports template binding errors during the build step
|
||||
before users can see them.
|
||||
|
||||
AOT编译器在构建过程中检测和报告模板绑定错误,避免用户遇到这些错误。
|
||||
AOT 编译器在构建过程中检测和报告模板绑定错误,避免用户遇到这些错误。
|
||||
|
||||
*Better security*
|
||||
|
||||
|
@ -115,8 +115,8 @@ AOT compiles HTML templates and components into JavaScript files long before the
|
|||
With no templates to read and no risky client-side HTML or JavaScript evaluation,
|
||||
there are fewer opportunities for injection attacks.
|
||||
|
||||
AOT编译远在HTML模版和组件被服务到客户端之前,将它们编译到JavaScript文件。
|
||||
没有模版可以阅读,没有高风险客户端HTML或JavaScript可利用,所以注入攻击的机会较少。
|
||||
AOT 编译远在 HTML 模版和组件被服务到客户端之前,将它们编译到 JavaScript 文件。
|
||||
没有模版可以阅读,没有高风险客户端 HTML 或 JavaScript 可利用,所以注入攻击的机会较少。
|
||||
|
||||
{@a compiler-options}
|
||||
|
||||
|
@ -370,11 +370,11 @@ The next sections elaborate on these points.
|
|||
|
||||
It helps to think of the AOT compiler as having two phases: a code analysis phase in which it simply records a representation of the source; and a code generation phase in which the compiler's `StaticReflector` handles the interpretation as well as places restrictions on what it interprets.
|
||||
|
||||
我们可以把 AOT 编译器看做两个阶段:在代码分析阶段,它只记录源代码,而在代码生成阶段,编译器的`StaticReflector`会解释这些结果,并为这些结果加上限制。
|
||||
我们可以把 AOT 编译器看做两个阶段:在代码分析阶段,它只记录源代码,而在代码生成阶段,编译器的 `StaticReflector` 会解释这些结果,并为这些结果加上限制。
|
||||
|
||||
## Phase 1: analysis
|
||||
|
||||
## 阶段1:分析
|
||||
## 阶段 1:分析
|
||||
|
||||
The TypeScript compiler does some of the analytic work of the first phase. It emits the `.d.ts` _type definition files_ with type information that the AOT compiler needs to generate application code.
|
||||
|
||||
|
@ -382,11 +382,11 @@ TypeScript 编译器会做一些初步的分析工作,它会生成**类型定
|
|||
|
||||
At the same time, the AOT **_collector_** analyzes the metadata recorded in the Angular decorators and outputs metadata information in **`.metadata.json`** files, one per `.d.ts` file.
|
||||
|
||||
同时,AOT **收集器(collector)** 会记录 Angular 装饰器中的元数据,并把它们输出到**`.metadata.json`**文件中,和每个`.d.ts`文件相对应。
|
||||
同时,AOT **收集器(collector)** 会记录 Angular 装饰器中的元数据,并把它们输出到**`.metadata.json`**文件中,和每个 `.d.ts` 文件相对应。
|
||||
|
||||
You can think of `.metadata.json` as a diagram of the overall structure of a decorator's metadata, represented as an [abstract syntax tree (AST)](https://en.wikipedia.org/wiki/Abstract_syntax_tree).
|
||||
|
||||
我们可以把`.metadata.json`文件看做一个包括全部装饰器的元数据的全景图,就像[抽象语法树 (AST) ](https://en.wikipedia.org/wiki/Abstract_syntax_tree)一样。
|
||||
我们可以把 `.metadata.json` 文件看做一个包括全部装饰器的元数据的全景图,就像[抽象语法树 (AST) ](https://en.wikipedia.org/wiki/Abstract_syntax_tree)一样。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
|
@ -430,13 +430,13 @@ Parentheses | `(a + b)`
|
|||
If an expression uses unsupported syntax, the _collector_ writes an error node to the `.metadata.json` file. The compiler later reports the error if it needs that
|
||||
piece of metadata to generate the application code.
|
||||
|
||||
如果表达式使用了不支持的语法,**收集器**就会往`.metadata.json`文件中写入一个错误节点。稍后,如果编译器用到元数据中的这部分内容来生成应用代码,它就会报告这个错误。
|
||||
如果表达式使用了不支持的语法,**收集器**就会往 `.metadata.json` 文件中写入一个错误节点。稍后,如果编译器用到元数据中的这部分内容来生成应用代码,它就会报告这个错误。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
If you want `ngc` to report syntax errors immediately rather than produce a `.metadata.json` file with errors, set the `strictMetadataEmit` option in `tsconfig`.
|
||||
|
||||
如果你希望`ngc`立即汇报这些语法错误,而不要生成带有错误信息的`.metadata.json`文件,可以到`tsconfig`中设置 `strictMetadataEmit` 选项。
|
||||
如果你希望 `ngc` 立即汇报这些语法错误,而不要生成带有错误信息的 `.metadata.json` 文件,可以到 `tsconfig` 中设置 `strictMetadataEmit` 选项。
|
||||
|
||||
```
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ NgModules 很重要。这里只是简单介绍,在 [NgModules](guide/ngmodules
|
|||
Every Angular app has at least one NgModule class, [the _root module_](guide/bootstrapping "Bootstrapping"),
|
||||
conventionally named `AppModule`.
|
||||
|
||||
每个 Angular 应用至少有一个模块([_根模块_](guide/bootstrapping "引导启动")),习惯上命名为`AppModule`。
|
||||
每个 Angular 应用至少有一个模块([_根模块_](guide/bootstrapping "引导启动")),习惯上命名为 `AppModule`。
|
||||
|
||||
While the _root module_ may be the only module in a small application, most apps have many more
|
||||
_feature modules_, each a cohesive block of code dedicated to an application domain,
|
||||
|
@ -74,7 +74,7 @@ _根模块_在一些小型应用中可能是唯一的模块,大多数应用会
|
|||
|
||||
An NgModule, whether a _root_ or _feature_, is a class with an `@NgModule` decorator.
|
||||
|
||||
Angular 模块(无论是_根模块_还是_特性模块_)都是一个带有`@NgModule`装饰器的类。
|
||||
Angular 模块(无论是_根模块_还是_特性模块_)都是一个带有 `@NgModule` 装饰器的类。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
|
@ -93,7 +93,7 @@ Angular 有很多装饰器,它们负责把元数据附加到类上,以了解
|
|||
`NgModule` is a decorator function that takes a single metadata object whose properties describe the module.
|
||||
The most important properties are:
|
||||
|
||||
`NgModule`是一个装饰器函数,它接收一个用来描述模块属性的元数据对象。其中最重要的属性是:
|
||||
`NgModule` 是一个装饰器函数,它接收一个用来描述模块属性的元数据对象。其中最重要的属性是:
|
||||
|
||||
* `declarations` - the _view classes_ that belong to this module.
|
||||
Angular has three kinds of view classes: [components](guide/architecture#components), [directives](guide/architecture#directives), and [pipes](guide/pipes).
|
||||
|
@ -116,7 +116,7 @@ the global collection of services; they become accessible in all parts of the ap
|
|||
* `bootstrap` - the main application view, called the _root component_,
|
||||
that hosts all other app views. Only the _root module_ should set this `bootstrap` property.
|
||||
|
||||
`bootstrap` - 指定应用的主视图(称为_根组件_),它是所有其它视图的宿主。只有_根模块_才能设置`bootstrap`属性。
|
||||
`bootstrap` - 指定应用的主视图(称为_根组件_),它是所有其它视图的宿主。只有_根模块_才能设置 `bootstrap` 属性。
|
||||
|
||||
Here's a simple root module:
|
||||
|
||||
|
@ -128,7 +128,7 @@ Here's a simple root module:
|
|||
|
||||
The `export` of `AppComponent` is just to show how to use the `exports` array to export a component; it isn't actually necessary in this example. A root module has no reason to _export_ anything because other components don't need to _import_ the root module.
|
||||
|
||||
`AppComponent`的`export`语句只是用于演示如何导出的,它在这个例子中并不是必须的。根模块不需要_导出_任何东西,因为其它组件不需要导入根模块。
|
||||
`AppComponent` 的 `export` 语句只是用于演示如何导出的,它在这个例子中并不是必须的。根模块不需要_导出_任何东西,因为其它组件不需要导入根模块。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -136,7 +136,7 @@ Launch an application by _bootstrapping_ its root module.
|
|||
During development you're likely to bootstrap the `AppModule` in a `main.ts` file like this one.
|
||||
|
||||
我们通过_引导_根模块来启动应用。
|
||||
在开发期间,你通常在一个`main.ts`文件中引导`AppModule`,就像这样:
|
||||
在开发期间,你通常在一个 `main.ts` 文件中引导 `AppModule`,就像这样:
|
||||
|
||||
<code-example path="architecture/src/main.ts" title="src/main.ts" linenums="false"></code-example>
|
||||
|
||||
|
@ -146,7 +146,7 @@ During development you're likely to bootstrap the `AppModule` in a `main.ts` fil
|
|||
|
||||
The NgModule — a class decorated with `@NgModule` — is a fundamental feature of Angular.
|
||||
|
||||
NgModule(一个带`@NgModule`装饰器的类)是 Angular 的基础特性之一。
|
||||
NgModule(一个带 `@NgModule` 装饰器的类)是 Angular 的基础特性之一。
|
||||
|
||||
JavaScript also has its own module system for managing collections of JavaScript objects.
|
||||
It's completely different and unrelated to the NgModule system.
|
||||
|
@ -159,7 +159,7 @@ The module declares some objects to be public by marking them with the `export`
|
|||
Other JavaScript modules use *import statements* to access public objects from other modules.
|
||||
|
||||
JavaScript 中,每个_文件_是一个模块,文件中定义的所有对象都从属于那个模块。
|
||||
通过`export`关键字,模块可以把它的某些对象声明为公共的。
|
||||
通过 `export` 关键字,模块可以把它的某些对象声明为公共的。
|
||||
其它 JavaScript 模块可以使用*import 语句*来访问这些公共对象。
|
||||
|
||||
<code-example path="architecture/src/app/app.module.ts" region="imports" linenums="false"></code-example>
|
||||
|
@ -190,17 +190,17 @@ Angular 提供了一组 JavaScript 模块。可以把它们看做库模块。
|
|||
|
||||
Each Angular library name begins with the `@angular` prefix.
|
||||
|
||||
每个 Angular 库的名字都带有`@angular`前缀。
|
||||
每个 Angular 库的名字都带有 `@angular` 前缀。
|
||||
|
||||
You install them with the **npm** package manager and import parts of them with JavaScript `import` statements.
|
||||
|
||||
用 **npm** 包管理工具安装它们,用 JavaScript 的`import`语句导入其中某些部件。
|
||||
用 **npm** 包管理工具安装它们,用 JavaScript 的 `import` 语句导入其中某些部件。
|
||||
|
||||
<br class="clear">
|
||||
|
||||
For example, import Angular's `Component` decorator from the `@angular/core` library like this:
|
||||
|
||||
例如,象下面这样,从`@angular/core`库中导入`Component`装饰器:
|
||||
例如,象下面这样,从 `@angular/core` 库中导入 `Component` 装饰器:
|
||||
|
||||
<code-example path="architecture/src/app/app.component.ts" region="import" linenums="false"></code-example>
|
||||
|
||||
|
@ -212,7 +212,7 @@ You also import NgModules from Angular _libraries_ using JavaScript import state
|
|||
|
||||
In the example of the simple root module above, the application module needs material from within that `BrowserModule`. To access that material, add it to the `@NgModule` metadata `imports` like this.
|
||||
|
||||
在上面那个简单的根模块的例子中,应用模块需要`BrowserModule`的某些素材。要访问这些素材,就得把它加入`@NgModule`元数据的`imports`中,就像这样:
|
||||
在上面那个简单的根模块的例子中,应用模块需要 `BrowserModule` 的某些素材。要访问这些素材,就得把它加入 `@NgModule` 元数据的 `imports` 中,就像这样:
|
||||
|
||||
<code-example path="architecture/src/app/mini-app.ts" region="ngmodule-imports" linenums="false"></code-example>
|
||||
|
||||
|
@ -273,8 +273,8 @@ For example, this `HeroListComponent` has a `heroes` property that returns an ar
|
|||
that it acquires from a service.
|
||||
`HeroListComponent` also has a `selectHero()` method that sets a `selectedHero` property when the user clicks to choose a hero from that list.
|
||||
|
||||
例如,`HeroListComponent`有一个`heroes`属性,它返回一个英雄数组,这个数组从一个服务获得。
|
||||
`HeroListComponent`还有一个当用户从列表中点选一个英雄时设置`selectedHero`属性的`selectHero()`方法。
|
||||
例如,`HeroListComponent` 有一个 `heroes` 属性,它返回一个英雄数组,这个数组从一个服务获得。
|
||||
`HeroListComponent` 还有一个当用户从列表中点选一个英雄时设置 `selectedHero` 属性的 `selectHero()` 方法。
|
||||
|
||||
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (class)" region="class"></code-example>
|
||||
|
||||
|
@ -282,7 +282,7 @@ Angular creates, updates, and destroys components as the user moves through the
|
|||
Your app can take action at each moment in this lifecycle through optional [lifecycle hooks](guide/lifecycle-hooks), like `ngOnInit()` declared above.
|
||||
|
||||
当用户在这个应用中漫游时, Angular 会创建、更新和销毁组件。
|
||||
应用可以通过[生命周期钩子](guide/lifecycle-hooks)在组件生命周期的各个时间点上插入自己的操作,例如上面声明的`ngOnInit()`。
|
||||
应用可以通过[生命周期钩子](guide/lifecycle-hooks)在组件生命周期的各个时间点上插入自己的操作,例如上面声明的 `ngOnInit()`。
|
||||
|
||||
<hr/>
|
||||
|
||||
|
@ -300,33 +300,33 @@ that tells Angular how to render the component.
|
|||
A template looks like regular HTML, except for a few differences. Here is a
|
||||
template for our `HeroListComponent`:
|
||||
|
||||
多数情况下,模板看起来很像标准 HTML,当然也有一点不同的地方。下面是`HeroListComponent`组件的一个模板:
|
||||
多数情况下,模板看起来很像标准 HTML,当然也有一点不同的地方。下面是 `HeroListComponent` 组件的一个模板:
|
||||
|
||||
<code-example path="architecture/src/app/hero-list.component.html" title="src/app/hero-list.component.html"></code-example>
|
||||
|
||||
Although this template uses typical HTML elements like `<h2>` and `<p>`, it also has some differences. Code like `*ngFor`, `{{hero.name}}`, `(click)`, `[hero]`, and `<app-hero-detail>` uses Angular's [template syntax](guide/template-syntax).
|
||||
|
||||
模板除了可以使用像`<h2>`和`<p>`这样的典型的 HTML 元素,还能使用其它元素。
|
||||
例如,像`*ngFor`、`{{hero.name}}`、`(click)`、`[hero]`和`<app-hero-detail>`这样的代码使用了 Angular 的[模板语法](guide/template-syntax)。
|
||||
模板除了可以使用像 `<h2>` 和 `<p>` 这样的典型的 HTML 元素,还能使用其它元素。
|
||||
例如,像 `*ngFor`、`{{hero.name}}`、`(click)`、`[hero]` 和 `<app-hero-detail>` 这样的代码使用了 Angular 的[模板语法](guide/template-syntax)。
|
||||
|
||||
In the last line of the template, the `<app-hero-detail>` tag is a custom element that represents a new component, `HeroDetailComponent`.
|
||||
|
||||
在模板的最后一行,`<app-hero-detail>`标签就是一个用来表示新组件`HeroDetailComponent`的自定义元素。
|
||||
在模板的最后一行,`<app-hero-detail>` 标签就是一个用来表示新组件 `HeroDetailComponent` 的自定义元素。
|
||||
|
||||
The `HeroDetailComponent` is a *different* component than the `HeroListComponent` you've been reviewing.
|
||||
The `HeroDetailComponent` (code not shown) presents facts about a particular hero, the
|
||||
hero that the user selects from the list presented by the `HeroListComponent`.
|
||||
The `HeroDetailComponent` is a **child** of the `HeroListComponent`.
|
||||
|
||||
`HeroDetailComponent`跟以前见到过的`HeroListComponent`是*不同*的组件。
|
||||
`HeroDetailComponent`(代码未显示)用于展现一个特定英雄的情况,这个英雄是用户从`HeroListComponent`列表中选择的。
|
||||
`HeroDetailComponent`是`HeroListComponent`的*子组件*。
|
||||
`HeroDetailComponent` 跟以前见到过的 `HeroListComponent` 是*不同*的组件。
|
||||
`HeroDetailComponent`(代码未显示)用于展现一个特定英雄的情况,这个英雄是用户从 `HeroListComponent` 列表中选择的。
|
||||
`HeroDetailComponent` 是 `HeroListComponent` 的*子组件*。
|
||||
|
||||
<img src="generated/images/guide/architecture/component-tree.png" alt="Metadata" class="left">
|
||||
|
||||
Notice how `<app-hero-detail>` rests comfortably among native HTML elements. Custom components mix seamlessly with native HTML in the same layouts.
|
||||
|
||||
注意到了吗?`<app-hero-detail>`舒适地躺在原生 HTML 元素之间。
|
||||
注意到了吗?`<app-hero-detail>` 舒适地躺在原生 HTML 元素之间。
|
||||
自定义组件和原生 HTML 在同一布局中融合得天衣无缝。
|
||||
|
||||
<hr class="clear"/>
|
||||
|
@ -346,46 +346,46 @@ Metadata tells Angular how to process a class.
|
|||
[Looking back at the code](guide/architecture#component-code) for `HeroListComponent`, you can see that it's just a class.
|
||||
There is no evidence of a framework, no "Angular" in it at all.
|
||||
|
||||
[回头看看](guide/architecture#component-code)`HeroListComponent`就会明白:它只是一个类。
|
||||
[回头看看](guide/architecture#component-code)`HeroListComponent` 就会明白:它只是一个类。
|
||||
一点框架的痕迹也没有,里面完全没有出现 "Angular" 的字样。
|
||||
|
||||
In fact, `HeroListComponent` really is *just a class*. It's not a component until you *tell Angular about it*.
|
||||
|
||||
实际上,`HeroListComponent`真的*只是一个类*。直到我们*告诉 Angular* 它是一个组件。
|
||||
实际上,`HeroListComponent` 真的*只是一个类*。直到我们*告诉 Angular* 它是一个组件。
|
||||
|
||||
To tell Angular that `HeroListComponent` is a component, attach **metadata** to the class.
|
||||
|
||||
要告诉 Angular `HeroListComponent`是个组件,只要把**元数据**附加到这个类。
|
||||
要告诉 Angular `HeroListComponent` 是个组件,只要把**元数据**附加到这个类。
|
||||
|
||||
In TypeScript, you attach metadata by using a **decorator**.
|
||||
Here's some metadata for `HeroListComponent`:
|
||||
|
||||
在TypeScript中,我们用**装饰器 (decorator) **来附加元数据。
|
||||
下面就是`HeroListComponent`的一些元数据。
|
||||
在 TypeScript 中,我们用**装饰器 (decorator) **来附加元数据。
|
||||
下面就是 `HeroListComponent` 的一些元数据。
|
||||
|
||||
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (metadata)" region="metadata"></code-example>
|
||||
|
||||
Here is the `@Component` decorator, which identifies the class
|
||||
immediately below it as a component class.
|
||||
|
||||
这里看到`@Component`装饰器,它把紧随其后的类标记成了组件类。
|
||||
这里看到 `@Component` 装饰器,它把紧随其后的类标记成了组件类。
|
||||
|
||||
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 are a few of the most useful `@Component` configuration options:
|
||||
|
||||
`@Component`的配置项包括:
|
||||
`@Component` 的配置项包括:
|
||||
|
||||
* `selector`: CSS selector that tells Angular to create and insert an instance of this component
|
||||
where it finds a `<app-hero-list>` tag in *parent* HTML.
|
||||
For example, if an app's HTML contains `<app-hero-list></app-hero-list>`, then
|
||||
Angular inserts an instance of the `HeroListComponent` view between those tags.
|
||||
|
||||
`selector`: CSS 选择器,它告诉 Angular 在*父级* HTML 中查找`<app-hero-list>`标签,创建并插入该组件。
|
||||
例如,如果应用的 HTML 包含`<app-hero-list></app-hero-list>`, Angular 就会把`HeroListComponent`的一个实例插入到这个标签中。
|
||||
`selector`: CSS 选择器,它告诉 Angular 在*父级* HTML 中查找 `<app-hero-list>` 标签,创建并插入该组件。
|
||||
例如,如果应用的 HTML 包含 `<app-hero-list></app-hero-list>`, Angular 就会把 `HeroListComponent` 的一个实例插入到这个标签中。
|
||||
|
||||
* `templateUrl`: module-relative address of this component's HTML template, shown [above](guide/architecture#templates).
|
||||
|
||||
|
@ -396,13 +396,13 @@ This is one way to tell Angular that the component's constructor requires a `Her
|
|||
so it can get the list of heroes to display.
|
||||
|
||||
`providers` - 组件所需服务的*依赖注入提供商*数组。
|
||||
这是在告诉 Angular:该组件的构造函数需要一个`HeroService`服务,这样组件就可以从服务中获得英雄数据。
|
||||
这是在告诉 Angular:该组件的构造函数需要一个 `HeroService` 服务,这样组件就可以从服务中获得英雄数据。
|
||||
|
||||
<img src="generated/images/guide/architecture/template-metadata-component.png" alt="Metadata" class="left">
|
||||
|
||||
The metadata in the `@Component` tells Angular where to get the major building blocks you specify for the component.
|
||||
|
||||
`@Component`里面的元数据会告诉 Angular 从哪里获取你为组件指定的主要的构建块。
|
||||
`@Component` 里面的元数据会告诉 Angular 从哪里获取你为组件指定的主要的构建块。
|
||||
|
||||
The template, metadata, and component together describe a view.
|
||||
|
||||
|
@ -412,7 +412,7 @@ Apply other metadata decorators in a similar fashion to guide Angular behavior.
|
|||
`@Injectable`, `@Input`, and `@Output` are a few of the more popular decorators.
|
||||
|
||||
其它元数据装饰器用类似的方式来指导 Angular 的行为。
|
||||
例如`@Injectable`、`@Input`和`@Output`等是一些最常用的装饰器。
|
||||
例如 `@Injectable`、`@Input` 和 `@Output` 等是一些最常用的装饰器。
|
||||
|
||||
<br class="clear">
|
||||
|
||||
|
@ -458,23 +458,23 @@ The `HeroListComponent` [example](guide/architecture#templates) template has thr
|
|||
* The `{{hero.name}}` [*interpolation*](guide/displaying-data#interpolation)
|
||||
displays the component's `hero.name` property value within the `<li>` element.
|
||||
|
||||
`{{hero.name}}`[*插值表达式*](guide/displaying-data#interpolation)在`<li>`标签中显示组件的`hero.name`属性的值。
|
||||
`{{hero.name}}`[*插值表达式*](guide/displaying-data#interpolation)在 `<li>` 标签中显示组件的 `hero.name` 属性的值。
|
||||
|
||||
* The `[hero]` [*property binding*](guide/template-syntax#property-binding) passes the value of `selectedHero` from
|
||||
the parent `HeroListComponent` to the `hero` property of the child `HeroDetailComponent`.
|
||||
|
||||
`[hero]`[*属性绑定*](guide/template-syntax#property-binding)把父组件`HeroListComponent`的`selectedHero`的值传到子组件`HeroDetailComponent`的`hero`属性中。
|
||||
`[hero]`[*属性绑定*](guide/template-syntax#property-binding)把父组件 `HeroListComponent` 的 `selectedHero` 的值传到子组件 `HeroDetailComponent` 的 `hero` 属性中。
|
||||
|
||||
* The `(click)` [*event binding*](guide/user-input#click) calls the component's `selectHero` method when the user clicks a hero's name.
|
||||
|
||||
`(click)` [*事件绑定*](guide/user-input#click)在用户点击英雄的名字时调用组件的`selectHero`方法。
|
||||
`(click)` [*事件绑定*](guide/user-input#click)在用户点击英雄的名字时调用组件的 `selectHero` 方法。
|
||||
|
||||
**Two-way data binding** is an important fourth form
|
||||
that combines property and event binding in a single notation, using the `ngModel` directive.
|
||||
Here's an example from the `HeroDetailComponent` template:
|
||||
|
||||
**双向数据绑定**是重要的第四种绑定形式,它使用`ngModel`指令组合了属性绑定和事件绑定的功能。
|
||||
下面是`HeroDetailComponent`模板的范例:
|
||||
**双向数据绑定**是重要的第四种绑定形式,它使用 `ngModel` 指令组合了属性绑定和事件绑定的功能。
|
||||
下面是 `HeroDetailComponent` 模板的范例:
|
||||
|
||||
<code-example path="architecture/src/app/hero-detail.component.html" linenums="false" title="src/app/hero-detail.component.html (ngModel)" region="ngModel"></code-example>
|
||||
|
||||
|
@ -522,7 +522,7 @@ A directive is a class with a `@Directive` decorator.
|
|||
A component is a *directive-with-a-template*;
|
||||
a `@Component` decorator is actually a `@Directive` decorator extended with template-oriented features.
|
||||
|
||||
组件是一个*带模板的指令*;`@Component`装饰器实际上就是一个`@Directive`装饰器,只是扩展了一些面向模板的特性。
|
||||
组件是一个*带模板的指令*;`@Component` 装饰器实际上就是一个 `@Directive` 装饰器,只是扩展了一些面向模板的特性。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
|
@ -555,11 +555,11 @@ The [example template](guide/architecture#templates) uses two built-in structura
|
|||
|
||||
* [`*ngFor`](guide/displaying-data#ngFor) tells Angular to stamp out one `<li>` per hero in the `heroes` list.
|
||||
|
||||
[`*ngFor`](guide/displaying-data#ngFor)告诉 Angular 为`heroes`列表中的每个英雄生成一个`<li>`标签。
|
||||
[`*ngFor`](guide/displaying-data#ngFor)告诉 Angular 为 `heroes` 列表中的每个英雄生成一个 `<li>` 标签。
|
||||
|
||||
* [`*ngIf`](guide/displaying-data#ngIf) includes the `HeroDetail` component only if a selected hero exists.
|
||||
|
||||
[`*ngIf`](guide/displaying-data#ngIf)表示只有在选择的英雄存在时,才会包含`HeroDetail`组件。
|
||||
[`*ngIf`](guide/displaying-data#ngIf)表示只有在选择的英雄存在时,才会包含 `HeroDetail` 组件。
|
||||
|
||||
**Attribute** directives alter the appearance or behavior of an existing element.
|
||||
In templates they look like regular HTML attributes, hence the name.
|
||||
|
@ -572,8 +572,8 @@ an example of an attribute directive. `ngModel` modifies the behavior of
|
|||
an existing element (typically an `<input>`)
|
||||
by setting its display value property and responding to change events.
|
||||
|
||||
`ngModel`指令就是属性型指令的一个例子,它实现了双向数据绑定。
|
||||
`ngModel`修改现有元素(一般是`<input>`)的行为:设置其显示属性值,并响应 change 事件。
|
||||
`ngModel` 指令就是属性型指令的一个例子,它实现了双向数据绑定。
|
||||
`ngModel` 修改现有元素(一般是 `<input>`)的行为:设置其显示属性值,并响应 change 事件。
|
||||
|
||||
<code-example path="architecture/src/app/hero-detail.component.html" linenums="false" title="src/app/hero-detail.component.html (ngModel)" region="ngModel"></code-example>
|
||||
|
||||
|
@ -588,7 +588,7 @@ Angular 还有少量指令,它们或者修改结构布局(例如 [ngSwitch](
|
|||
Of course, you can also write your own directives. Components such as
|
||||
`HeroListComponent` are one kind of custom directive.
|
||||
|
||||
当然,我们也能编写自己的指令。像`HeroListComponent`这样的组件就是一种自定义指令。
|
||||
当然,我们也能编写自己的指令。像 `HeroListComponent` 这样的组件就是一种自定义指令。
|
||||
|
||||
<!-- PENDING: link to where to learn more about other kinds! -->
|
||||
|
||||
|
@ -655,8 +655,8 @@ Here's an example of a service class that logs to the browser console:
|
|||
Here's a `HeroService` that uses a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) to fetch heroes.
|
||||
The `HeroService` depends on the `Logger` service and another `BackendService` that handles the server communication grunt work.
|
||||
|
||||
下面是`HeroService`类,用于获取英雄数据,并通过一个已解析的[承诺 (Promise)](http://exploringjs.com/es6/ch_promises.html) 返回它们。
|
||||
`HeroService`还依赖于`Logger`服务和另一个用于处理服务器通讯的`BackendService`服务。
|
||||
下面是 `HeroService` 类,用于获取英雄数据,并通过一个已解析的[承诺 (Promise)](http://exploringjs.com/es6/ch_promises.html) 返回它们。
|
||||
`HeroService` 还依赖于 `Logger` 服务和另一个用于处理服务器通讯的 `BackendService` 服务。
|
||||
|
||||
<code-example path="architecture/src/app/hero.service.ts" linenums="false" title="src/app/hero.service.ts (class)" region="class"></code-example>
|
||||
|
||||
|
@ -711,7 +711,7 @@ Angular can tell which services a component needs by looking at the types of its
|
|||
For example, the constructor of your `HeroListComponent` needs a `HeroService`:
|
||||
|
||||
Angular 通过查看构造函数的参数类型得知组件需要哪些服务。
|
||||
例如,`HeroListComponent`组件的构造函数需要一个`HeroService`服务:
|
||||
例如,`HeroListComponent` 组件的构造函数需要一个 `HeroService` 服务:
|
||||
|
||||
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (constructor)" region="ctor"></code-example>
|
||||
|
||||
|
@ -734,7 +734,7 @@ This is *dependency injection*.
|
|||
|
||||
The process of `HeroService` injection looks a bit like this:
|
||||
|
||||
`HeroService`注入的过程差不多是这样的:
|
||||
`HeroService` 注入的过程差不多是这样的:
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/architecture/injector-injects.png" alt="Service">
|
||||
|
@ -742,13 +742,13 @@ The process of `HeroService` injection looks a bit like this:
|
|||
|
||||
If the injector doesn't have a `HeroService`, how does it know how to make one?
|
||||
|
||||
如果注入器还没有`HeroService`,它怎么知道该如何创建一个呢?
|
||||
如果注入器还没有 `HeroService`,它怎么知道该如何创建一个呢?
|
||||
|
||||
In brief, you 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.
|
||||
|
||||
简单点说,我们必须先用注入器(injector)为`HeroService`注册一个**提供商(provider)**。
|
||||
提供商用来创建或返回服务,通常就是这个服务类本身(相当于`new HeroService()`)。
|
||||
简单点说,我们必须先用注入器(injector)为 `HeroService` 注册一个**提供商(provider)**。
|
||||
提供商用来创建或返回服务,通常就是这个服务类本身(相当于 `new HeroService()`)。
|
||||
|
||||
You can register providers in modules or in components.
|
||||
|
||||
|
@ -763,7 +763,7 @@ the same instance of a service is available everywhere.
|
|||
|
||||
Alternatively, register at a component level in the `providers` property of the `@Component` metadata:
|
||||
|
||||
或者,也可以在`@Component`元数据中的`providers`属性中把它注册在组件层:
|
||||
或者,也可以在 `@Component` 元数据中的 `providers` 属性中把它注册在组件层:
|
||||
|
||||
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (component providers)" region="providers"></code-example>
|
||||
|
||||
|
@ -896,11 +896,11 @@ by implementing the lifecycle hook interfaces.
|
|||
>
|
||||
> It displays a price of 42.33 as `$42.33`.
|
||||
|
||||
> [**管道**](guide/pipes):在模板中使用管道转换成用于显示的值,以增强用户体验。例如,`currency`管道表达式:
|
||||
> [**管道**](guide/pipes):在模板中使用管道转换成用于显示的值,以增强用户体验。例如,`currency` 管道表达式:
|
||||
>
|
||||
> > `price | currency:'USD':true`
|
||||
>
|
||||
> 它把价格“42.33”显示为`$42.33`。
|
||||
> 它把价格“42.33”显示为 `$42.33`。
|
||||
|
||||
> [**Router**](guide/router): Navigate from page to page within the client
|
||||
application and never leave the browser.
|
||||
|
|
|
@ -61,7 +61,7 @@ An attribute directive minimally requires building a controller class annotated
|
|||
the attribute.
|
||||
The controller class implements the desired directive behavior.
|
||||
|
||||
属性型指令至少需要一个带有`@Directive`装饰器的控制器类。该装饰器指定了一个用于标识属性的选择器。
|
||||
属性型指令至少需要一个带有 `@Directive` 装饰器的控制器类。该装饰器指定了一个用于标识属性的选择器。
|
||||
控制器类实现了指令需要的指令行为。
|
||||
|
||||
This page demonstrates building a simple _appHighlight_ attribute
|
||||
|
@ -90,25 +90,25 @@ ng generate directive highlight
|
|||
|
||||
The CLI creates `src/app/highlight.directive.ts`, a corresponding test file (`.../spec.ts`, and _declares_ the directive class in the root `AppModule`.
|
||||
|
||||
CLI 会创建`src/app/highlight.directive.ts`及相应的测试文件(`.../spec.ts`),并且在根模块`AppModule`中声明这个指令类。
|
||||
CLI 会创建 `src/app/highlight.directive.ts` 及相应的测试文件(`.../spec.ts`),并且在根模块 `AppModule` 中声明这个指令类。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
_Directives_ must be declared in [Angular Modules](guide/ngmodules) in the same manner as _components_.
|
||||
|
||||
和**组件**一样,这些**指令**也必须在[Angular模块](guide/ngmodules)中进行声明。
|
||||
和**组件**一样,这些**指令**也必须在[Angular 模块](guide/ngmodules)中进行声明。
|
||||
|
||||
</div >
|
||||
|
||||
The generated `src/app/highlight.directive.ts` is as follows:
|
||||
|
||||
生成的`src/app/highlight.directive.ts`文件如下:
|
||||
生成的 `src/app/highlight.directive.ts` 文件如下:
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.0.ts" title="src/app/highlight.directive.ts"></code-example>
|
||||
|
||||
The imported `Directive` symbol provides the Angular the `@Directive` decorator.
|
||||
|
||||
这里导入的`Directive`符号提供了 Angular 的 `@Directive` 装饰器。
|
||||
这里导入的 `Directive` 符号提供了 Angular 的 `@Directive` 装饰器。
|
||||
|
||||
The `@Directive` decorator's lone configuration property specifies the directive's
|
||||
[CSS attribute selector](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors), `[appHighlight]`.
|
||||
|
@ -144,8 +144,8 @@ The CLI added the `app` prefix for you.
|
|||
Make sure you do **not** prefix the `highlight` directive name with **`ng`** because
|
||||
that prefix is reserved for Angular and using it could cause bugs that are difficult to diagnose.
|
||||
|
||||
确认你**没有**给`highlight`指令添加**`ng`**前缀。
|
||||
那个前缀属于 Angular,使用它可能导致难以诊断的 bug。例如,这个简短的前缀`my`可以帮助你区分自定义指令。
|
||||
确认你**没有**给 `highlight` 指令添加**`ng`**前缀。
|
||||
那个前缀属于 Angular,使用它可能导致难以诊断的 bug。例如,这个简短的前缀 `my` 可以帮助你区分自定义指令。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -153,23 +153,23 @@ After the `@Directive` metadata comes the directive's controller class,
|
|||
called `HighlightDirective`, which contains the (currently empty) logic for the directive.
|
||||
Exporting `HighlightDirective` makes the directive accessible.
|
||||
|
||||
紧跟在`@Directive`元数据之后的就是该指令的控制器类,名叫`HighlightDirective`,它包含了该指令的逻辑(目前为空逻辑)。然后导出`HighlightDirective`,以便它能在别处访问到。
|
||||
紧跟在 `@Directive` 元数据之后的就是该指令的控制器类,名叫 `HighlightDirective`,它包含了该指令的逻辑(目前为空逻辑)。然后导出 `HighlightDirective`,以便它能在别处访问到。
|
||||
|
||||
Now edit the generated `src/app/highlight.directive.ts` to look as follows:
|
||||
|
||||
现在,把刚才生成的`src/app/highlight.directive.ts`编辑成这样:
|
||||
现在,把刚才生成的 `src/app/highlight.directive.ts` 编辑成这样:
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.1.ts" title="src/app/highlight.directive.ts"></code-example>
|
||||
|
||||
The `import` statement specifies an additional `ElementRef` symbol from the Angular `core` library:
|
||||
|
||||
`import`语句还从 Angular 的 `core` 库中导入了一个 `ElementRef` 符号。
|
||||
`import` 语句还从 Angular 的 `core` 库中导入了一个 `ElementRef` 符号。
|
||||
|
||||
You use the `ElementRef`in the directive's constructor
|
||||
to [inject](guide/dependency-injection) a reference to the host DOM element,
|
||||
the element to which you applied `appHighlight`.
|
||||
|
||||
我们可以在指令的构造函数中注入`ElementRef`,来引用宿主 DOM 元素,
|
||||
我们可以在指令的构造函数中注入 `ElementRef`,来引用宿主 DOM 元素,
|
||||
|
||||
`ElementRef` grants direct access to the host DOM element
|
||||
through its `nativeElement` property.
|
||||
|
@ -194,7 +194,7 @@ To use the new `HighlightDirective`, add a paragraph (`<p>`) element to the temp
|
|||
|
||||
Now run the application to see the `HighlightDirective` in action.
|
||||
|
||||
运行这个应用以查看`HighlightDirective`的实际效果。
|
||||
运行这个应用以查看 `HighlightDirective` 的实际效果。
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
|
||||
|
@ -207,9 +207,9 @@ It created an instance of the `HighlightDirective` class and
|
|||
injected a reference to the `<p>` element into the directive's constructor
|
||||
which sets the `<p>` element's background style to yellow.
|
||||
|
||||
总结:Angular 在**宿主**元素`<p>`上发现了一个`appHighlight`属性。
|
||||
然后它创建了一个`HighlightDirective`类的实例,并把所在元素的引用注入到了指令的构造函数中。
|
||||
在构造函数中,我们把`<p>`元素的背景设置为了黄色。
|
||||
总结:Angular 在**宿主**元素 `<p>` 上发现了一个 `appHighlight` 属性。
|
||||
然后它创建了一个 `HighlightDirective` 类的实例,并把所在元素的引用注入到了指令的构造函数中。
|
||||
在构造函数中,我们把 `<p>` 元素的背景设置为了黄色。
|
||||
|
||||
{@a respond-to-user}
|
||||
|
||||
|
@ -222,33 +222,33 @@ The directive could be more dynamic.
|
|||
It could detect when the user mouses into or out of the element
|
||||
and respond by setting or clearing the highlight color.
|
||||
|
||||
当前,`appHighlight`只是简单的设置元素的颜色。
|
||||
当前,`appHighlight` 只是简单的设置元素的颜色。
|
||||
这个指令应该在用户鼠标悬浮一个元素时,设置它的颜色。
|
||||
|
||||
Begin by adding `HostListener` to the list of imported symbols.
|
||||
|
||||
先把`HostListener`加进导入列表中,同时再添加`Input`符号,因为我们很快就要用到它。
|
||||
先把 `HostListener` 加进导入列表中,同时再添加 `Input` 符号,因为我们很快就要用到它。
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" title="src/app/highlight.directive.ts (imports)" region="imports"></code-example>
|
||||
|
||||
Then add two eventhandlers that respond when the mouse enters or leaves,
|
||||
each adorned by the `HostListener` decorator.
|
||||
|
||||
然后使用`HostListener`装饰器添加两个事件处理器,它们会在鼠标进入或离开时进行响应。
|
||||
然后使用 `HostListener` 装饰器添加两个事件处理器,它们会在鼠标进入或离开时进行响应。
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" title="src/app/highlight.directive.ts (mouse-methods)" region="mouse-methods"></code-example>
|
||||
|
||||
The `@HostListener` decorator lets you subscribe to events of the DOM
|
||||
element that hosts an attribute directive, the `<p>` in this case.
|
||||
|
||||
`@HostListener`装饰器引用属性型指令的宿主元素,在这个例子中就是`<p>`。
|
||||
`@HostListener` 装饰器引用属性型指令的宿主元素,在这个例子中就是 `<p>`。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
Of course you could reach into the DOM with standard JavaScript and attach event listeners manually.
|
||||
There are at least three problems with _that_ approach:
|
||||
|
||||
当然,你可以通过标准的JavaScript方式手动给宿主 DOM 元素附加一个事件监听器。
|
||||
当然,你可以通过标准的 JavaScript 方式手动给宿主 DOM 元素附加一个事件监听器。
|
||||
但这种方法至少有三个问题:
|
||||
|
||||
1. You have to write the listeners correctly.
|
||||
|
@ -267,7 +267,7 @@ There are at least three problems with _that_ approach:
|
|||
|
||||
The handlers delegate to a helper method that sets the color on the host DOM element, `el`.
|
||||
|
||||
这些处理器委托了一个辅助方法来为DOM元素(`el`)设置颜色。
|
||||
这些处理器委托了一个辅助方法来为 DOM 元素(`el`)设置颜色。
|
||||
|
||||
The helper method, `highlight`, was extracted from the constructor.
|
||||
The revised constructor simply declares the injected `el: ElementRef`.
|
||||
|
@ -286,7 +286,7 @@ Here's the updated directive in full:
|
|||
Run the app and confirm that the background color appears when
|
||||
the mouse hovers over the `p` and disappears as it moves out.
|
||||
|
||||
运行本应用并确认:当把鼠标移到`p`上的时候,背景色就出现了,而移开的时候,它消失了。
|
||||
运行本应用并确认:当把鼠标移到 `p` 上的时候,背景色就出现了,而移开的时候,它消失了。
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/attribute-directives/highlight-directive-anim.gif" alt="Second Highlight">
|
||||
|
@ -306,13 +306,13 @@ In this section, you give the developer the power to set the highlight color whi
|
|||
|
||||
Begin by adding `Input` to the list of symbols imported from `@angular/core`.
|
||||
|
||||
我们先从`@angular/core`中导入`Input`。
|
||||
我们先从 `@angular/core` 中导入 `Input`。
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.3.ts" linenums="false" title="src/app/highlight.directive.ts (imports)" region="imports"></code-example>
|
||||
|
||||
Add a `highlightColor` property to the directive class like this:
|
||||
|
||||
然后把`highlightColor`属性添加到指令类中,就像这样:
|
||||
然后把 `highlightColor` 属性添加到指令类中,就像这样:
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" title="src/app/highlight.directive.ts (highlightColor)" region="color"></code-example>
|
||||
|
||||
|
@ -324,23 +324,23 @@ Add a `highlightColor` property to the directive class like this:
|
|||
|
||||
Notice the `@Input` decorator. It adds metadata to the class that makes the directive's `highlightColor` property available for binding.
|
||||
|
||||
注意看`@Input`装饰器。它往类上添加了一些元数据,从而让该指令的`highlightColor`能用于绑定。
|
||||
注意看 `@Input` 装饰器。它往类上添加了一些元数据,从而让该指令的 `highlightColor` 能用于绑定。
|
||||
|
||||
It's called an *input* property because data flows from the binding expression _into_ the directive.
|
||||
Without that input metadata, Angular rejects the binding; see [below](guide/attribute-directives#why-input "Why add @Input?") for more about that.
|
||||
|
||||
它之所以称为*输入*属性,是因为数据流是从绑定表达式流向指令内部的。
|
||||
如果没有这个元数据,Angular就会拒绝绑定,参见[稍后](guide/attribute-directives#why-input "为什么要添加@Input?")了解更多。
|
||||
如果没有这个元数据,Angular 就会拒绝绑定,参见[稍后](guide/attribute-directives#why-input "为什么要添加@Input?")了解更多。
|
||||
|
||||
Try it by adding the following directive binding variations to the `AppComponent` template:
|
||||
|
||||
试试把下列指令绑定变量添加到`AppComponent`的模板中:
|
||||
试试把下列指令绑定变量添加到 `AppComponent` 的模板中:
|
||||
|
||||
<code-example path="attribute-directives/src/app/app.component.1.html" linenums="false" title="src/app/app.component.html (excerpt)" region="color-1"></code-example>
|
||||
|
||||
Add a `color` property to the `AppComponent`.
|
||||
|
||||
把`color`属性添加到`AppComponent`中:
|
||||
把 `color` 属性添加到 `AppComponent` 中:
|
||||
|
||||
<code-example path="attribute-directives/src/app/app.component.1.ts" linenums="false" title="src/app/app.component.ts (class)" region="class"></code-example>
|
||||
|
||||
|
@ -361,19 +361,19 @@ and sets the directive's highlight color with a property binding.
|
|||
You're re-using the directive's attribute selector (`[appHighlight]`) to do both jobs.
|
||||
That's a crisp, compact syntax.
|
||||
|
||||
`[appHighlight]`属性同时做了两件事:把这个高亮指令应用到了`<p>`元素上,并且通过属性绑定设置了该指令的高亮颜色。
|
||||
我们复用了该指令的属性选择器`[appHighlight]`来同时完成它们。
|
||||
`[appHighlight]` 属性同时做了两件事:把这个高亮指令应用到了 `<p>` 元素上,并且通过属性绑定设置了该指令的高亮颜色。
|
||||
我们复用了该指令的属性选择器 `[appHighlight]` 来同时完成它们。
|
||||
这是清爽、简约的语法。
|
||||
|
||||
You'll have to rename the directive's `highlightColor` property to `appHighlight` because that's now the color property binding name.
|
||||
|
||||
我们还要把该指令的`highlightColor`改名为`myHighlight`,因为它是颜色属性目前的绑定名。
|
||||
我们还要把该指令的 `highlightColor` 改名为 `myHighlight`,因为它是颜色属性目前的绑定名。
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" title="src/app/highlight.directive.ts (renamed to match directive selector)" region="color-2"></code-example>
|
||||
|
||||
This is disagreeable. The word, `appHighlight`, is a terrible property name and it doesn't convey the property's intent.
|
||||
|
||||
这可不好。因为`appHighlight`是一个糟糕的属性名,而且不能反映该属性的意图。
|
||||
这可不好。因为 `appHighlight` 是一个糟糕的属性名,而且不能反映该属性的意图。
|
||||
|
||||
{@a input-alias}
|
||||
|
||||
|
@ -387,14 +387,14 @@ Fortunately you can name the directive property whatever you want _and_ **_alias
|
|||
|
||||
Restore the original property name and specify the selector as the alias in the argument to `@Input`.
|
||||
|
||||
恢复原始属性名,并在`@Input`的参数中把选择器`myHighlight`指定为别名。
|
||||
恢复原始属性名,并在 `@Input` 的参数中把选择器 `myHighlight` 指定为别名。
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" title="src/app/highlight.directive.ts (color property with alias)" region="color"></code-example>
|
||||
|
||||
_Inside_ the directive the property is known as `highlightColor`.
|
||||
_Outside_ the directive, where you bind to it, it's known as `appHighlight`.
|
||||
|
||||
在指令内部,该属性叫`highlightColor`,在外部,当我们绑定到它时,它叫`appHighlight`。
|
||||
在指令内部,该属性叫 `highlightColor`,在外部,当我们绑定到它时,它叫 `appHighlight`。
|
||||
|
||||
You get the best of both worlds: the property name you want and the binding syntax you want:
|
||||
|
||||
|
@ -405,8 +405,8 @@ You get the best of both worlds: the property name you want and the binding synt
|
|||
Now that you're binding via the alias to the `highlightColor`, modify the `onMouseEnter()` method to use that property.
|
||||
If someone neglects to bind to `appHighlightColor`, highlight the host element in red:
|
||||
|
||||
现在,我们绑定到了`highlightColor`属性,并修改`onMouseEnter()`方法来使用它。
|
||||
如果有人忘了绑定到`appHighlightColor`,那就用红色进行高亮。
|
||||
现在,我们绑定到了 `highlightColor` 属性,并修改 `onMouseEnter()` 方法来使用它。
|
||||
如果有人忘了绑定到 `appHighlightColor`,那就用红色进行高亮。
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.3.ts" linenums="false" title="src/app/highlight.directive.ts (mouse enter)" region="mouse-enter"></code-example>
|
||||
|
||||
|
@ -425,17 +425,17 @@ In this section, you'll turn `AppComponent` into a harness that
|
|||
lets you pick the highlight color with a radio button and bind your color choice to the directive.
|
||||
|
||||
凭空想象该指令如何工作可不容易。
|
||||
在本节,我们将把`AppComponent`改成一个测试程序,它让你可以通过单选按钮来选取高亮颜色,并且把你选取的颜色绑定到指令中。
|
||||
在本节,我们将把 `AppComponent` 改成一个测试程序,它让你可以通过单选按钮来选取高亮颜色,并且把你选取的颜色绑定到指令中。
|
||||
|
||||
Update <code>app.component.html</code> as follows:
|
||||
|
||||
把`app.component.html`修改成这样:
|
||||
把 `app.component.html` 修改成这样:
|
||||
|
||||
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (v2)" region="v2"></code-example>
|
||||
|
||||
Revise the `AppComponent.color` so that it has no initial value.
|
||||
|
||||
修改`AppComponent.color`,让它不再有初始值。
|
||||
修改 `AppComponent.color`,让它不再有初始值。
|
||||
|
||||
<code-example path="attribute-directives/src/app/app.component.ts" linenums="false" title="src/app/app.component.ts (class)" region="class"></code-example>
|
||||
|
||||
|
@ -465,34 +465,34 @@ Let the template developer set the default color.
|
|||
|
||||
Add a second **input** property to `HighlightDirective` called `defaultColor`:
|
||||
|
||||
把第二个名叫`defaultColor`的**输入**属性添加到`HighlightDirective`中:
|
||||
把第二个名叫 `defaultColor` 的**输入**属性添加到 `HighlightDirective` 中:
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" title="src/app/highlight.directive.ts (defaultColor)" region="defaultColor"></code-example>
|
||||
|
||||
Revise the directive's `onMouseEnter` so that it first tries to highlight with the `highlightColor`,
|
||||
then with the `defaultColor`, and falls back to "red" if both properties are undefined.
|
||||
|
||||
修改该指令的`onMouseEnter`,让它首先尝试使用`highlightColor`进行高亮,然后用`defaultColor`,如果它们都没有指定,那就用红色作为后备。
|
||||
修改该指令的 `onMouseEnter`,让它首先尝试使用 `highlightColor` 进行高亮,然后用 `defaultColor`,如果它们都没有指定,那就用红色作为后备。
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" title="src/app/highlight.directive.ts (mouse-enter)" region="mouse-enter"></code-example>
|
||||
|
||||
How do you bind to a second property when you're already binding to the `appHighlight` attribute name?
|
||||
|
||||
当已经绑定过`appHighlight`属性时,要如何绑定到第二个属性呢?
|
||||
当已经绑定过 `appHighlight` 属性时,要如何绑定到第二个属性呢?
|
||||
|
||||
As with components, you can add as many directive property bindings as you need by stringing them along in the template.
|
||||
The developer should be able to write the following template HTML to both bind to the `AppComponent.color`
|
||||
and fall back to "violet" as the default color.
|
||||
|
||||
像组件一样,你也可以绑定到指令的很多属性,只要把它们依次写在模板中就行了。
|
||||
开发者可以绑定到`AppComponent.color`,并且用紫罗兰色作为默认颜色,代码如下:
|
||||
开发者可以绑定到 `AppComponent.color`,并且用紫罗兰色作为默认颜色,代码如下:
|
||||
|
||||
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (defaultColor)" region="defaultColor"></code-example>
|
||||
|
||||
Angular knows that the `defaultColor` binding belongs to the `HighlightDirective`
|
||||
because you made it _public_ with the `@Input` decorator.
|
||||
|
||||
Angular之所以知道`defaultColor`绑定属于`HighlightDirective`,是因为我们已经通过`@Input`装饰器把它设置成了*公共*属性。
|
||||
Angular 之所以知道 `defaultColor` 绑定属于 `HighlightDirective`,是因为我们已经通过 `@Input` 装饰器把它设置成了*公共*属性。
|
||||
|
||||
Here's how the harness should work when you're done coding.
|
||||
|
||||
|
@ -554,7 +554,7 @@ You can also experience and download the <live-example title="Attribute Directiv
|
|||
In this demo, the `highlightColor` property is an ***input*** property of
|
||||
the `HighlightDirective`. You've seen it applied without an alias:
|
||||
|
||||
在这个例子中`hightlightColor`是`HighlightDirective`的一个***输入型***属性。我们见过它没有用别名时的代码:
|
||||
在这个例子中 `hightlightColor` 是 `HighlightDirective` 的一个***输入型***属性。我们见过它没有用别名时的代码:
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" title="src/app/highlight.directive.ts (color)" region="color"></code-example>
|
||||
|
||||
|
@ -568,13 +568,13 @@ Either way, the `@Input` decorator tells Angular that this property is
|
|||
_public_ and available for binding by a parent component.
|
||||
Without `@Input`, Angular refuses to bind to the property.
|
||||
|
||||
无论哪种方式,`@Input`装饰器都告诉Angular,该属性是*公共的*,并且能被父组件绑定。
|
||||
如果没有`@Input`,Angular就会拒绝绑定到该属性。
|
||||
无论哪种方式,`@Input` 装饰器都告诉 Angular,该属性是*公共的*,并且能被父组件绑定。
|
||||
如果没有 `@Input`,Angular 就会拒绝绑定到该属性。
|
||||
|
||||
You've bound template HTML to component properties before and never used `@Input`.
|
||||
What's different?
|
||||
|
||||
但我们以前也曾经把模板HTML绑定到组件的属性,而且从来没有用过`@Input`。
|
||||
但我们以前也曾经把模板 HTML 绑定到组件的属性,而且从来没有用过 `@Input`。
|
||||
差异何在?
|
||||
|
||||
The difference is a matter of trust.
|
||||
|
@ -584,9 +584,9 @@ Therefore, the component's own template may bind to _any_ property of that compo
|
|||
with or without the `@Input` decorator.
|
||||
|
||||
差异在于信任度不同。
|
||||
Angular把组件的模板看做*从属于*该组件的。
|
||||
Angular 把组件的模板看做*从属于*该组件的。
|
||||
组件和它的模板默认会相互信任。
|
||||
这也就是意味着,组件自己的模板可以绑定到组件的*任意*属性,无论是否使用了`@Input`装饰器。
|
||||
这也就是意味着,组件自己的模板可以绑定到组件的*任意*属性,无论是否使用了 `@Input` 装饰器。
|
||||
|
||||
But a component or directive shouldn't blindly trust _other_ components and directives.
|
||||
The properties of a component or directive are hidden from binding by default.
|
||||
|
@ -596,23 +596,23 @@ Only then can it be bound by some other component or directive.
|
|||
|
||||
但组件或指令不应该盲目的信任其它组件或指令。
|
||||
因此组件或指令的属性默认是不能被绑定的。
|
||||
从Angular绑定机制的角度来看,它们是*私有*的,而当添加了`@Input`时,它们变成了*公共*的
|
||||
从 Angular 绑定机制的角度来看,它们是*私有*的,而当添加了 `@Input` 时,它们变成了*公共*的
|
||||
只有这样,它们才能被其它组件或属性绑定。
|
||||
|
||||
You can tell if `@Input` is needed by the position of the property name in a binding.
|
||||
|
||||
你可以根据属性名在绑定中出现的位置来判定是否要加`@Input`。
|
||||
你可以根据属性名在绑定中出现的位置来判定是否要加 `@Input`。
|
||||
|
||||
* When it appears in the template expression to the ***right*** of the equals (=),
|
||||
it belongs to the template's component and does not require the `@Input` decorator.
|
||||
|
||||
当它出现在等号***右侧***的模板表达式中时,它属于模板所在的组件,不需要`@Input`装饰器。
|
||||
当它出现在等号***右侧***的模板表达式中时,它属于模板所在的组件,不需要 `@Input` 装饰器。
|
||||
|
||||
* When it appears in **square brackets** ([ ]) to the **left** of the equals (=),
|
||||
the property belongs to some _other_ component or directive;
|
||||
that property must be adorned with the `@Input` decorator.
|
||||
|
||||
当它出现在等号**左边**的**方括号([ ])**中时,该属性属于*其它*组件或指令,它必须带有`@Input` 装饰器。
|
||||
当它出现在等号**左边**的**方括号([ ])**中时,该属性属于*其它*组件或指令,它必须带有 `@Input` 装饰器。
|
||||
|
||||
Now apply that reasoning to the following example:
|
||||
|
||||
|
@ -624,12 +624,12 @@ Now apply that reasoning to the following example:
|
|||
The template and its component trust each other.
|
||||
The `color` property doesn't require the `@Input` decorator.
|
||||
|
||||
`color`属性位于右侧的绑定表达式中,它属于模板所在的组件。
|
||||
该模板和组件相互信任。因此`color`不需要`@Input`装饰器。
|
||||
`color` 属性位于右侧的绑定表达式中,它属于模板所在的组件。
|
||||
该模板和组件相互信任。因此 `color` 不需要 `@Input` 装饰器。
|
||||
|
||||
* The `appHighlight` property on the left refers to an _aliased_ property of the `HighlightDirective`,
|
||||
not a property of the template's component. There are trust issues.
|
||||
Therefore, the directive property must carry the `@Input` decorator.
|
||||
|
||||
`appHighlight`属性位于左侧,它引用了`HighlightDirective`中一个*带别名的*属性,它不是模板所属组件的一部分,因此存在信任问题。
|
||||
所以,该属性必须带`@Input`装饰器。
|
||||
`appHighlight` 属性位于左侧,它引用了 `HighlightDirective` 中一个*带别名的*属性,它不是模板所属组件的一部分,因此存在信任问题。
|
||||
所以,该属性必须带 `@Input` 装饰器。
|
||||
|
|
|
@ -82,7 +82,7 @@ The `@NgModule` decorator identifies `AppModule` as an `NgModule` class.
|
|||
* **_bootstrap_**—the _root_ component that Angular creates and inserts
|
||||
into the `index.html` host web page.
|
||||
|
||||
**_bootstrap_** —— *根*组件,Angular 创建它并插入`index.html`宿主页面。
|
||||
**_bootstrap_** —— *根*组件,Angular 创建它并插入 `index.html` 宿主页面。
|
||||
|
||||
The default CLI application only has one component, `AppComponent`, so it
|
||||
is in both the `declarations` and the `bootstrap` arrays.
|
||||
|
@ -279,7 +279,7 @@ root module's `bootstrap` array.
|
|||
|
||||
## More about Angular Modules
|
||||
|
||||
## 关于Angular模块的更多知识
|
||||
## 关于 Angular 模块的更多知识
|
||||
|
||||
For more on NgModules you're likely to see frequently in apps,
|
||||
see [Frequently Used Modules](#).
|
||||
|
|
|
@ -224,7 +224,7 @@ This file incorporates the mandatory and many of the optional polyfills as JavaS
|
|||
|
||||
The npm packages for the _mandatory_ polyfills (such as `zone.js`) were installed automatically for you when you created your project and their corresponding `import` statements are ready to go. You probably won't touch these.
|
||||
|
||||
**强制性** 腻子脚本(如`zone.js`)的npm 包在创建项目时就已经自动安装了,相应的 `import` 语句也都加好了。我们一般不用动它们。
|
||||
**强制性** 腻子脚本(如 `zone.js`)的 npm 包在创建项目时就已经自动安装了,相应的 `import` 语句也都加好了。我们一般不用动它们。
|
||||
|
||||
But if you need an optional polyfill, you'll have to install its npm package.
|
||||
For example, [if you need the web animations polyfill](http://caniuse.com/#feat=web-animation), you could install it with `npm`, using the following command (or the `yarn` equivalent):
|
||||
|
@ -465,7 +465,7 @@ Here are the features which may require additional polyfills:
|
|||
<p>If AnimationBuilder is used then the polyfill will enable scrubbing
|
||||
support for IE/Edge and Safari (Chrome and Firefox support this natively).</p>
|
||||
|
||||
<p>如果使用了AnimationBuilder,那么腻子脚本将为 IE/Edge 和 Safari 启用擦除(scrubbing)支持(Chrome 和 Firefox 原生支持此特性)</p>
|
||||
<p>如果使用了 AnimationBuilder,那么腻子脚本将为 IE/Edge 和 Safari 启用擦除(scrubbing)支持(Chrome 和 Firefox 原生支持此特性)</p>
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -477,7 +477,7 @@ Here are the features which may require additional polyfills:
|
|||
|
||||
If you use the following deprecated i18n pipes:
|
||||
|
||||
如果你使用下列已废弃的i18n管道:
|
||||
如果你使用下列已废弃的 i18n 管道:
|
||||
|
||||
[date](api/common/DeprecatedDatePipe),
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
The Angular documentation is a living document with continuous improvements.
|
||||
This log calls attention to recent significant changes.
|
||||
|
||||
我们将持续不断的更新和改进Angular文档。本日志记录了近期最重要的变更。
|
||||
我们将持续不断的更新和改进 Angular 文档。本日志记录了近期最重要的变更。
|
||||
|
||||
## Updated to Angular 4.0. Documentation for Angular 2.x can be found at [v2.angular.io](https://v2.angular.io).
|
||||
|
||||
|
@ -13,19 +13,19 @@ This log calls attention to recent significant changes.
|
|||
|
||||
## All mention of moduleId removed. "Component relative paths" guide deleted (2017-03-13)
|
||||
|
||||
## 移除了所有的moduleId引用。移除了“组件相对路径” 的烹饪书。(2017-03-13)
|
||||
## 移除了所有的 moduleId 引用。移除了“组件相对路径” 的烹饪书。(2017-03-13)
|
||||
|
||||
We added a new SystemJS plugin (systemjs-angular-loader.js) to our recommended SystemJS configuration.
|
||||
This plugin dynamically converts "component-relative" paths in templateUrl and styleUrls to "absolute paths" for you.
|
||||
|
||||
我们往建议的SystemJS配置中新增了一个SystemJS插件 (systemjs-angular-loader.js) 。
|
||||
这个插件可以帮你把templateUrl和styleUrls中的组件相对路径动态转换为绝对路径。
|
||||
我们往建议的 SystemJS 配置中新增了一个 SystemJS 插件 (systemjs-angular-loader.js) 。
|
||||
这个插件可以帮你把 templateUrl 和 styleUrls 中的组件相对路径动态转换为绝对路径。
|
||||
|
||||
We strongly encourage you to only write component-relative paths.
|
||||
That is the only form of URL discussed in these docs. You no longer need to write @Component({ moduleId: module.id }), nor should you.
|
||||
|
||||
我们强烈建议你只写组件相对路径。
|
||||
这也是本文档中所使用的唯一形式。你不必再写`@Component({ moduleId: module.id })`,而且也不应该再这么写。
|
||||
这也是本文档中所使用的唯一形式。你不必再写 `@Component({ moduleId: module.id })`,而且也不应该再这么写。
|
||||
|
||||
## NEW: Downloadable examples for each guide (2017-02-28)
|
||||
|
||||
|
@ -47,20 +47,20 @@ Discusses `<ng-container>`.
|
|||
Revised samples are more clear and cover all topics discussed.
|
||||
|
||||
对[模板语法](guide/template-syntax) 和 [结构型指令](guide/structural-directives)这两篇指南做了大幅修改,来让它们更加清晰、准确,并符合当前的最佳实践。
|
||||
讨论了`<ng-container>`。
|
||||
讨论了 `<ng-container>`。
|
||||
修改了例子,来让它们更清晰,并且涵盖了所有讨论到的主题。
|
||||
|
||||
## NEW: Samples re-structured with `src/` folder (2017-02-02)
|
||||
|
||||
## 新增:调整了范例程序的结构,移到了`src/`文件夹 (2017-02-02)
|
||||
## 新增:调整了范例程序的结构,移到了 `src/` 文件夹 (2017-02-02)
|
||||
|
||||
All documentation samples have been realigned with the default folder structure of the Angular CLI.
|
||||
That's a step along the road to basing the sample in the Angular CLI.
|
||||
But it's also good in its own right.
|
||||
It helps clearly separate app code from setup and configuration files.
|
||||
|
||||
所有的文档范例都已经向Angular CLI的默认文件夹结构看齐了。
|
||||
这是把范例迁移到Angular CLI过程中的一步。
|
||||
所有的文档范例都已经向 Angular CLI 的默认文件夹结构看齐了。
|
||||
这是把范例迁移到 Angular CLI 过程中的一步。
|
||||
不过也不仅是为了迁移,它确实能帮我们把应用代码从环境代码和配置代码中分离出来。
|
||||
|
||||
All samples now have a `src/` folder at the project root.
|
||||
|
@ -69,9 +69,9 @@ Read about moving your existing project to this structure in
|
|||
<a href="https://github.com/angular/quickstart#updating-to-a-newer-version-of-the-quickstart-repo" target="Migrating samples/quickstart app to the src folder">
|
||||
the QuickStart repo update instructions</a>.
|
||||
|
||||
我们已经把所有范例改成了使用项目根目录下的`src/`文件夹。
|
||||
也就是把以前的`app/`文件夹移到了`src/`文件夹下面。
|
||||
要了解如何对你的现有项目进行这种迁移,请参阅<a href="https://github.com/angular/quickstart#updating-to-a-newer-version-of-the-quickstart-repo" target="_blank" target="把范例中的应用迁移到src文件夹">QuickStart中的迁移指南</a>。
|
||||
我们已经把所有范例改成了使用项目根目录下的 `src/` 文件夹。
|
||||
也就是把以前的 `app/` 文件夹移到了 `src/` 文件夹下面。
|
||||
要了解如何对你的现有项目进行这种迁移,请参阅<a href="https://github.com/angular/quickstart#updating-to-a-newer-version-of-the-quickstart-repo" target="_blank" target="把范例中的应用迁移到 src 文件夹">QuickStart 中的迁移指南</a>。
|
||||
|
||||
Notably:
|
||||
|
||||
|
@ -79,23 +79,23 @@ Notably:
|
|||
|
||||
* `app/main.ts` moved to `src/main.ts`.
|
||||
|
||||
把`app/main.ts`移到`src/main.ts`。
|
||||
把 `app/main.ts` 移到 `src/main.ts`。
|
||||
|
||||
* `app/` moved to `src/app/`.
|
||||
|
||||
把`app/`移到`src/app/`。
|
||||
把 `app/` 移到 `src/app/`。
|
||||
|
||||
* `index.html`, `styles.css` and `tsconfig.json` moved inside `src/`.
|
||||
|
||||
把`index.html`、`styles.css`和`tsconfig.json`移到`src/`中。
|
||||
把 `index.html`、`styles.css` 和 `tsconfig.json` 移到 `src/` 中。
|
||||
|
||||
* `systemjs.config.js` now imports `main.js` instead of `app`.
|
||||
|
||||
`systemjs.config.js`现在要导入`main.js`而不是`app`。
|
||||
`systemjs.config.js` 现在要导入 `main.js` 而不是 `app`。
|
||||
|
||||
* Added `lite-server` configuration (`bs-config.json`) to serve `src/`.
|
||||
|
||||
新增了一个`lite-server`配置(`bs-config.json`)以便在`src/`下启动开发服务器。
|
||||
新增了一个 `lite-server` 配置(`bs-config.json`)以便在 `src/` 下启动开发服务器。
|
||||
|
||||
## NEW: Reactive Forms guide (2017-01-31)
|
||||
|
||||
|
@ -131,7 +131,7 @@ It includes important advice on optimizing for production.
|
|||
Closes issue #3086.
|
||||
Revised samples are clearer and cover all topics discussed.
|
||||
|
||||
[多级依赖注入](guide/hierarchical-dependency-injection)做了显著修改。关闭了issue #3086。修改过的范例更加清晰,而且涵盖了讨论到的全部主题。
|
||||
[多级依赖注入](guide/hierarchical-dependency-injection)做了显著修改。关闭了 issue #3086。修改过的范例更加清晰,而且涵盖了讨论到的全部主题。
|
||||
|
||||
## Miscellaneous (2017-01-05)
|
||||
|
||||
|
@ -145,11 +145,11 @@ added (optional) instructions on how to remove _non-essential_ files.
|
|||
|
||||
* No longer consolidate RxJS operator imports in `rxjs-extensions` file; each file should import what it needs.
|
||||
|
||||
不再在`rxjs-extensions`文件中统一导入RxJS的操作符,每个文件应该各自导入它自己所需的。
|
||||
不再在 `rxjs-extensions` 文件中统一导入 RxJS 的操作符,每个文件应该各自导入它自己所需的。
|
||||
|
||||
* All samples prepend template/style URLs with `./` as a best practice.
|
||||
|
||||
所有范例都在模板/样式的URL之前添加`./`前缀 …… 而且你在实际开发中也应该这么做。
|
||||
所有范例都在模板/样式的 URL 之前添加 `./` 前缀 …… 而且你在实际开发中也应该这么做。
|
||||
|
||||
* [Style Guide](guide/styleguide): copy edits and revised rules.
|
||||
|
||||
|
@ -175,37 +175,37 @@ HTTP guide.
|
|||
|
||||
## Testing: added component test plunkers (2016-12-02)
|
||||
|
||||
## 测试:添加了组件测试的plunker范例 (2016-12-02)
|
||||
## 测试:添加了组件测试的 plunker 范例 (2016-12-02)
|
||||
|
||||
Added two plunkers that each test _one simple component_ so you can write a component test plunker of your own: <live-example name="setup" plnkr="quickstart-specs">one</live-example> for the QuickStart seed's `AppComponent` and <live-example name="testing" plnkr="banner-specs">another</live-example> for the Testing guide's `BannerComponent`.
|
||||
Linked to these plunkers in "Testing" and "Setup anatomy" guides.
|
||||
|
||||
添加了两个plunker例子,每个都测试一个简单的组件,以便你可以自己在plunker中写组件测试:<live-example name="setup" plnkr="quickstart-specs">一个</live-example>用于测试快速起步中的`AppComponent`,<live-example name="testing" plnkr="banner-specs">另一个</live-example>用于测试“测试”章节的`BannerComponent`。
|
||||
添加了两个 plunker 例子,每个都测试一个简单的组件,以便你可以自己在 plunker 中写组件测试:<live-example name="setup" plnkr="quickstart-specs">一个</live-example>用于测试快速起步中的 `AppComponent`,<live-example name="testing" plnkr="banner-specs">另一个</live-example>用于测试“测试”章节的 `BannerComponent`。
|
||||
并在“测试”和“环境设置剖析”中链接到它们。
|
||||
|
||||
## Internationalization: pluralization and _select_ (2016-11-30)
|
||||
|
||||
## 国际化:单复数和`select` (2016-11-30)
|
||||
## 国际化:单复数和 `select` (2016-11-30)
|
||||
|
||||
The [Internationalization (i18n)](guide/i18n) guide explains how to handle pluralization and
|
||||
translation of alternative texts with `select`.
|
||||
The sample demonstrates these features too.
|
||||
|
||||
[国际化 (i18n)](guide/i18n)解释了如何处理单复数问题,和如何使用`select`来翻译候选内容。
|
||||
[国际化 (i18n)](guide/i18n)解释了如何处理单复数问题,和如何使用 `select` 来翻译候选内容。
|
||||
例子中也演示了这些特性。
|
||||
|
||||
## Testing: karma file updates (2016-11-30)
|
||||
|
||||
## 测试:更新了karma文件 (2016-11-30)
|
||||
## 测试:更新了 karma 文件 (2016-11-30)
|
||||
|
||||
* `karma.config` + `karma-test-shim` can handle multiple spec source paths;
|
||||
see quickstart issue: [angular/quickstart#294](https://github.com/angular/quickstart/issues/294).
|
||||
|
||||
`karma.config` + `karma-test-shim`可以处理多个测试源文件路径了,参见[angular/quickstart#294](https://github.com/angular/quickstart/issues/294)。
|
||||
`karma.config` + `karma-test-shim` 可以处理多个测试源文件路径了,参见[angular/quickstart#294](https://github.com/angular/quickstart/issues/294)。
|
||||
|
||||
* Displays Jasmine Runner output in the karma-launched browser.
|
||||
|
||||
在启动了karma的浏览器中显示Jasmine的输出。
|
||||
在启动了 karma 的浏览器中显示 Jasmine 的输出。
|
||||
|
||||
## QuickStart Rewrite (2016-11-18)
|
||||
|
||||
|
@ -224,15 +224,15 @@ You are no longer asked to copy-and-paste code into setup files that were not ex
|
|||
|
||||
## Sync with Angular v.2.2.0 (2016-11-14)
|
||||
|
||||
## 与Angular v.2.2.0同步(2016-11-14)
|
||||
## 与 Angular v.2.2.0 同步(2016-11-14)
|
||||
|
||||
Docs and code samples updated and tested with Angular v.2.2.0.
|
||||
|
||||
使用Angular v.2.2.0更新和测试所有文档和代码例子。
|
||||
使用 Angular v.2.2.0 更新和测试所有文档和代码例子。
|
||||
|
||||
## UPDATE: NgUpgrade Guide for the AOT friendly _upgrade/static_ module (2016-11-14)
|
||||
|
||||
## 更新:用于AoT的_upgrade/static_模块NgUpgrade指南 (2016-11-14)
|
||||
## 更新:用于 AoT 的_upgrade/static_模块 NgUpgrade 指南 (2016-11-14)
|
||||
|
||||
The updated [NgUpgrade Guide](guide/upgrade) guide covers the
|
||||
new AOT friendly `upgrade/static` module
|
||||
|
@ -240,52 +240,52 @@ released in v.2.2.0, which is the recommended
|
|||
facility for migrating from AngularJS to Angular.
|
||||
The documentation for the version prior to v.2.2.0 has been removed.
|
||||
|
||||
更新的[NgUpgrade指南](guide/upgrade)涵盖在v.2.2.0发布的AoT`upgrade/static`模块,
|
||||
是从AngularJS升级至Angular的推荐工具。
|
||||
删除早于v.2.2.0版本的文档。
|
||||
更新的[NgUpgrade 指南](guide/upgrade)涵盖在 v.2.2.0 发布的 AoT`upgrade/static` 模块,
|
||||
是从 AngularJS 升级至 Angular 的推荐工具。
|
||||
删除早于 v.2.2.0 版本的文档。
|
||||
|
||||
## ES6 described in "TypeScript to JavaScript" (2016-11-14)
|
||||
|
||||
## 在“从TypeScript到JavaScript”增加ES6的描述 (2016-11-14)
|
||||
## 在“从 TypeScript 到 JavaScript”增加 ES6 的描述 (2016-11-14)
|
||||
|
||||
The updated TypeScript to JavaScript guide explains how to write apps in ES6/7
|
||||
by translating the common idioms in the TypeScript documentation examples
|
||||
(and elsewhere on the web) to ES6/7 and ES5.
|
||||
|
||||
更新了“从TypeScript到JavaScript”,以解释如何使用ES6/7编写应用。
|
||||
将TypeScript文档示例中(以及网站其它地方)的习惯用法翻译成ES6/7和ES5。
|
||||
更新了“从 TypeScript 到 JavaScript”,以解释如何使用 ES6/7 编写应用。
|
||||
将 TypeScript 文档示例中(以及网站其它地方)的习惯用法翻译成 ES6/7 和 ES5。
|
||||
|
||||
This was [removed in August 2017](https://github.com/angular/angular/pull/18694) but can still be
|
||||
viewed in the [v2 documentation](https://v2.angular.io/docs/ts/latest/cookbook/ts-to-js.html).
|
||||
|
||||
本章已经 [于2017年8月移除](https://github.com/angular/angular/pull/18694),
|
||||
本章已经 [于 2017 年 8 月移除](https://github.com/angular/angular/pull/18694),
|
||||
不过仍然可以在[第二版的文档中](https://v2.angular.io/docs/ts/latest/cookbook/ts-to-js.html)看到。
|
||||
|
||||
## Sync with Angular v.2.1.1 (2016-10-21)
|
||||
|
||||
## 与Angular v.2.1.1 同步(2016-10-21)
|
||||
## 与 Angular v.2.1.1 同步(2016-10-21)
|
||||
|
||||
Docs and code samples updated and tested with Angular v.2.1.1.
|
||||
|
||||
使用Angular v.2.1.1更新和测试所有文档和代码例子。
|
||||
使用 Angular v.2.1.1 更新和测试所有文档和代码例子。
|
||||
|
||||
## npm _@types_ packages replace _typings_ (2016-10-20)
|
||||
|
||||
## 使用npm的_@types_包替换_typings_ (2016-10-20)
|
||||
## 使用 npm 的_@types_包替换_typings_ (2016-10-20)
|
||||
|
||||
Documentation samples now get TypeScript type information for 3rd party libraries
|
||||
from npm `@types` packages rather than with the _typings_ tooling.
|
||||
The `typings.json` file is gone.
|
||||
|
||||
文档例子现在从npm的`@types`第三方库获取TypeScript类型信息,不再使用_typings_。
|
||||
删除`typings.json`文件。
|
||||
文档例子现在从 npm 的 `@types` 第三方库获取 TypeScript 类型信息,不再使用_typings_。
|
||||
删除 `typings.json` 文件。
|
||||
|
||||
The [AngularJS Upgrade](guide/upgrade) guide reflects this change.
|
||||
The `package.json` installs `@types/angular` and several `@types/angular-...`
|
||||
packages in support of upgrade; these are not needed for pure Angular development.
|
||||
|
||||
"[从AngularJS升级](guide/upgrade)"指南反映了这个变化。
|
||||
`package.json`安装`@types/angular`和一些`@types/angular-...`包来支持升级。它们在纯Angular开发中是不需要的。
|
||||
"[从 AngularJS 升级](guide/upgrade)"指南反映了这个变化。
|
||||
`package.json` 安装 `@types/angular` 和一些 `@types/angular-...` 包来支持升级。它们在纯 Angular 开发中是不需要的。
|
||||
|
||||
## "Template Syntax" explains two-way data binding syntax (2016-10-20)
|
||||
|
||||
|
@ -294,20 +294,20 @@ packages in support of upgrade; these are not needed for pure Angular developmen
|
|||
Demonstrates how to two-way data bind to a custom Angular component and
|
||||
re-explains `[(ngModel)]` in terms of the basic `[()]` syntax.
|
||||
|
||||
展示了如何在自定义Angular组件中双向数据绑定,用基础`[()]`重新解释`[(ngModel)]`。
|
||||
展示了如何在自定义 Angular 组件中双向数据绑定,用基础 `[()]` 重新解释 `[(ngModel)]`。
|
||||
|
||||
## BREAKING CHANGE: `in-memory-web-api` (v.0.1.11) delivered as esm umd (2016-10-19)
|
||||
|
||||
## 破坏性变化:`in-memory-web-api` (v.0.1.11) 以esm umd的形式发布 (2016-10-19)
|
||||
## 破坏性变化:`in-memory-web-api` (v.0.1.11) 以 esm umd 的形式发布 (2016-10-19)
|
||||
|
||||
This change supports ES6 developers and aligns better with typical Angular libraries.
|
||||
It does not affect the module's API but it does affect how you load and import it.
|
||||
See the <a href="https://github.com/angular/in-memory-web-api/blob/master/CHANGELOG.md#0113-2016-10-20">change note</a>
|
||||
in the `in-memory-web-api` repo.
|
||||
|
||||
这个变化支持ES6开发者,并与典型的Angular库看齐。
|
||||
它不会影响模块的API,但是它改变了加载和导入它的方式。
|
||||
参见`in-memory-web-api`库的<a href="https://github.com/angular/in-memory-web-api/blob/master/CHANGELOG.md#0113-2016-10-20" target="_blank">变更记录</a>。
|
||||
这个变化支持 ES6 开发者,并与典型的 Angular 库看齐。
|
||||
它不会影响模块的 API,但是它改变了加载和导入它的方式。
|
||||
参见 `in-memory-web-api` 库的<a href="https://github.com/angular/in-memory-web-api/blob/master/CHANGELOG.md#0113-2016-10-20" target="_blank">变更记录</a>。
|
||||
|
||||
## "Router" _preload_ syntax and _:enter_/_:leave_ animations (2016-10-19)
|
||||
|
||||
|
@ -320,15 +320,15 @@ _before_ the user navigates to them for improved perceived performance.
|
|||
|
||||
New `:enter` and `:leave` aliases make animation more natural.
|
||||
|
||||
新`:enter`和`:leave`语法,让动画更加自然。
|
||||
新 `:enter` 和 `:leave` 语法,让动画更加自然。
|
||||
|
||||
## Sync with Angular v.2.1.0 (2016-10-12)
|
||||
|
||||
## 与Angular v.2.1.0同步(2016-10-12)
|
||||
## 与 Angular v.2.1.0 同步(2016-10-12)
|
||||
|
||||
Docs and code samples updated and tested with Angular v.2.1.0.
|
||||
|
||||
使用Angular v.2.1.0更新和测试所有文档和代码例子。
|
||||
使用 Angular v.2.1.0 更新和测试所有文档和代码例子。
|
||||
|
||||
## NEW "Ahead of time (AOT) Compilation" guide (2016-10-11)
|
||||
|
||||
|
@ -339,16 +339,16 @@ explains what AOT compilation is and why you'd want it.
|
|||
It demonstrates the basics with a QuickStart app
|
||||
followed by the more advanced considerations of compiling and bundling the Tour of Heroes.
|
||||
|
||||
全新[预编译(AoT)](guide/aot-compiler)烹饪书介绍了什么是AoT编译和为何你需要它。
|
||||
全新[预编译(AoT)](guide/aot-compiler)烹饪书介绍了什么是 AoT 编译和为何你需要它。
|
||||
它以**快速上手**应用程序开始讲解,接着介绍了编译和构建**英雄指南**的更高级的注意事项。
|
||||
|
||||
## Sync with Angular v.2.0.2 (2016-10-6)
|
||||
|
||||
## 与Angular v.2.0.2同步 (2016-10-6)
|
||||
## 与 Angular v.2.0.2 同步 (2016-10-6)
|
||||
|
||||
Docs and code samples updated and tested with Angular v.2.0.2.
|
||||
|
||||
使用Angular v.2.0.2更新和测试所有文档和代码例子。
|
||||
使用 Angular v.2.0.2 更新和测试所有文档和代码例子。
|
||||
|
||||
## "Routing and Navigation" guide with the _Router Module_ (2016-10-5)
|
||||
|
||||
|
@ -359,13 +359,13 @@ in a _Routing Module_.
|
|||
The _Routing Module_ replaces the previous _routing object_ involving the `ModuleWithProviders`.
|
||||
|
||||
[Routing and Navigation](guide/router)现在在**路由模块**中设置路由配置。
|
||||
**路由模块**替换之前的**路由对象**,使用了`ModuleWithProviders`。
|
||||
**路由模块**替换之前的**路由对象**,使用了 `ModuleWithProviders`。
|
||||
|
||||
All guided samples with routing use the _Routing Module_ and prose content has been updated,
|
||||
most conspicuously in the
|
||||
[NgModule](guide/ngmodules) guide and [NgModule FAQ](guide/ngmodule-faq) guide.
|
||||
|
||||
所有使用路由的例子都使用**路由模块**,相关内容也被更新。更新最多的是[Angular模块(NgModule)](guide/ngmodules)章和[Angular模块常见问题](guide/ngmodule-faq)烹饪书。
|
||||
所有使用路由的例子都使用**路由模块**,相关内容也被更新。更新最多的是[Angular 模块(NgModule)](guide/ngmodules)章和[Angular 模块常见问题](guide/ngmodule-faq)烹饪书。
|
||||
|
||||
## New "Internationalization" guide (2016-09-30)
|
||||
|
||||
|
@ -374,7 +374,7 @@ most conspicuously in the
|
|||
Added a new [Internationalization (i18n)](guide/i18n) guide that shows how
|
||||
to use Angular "i18n" facilities to translate template text into multiple languages.
|
||||
|
||||
添加了新的[国际化(i18n)](guide/i18n)烹饪书,展示了如何使用Angular的“i18n”工具来讲模板文本翻译到多种语言。
|
||||
添加了新的[国际化(i18n)](guide/i18n)烹饪书,展示了如何使用 Angular 的“i18n”工具来讲模板文本翻译到多种语言。
|
||||
|
||||
## "angular-in-memory-web-api" package rename (2016-09-27)
|
||||
|
||||
|
@ -383,7 +383,7 @@ to use Angular "i18n" facilities to translate template text into multiple langua
|
|||
Many samples use the `angular-in-memory-web-api` to simulate a remote server.
|
||||
This library is also useful to you during early development before you have a server to talk to.
|
||||
|
||||
许多例子使用了`angular-in-memory-web-api`来模拟远程服务器。
|
||||
许多例子使用了 `angular-in-memory-web-api` 来模拟远程服务器。
|
||||
这个库在你拥有服务器之前的早期开发阶段也很有用。
|
||||
|
||||
The package name was changed from "angular2-in-memory-web-api" which is still frozen-in-time on npm.
|
||||
|
@ -392,7 +392,7 @@ The new "angular-in-memory-web-api" has new features.
|
|||
|
||||
这个包的名字从“angular2-in-memory-web-api”(仍然有效,但不再更新了)重新命名了。
|
||||
新的“angular-in-memory-web-api”有新的功能。
|
||||
<a href="https://github.com/angular/in-memory-web-api/blob/master/README.md" target="_blank">到github获得更多详情</a>.
|
||||
<a href="https://github.com/angular/in-memory-web-api/blob/master/README.md" target="_blank">到 github 获得更多详情</a>.
|
||||
|
||||
## "Style Guide" with _NgModules_ (2016-09-27)
|
||||
|
||||
|
@ -403,26 +403,26 @@ Barrels now are far less useful and have been removed from the style guide;
|
|||
they remain valuable but are not a matter of Angular style.
|
||||
Also relaxed the rule that discouraged use of the `@Component.host` property.
|
||||
|
||||
[StyleGuide](guide/styleguide)解释了我们为Angular模块(NgModule)而推荐的约定。
|
||||
[StyleGuide](guide/styleguide)解释了我们为 Angular 模块(NgModule)而推荐的约定。
|
||||
现在,封装桶不再那么重要,风格指南已经移除了它们。
|
||||
它们仍然很有价值,但是它们与Angular风格无关。
|
||||
我们同时对**不推荐使用`@Component.host`属性**的规则有所放宽。
|
||||
它们仍然很有价值,但是它们与 Angular 风格无关。
|
||||
我们同时对**不推荐使用 `@Component.host` 属性**的规则有所放宽。
|
||||
|
||||
## _moduleId: module.id_ everywhere (2016-09-25)
|
||||
|
||||
## moduleId:到处添加module.id(2016-09-25)
|
||||
## moduleId:到处添加 module.id(2016-09-25)
|
||||
|
||||
Sample components that get their templates or styles with `templateUrl` or `styleUrls`
|
||||
have been converted to _module-relative_ URLs.
|
||||
Added the `moduleId: module.id` property-and-value to their `@Component` metadata.
|
||||
|
||||
在所有使用`templateUrl`或者`styleUrls`来获取模板或样式的例子组件都被转换为**相对模块**的URL。
|
||||
我们添加了`moduleId: module.id`到它们的`@Component`元数据。
|
||||
在所有使用 `templateUrl` 或者 `styleUrls` 来获取模板或样式的例子组件都被转换为**相对模块**的 URL。
|
||||
我们添加了 `moduleId: module.id` 到它们的 `@Component` 元数据。
|
||||
|
||||
This change is a requirement for compilation with AOT compiler when the app loads
|
||||
modules with SystemJS as the samples currently do.
|
||||
|
||||
当应用像例子当前使用的方法一样 - 使用SystemJS加载模块时,本更新是AoT编译器的前提条件。
|
||||
当应用像例子当前使用的方法一样 - 使用 SystemJS 加载模块时,本更新是 AoT 编译器的前提条件。
|
||||
|
||||
## "Lifecycle Hooks" guide simplified (2016-09-24)
|
||||
|
||||
|
@ -432,4 +432,4 @@ The [Lifecycle Hooks](guide/lifecycle-hooks) guide is shorter, simpler, and
|
|||
draws more attention to the order in which Angular calls the hooks.
|
||||
|
||||
|
||||
[生命周期钩子](guide/lifecycle-hooks)章现在更加简短,并且对强调了Angular是以什么顺序来调用钩子方法的。
|
||||
[生命周期钩子](guide/lifecycle-hooks)章现在更加简短,并且对强调了 Angular 是以什么顺序来调用钩子方法的。
|
||||
|
|
|
@ -226,7 +226,7 @@ is available to <code>declarations</code> of this module.</p>
|
|||
|
||||
<p>Binds the presence of the CSS class <code>extra-sparkle</code> on the element to the truthiness of the expression <code>isDelightful</code>.</p>
|
||||
|
||||
<p>根据<code>isDelightful</code>表达式的结果是否为真,决定CSS类<code>extra-sparkle</code>是否出现在当前元素上。</p>
|
||||
<p>根据<code>isDelightful</code>表达式的结果是否为真,决定 CSS 类<code>extra-sparkle</code>是否出现在当前元素上。</p>
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -242,7 +242,7 @@ is available to <code>declarations</code> of this module.</p>
|
|||
|
||||
<p>Binds style property <code>width</code> to the result of expression <code>mySize</code> in pixels. Units are optional.</p>
|
||||
|
||||
<p>把CSS样式属性<code>width</code>的px(像素)值绑定到表达式<code>mySize</code>的结果。单位是可选的。</p>
|
||||
<p>把 CSS 样式属性<code>width</code>的 px(像素)值绑定到表达式<code>mySize</code>的结果。单位是可选的。</p>
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -258,7 +258,7 @@ is available to <code>declarations</code> of this module.</p>
|
|||
|
||||
<p>Calls method <code>readRainbow</code> when a click event is triggered on this button element (or its children) and passes in the event object.</p>
|
||||
|
||||
<p>当这个按钮元素(及其子元素)上的click事件触发时,调用方法<code>readRainbow</code>,并把这个事件对象作为参数传进去。</p>
|
||||
<p>当这个按钮元素(及其子元素)上的 click 事件触发时,调用方法<code>readRainbow</code>,并把这个事件对象作为参数传进去。</p>
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -462,7 +462,7 @@ is available to <code>declarations</code> of this module.</p>
|
|||
|
||||
<p>Turns the li element and its contents into a template, and uses that to instantiate a view for each item in list.</p>
|
||||
|
||||
<p>把li元素及其内容变成一个模板,并使用这个模板为列表中的每一个条目实例化一个视图。</p>
|
||||
<p>把 li 元素及其内容变成一个模板,并使用这个模板为列表中的每一个条目实例化一个视图。</p>
|
||||
|
||||
</td>
|
||||
|
||||
|
|
|
@ -27,11 +27,11 @@ in which two or more components share information.
|
|||
|
||||
* [Intercept input property changes with `ngOnChanges()`](guide/component-interaction#parent-to-child-on-changes)
|
||||
|
||||
[使用`ngOnChanges()`拦截输入属性的变化](guide/component-interaction#parent-to-child-on-changes)
|
||||
[使用 `ngOnChanges()` 拦截输入属性的变化](guide/component-interaction#parent-to-child-on-changes)
|
||||
|
||||
* [Parent calls an `@ViewChild()`](guide/component-interaction#parent-to-view-child)
|
||||
|
||||
[在父组件中调用`@ViewChild()`](guide/component-interaction#parent-to-view-child)
|
||||
[在父组件中调用 `@ViewChild()`](guide/component-interaction#parent-to-view-child)
|
||||
|
||||
* [Parent and children communicate via a service](guide/component-interaction#bidirectional-service)
|
||||
|
||||
|
@ -52,7 +52,7 @@ in which two or more components share information.
|
|||
`HeroChildComponent` has two ***input properties***,
|
||||
typically adorned with [@Input decorations](guide/template-syntax#inputs-outputs).
|
||||
|
||||
`HeroChildComponent` 有两个***输入型属性***,它们通常带[@Input装饰器](guide/template-syntax#inputs-outputs)。
|
||||
`HeroChildComponent` 有两个***输入型属性***,它们通常带[@Input 装饰器](guide/template-syntax#inputs-outputs)。
|
||||
|
||||
<code-example path="component-interaction/src/app/hero-child.component.ts" title="component-interaction/src/app/hero-child.component.ts">
|
||||
|
||||
|
@ -60,13 +60,13 @@ typically adorned with [@Input decorations](guide/template-syntax#inputs-outputs
|
|||
|
||||
The second `@Input` aliases the child component property name `masterName` as `'master'`.
|
||||
|
||||
第二个`@Input`为子组件的属性名`masterName`指定一个别名`master`(译者注:不推荐为起别名,请参见风格指南).
|
||||
第二个 `@Input` 为子组件的属性名 `masterName` 指定一个别名 `master`(译者注:不推荐为起别名,请参见风格指南).
|
||||
|
||||
The `HeroParentComponent` nests the child `HeroChildComponent` inside an `*ngFor` repeater,
|
||||
binding its `master` string property to the child's `master` alias,
|
||||
and each iteration's `hero` instance to the child's `hero` property.
|
||||
|
||||
父组件`HeroParentComponent`把子组件的`HeroChildComponent`放到`*ngFor`循环器中,把自己的`master`字符串属性绑定到子组件的`master`别名上,并把每个循环的`hero`实例绑定到子组件的`hero`属性。
|
||||
父组件 `HeroParentComponent` 把子组件的 `HeroChildComponent` 放到 `*ngFor` 循环器中,把自己的 `master` 字符串属性绑定到子组件的 `master` 别名上,并把每个循环的 `hero` 实例绑定到子组件的 `hero` 属性。
|
||||
|
||||
<code-example path="component-interaction/src/app/hero-parent.component.ts" title="component-interaction/src/app/hero-parent.component.ts">
|
||||
|
||||
|
@ -100,16 +100,16 @@ E2E test that all children were instantiated and displayed as expected:
|
|||
|
||||
## Intercept input property changes with a setter
|
||||
|
||||
## 通过setter截听输入属性值的变化
|
||||
## 通过 setter 截听输入属性值的变化
|
||||
|
||||
Use an input property setter to intercept and act upon a value from the parent.
|
||||
|
||||
使用一个输入属性的setter,以拦截父组件中值的变化,并采取行动。
|
||||
使用一个输入属性的 setter,以拦截父组件中值的变化,并采取行动。
|
||||
|
||||
The setter of the `name` input property in the child `NameChildComponent`
|
||||
trims the whitespace from a name and replaces an empty value with default text.
|
||||
|
||||
子组件`NameChildComponent`的输入属性`name`上的这个setter,会trim掉名字里的空格,并把空值替换成默认字符串。
|
||||
子组件 `NameChildComponent` 的输入属性 `name` 上的这个 setter,会 trim 掉名字里的空格,并把空值替换成默认字符串。
|
||||
|
||||
<code-example path="component-interaction/src/app/name-child.component.ts" title="component-interaction/src/app/name-child.component.ts">
|
||||
|
||||
|
@ -117,7 +117,7 @@ trims the whitespace from a name and replaces an empty value with default text.
|
|||
|
||||
Here's the `NameParentComponent` demonstrating name variations including a name with all spaces:
|
||||
|
||||
下面的`NameParentComponent`展示了各种名字的处理方式,包括一个全是空格的名字。
|
||||
下面的 `NameParentComponent` 展示了各种名字的处理方式,包括一个全是空格的名字。
|
||||
|
||||
<code-example path="component-interaction/src/app/name-parent.component.ts" title="component-interaction/src/app/name-parent.component.ts">
|
||||
|
||||
|
@ -133,7 +133,7 @@ Here's the `NameParentComponent` demonstrating name variations including a name
|
|||
|
||||
E2E tests of input property setter with empty and non-empty names:
|
||||
|
||||
端到端测试:输入属性的setter,分别使用空名字和非空名字。
|
||||
端到端测试:输入属性的 setter,分别使用空名字和非空名字。
|
||||
|
||||
<code-example path="component-interaction/e2e/app.e2e-spec.ts" region="parent-to-child-setter" title="component-interaction/e2e/app.e2e-spec.ts">
|
||||
|
||||
|
@ -151,23 +151,23 @@ E2E tests of input property setter with empty and non-empty names:
|
|||
|
||||
Detect and act upon changes to input property values with the `ngOnChanges()` method of the `OnChanges` lifecycle hook interface.
|
||||
|
||||
使用`OnChanges`生命周期钩子接口的`ngOnChanges()`方法来监测输入属性值的变化并做出回应。
|
||||
使用 `OnChanges` 生命周期钩子接口的 `ngOnChanges()` 方法来监测输入属性值的变化并做出回应。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
You may prefer this approach to the property setter when watching multiple, interacting input properties.
|
||||
|
||||
当需要监视多个、交互式输入属性的时候,本方法比用属性的setter更合适。
|
||||
当需要监视多个、交互式输入属性的时候,本方法比用属性的 setter 更合适。
|
||||
|
||||
Learn about `ngOnChanges()` in the [LifeCycle Hooks](guide/lifecycle-hooks) chapter.
|
||||
|
||||
学习关于`ngOnChanges()`的更多知识,参见[生命周期钩子](guide/lifecycle-hooks)一章。
|
||||
学习关于 `ngOnChanges()` 的更多知识,参见[生命周期钩子](guide/lifecycle-hooks)一章。
|
||||
|
||||
</div>
|
||||
|
||||
This `VersionChildComponent` detects changes to the `major` and `minor` input properties and composes a log message reporting these changes:
|
||||
|
||||
这个`VersionChildComponent`会监测输入属性`major`和`minor`的变化,并把这些变化编写成日志以报告这些变化。
|
||||
这个 `VersionChildComponent` 会监测输入属性 `major` 和 `minor` 的变化,并把这些变化编写成日志以报告这些变化。
|
||||
|
||||
<code-example path="component-interaction/src/app/version-child.component.ts" title="component-interaction/src/app/version-child.component.ts">
|
||||
|
||||
|
@ -175,7 +175,7 @@ This `VersionChildComponent` detects changes to the `major` and `minor` input pr
|
|||
|
||||
The `VersionParentComponent` supplies the `minor` and `major` values and binds buttons to methods that change them.
|
||||
|
||||
`VersionParentComponent`提供`minor`和`major`值,把修改它们值的方法绑定到按钮上。
|
||||
`VersionParentComponent` 提供 `minor` 和 `major` 值,把修改它们值的方法绑定到按钮上。
|
||||
|
||||
<code-example path="component-interaction/src/app/version-parent.component.ts" title="component-interaction/src/app/version-parent.component.ts">
|
||||
|
||||
|
@ -196,7 +196,7 @@ Here's the output of a button-pushing sequence:
|
|||
Test that ***both*** input properties are set initially and that button clicks trigger
|
||||
the expected `ngOnChanges` calls and values:
|
||||
|
||||
测试确保***这两个***输入属性值都被初始化了,当点击按钮后,`ngOnChanges`应该被调用,属性的值也符合预期。
|
||||
测试确保***这两个***输入属性值都被初始化了,当点击按钮后,`ngOnChanges` 应该被调用,属性的值也符合预期。
|
||||
|
||||
<code-example path="component-interaction/e2e/app.e2e-spec.ts" region="parent-to-child-onchanges" title="component-interaction/e2e/app.e2e-spec.ts">
|
||||
|
||||
|
@ -215,13 +215,13 @@ the expected `ngOnChanges` calls and values:
|
|||
The child component exposes an `EventEmitter` property with which it `emits` events when something happens.
|
||||
The parent binds to that event property and reacts to those events.
|
||||
|
||||
子组件暴露一个`EventEmitter`属性,当事件发生时,子组件利用该属性`emits`(向上弹射)事件。父组件绑定到这个事件属性,并在事件发生时作出回应。
|
||||
子组件暴露一个 `EventEmitter` 属性,当事件发生时,子组件利用该属性 `emits`(向上弹射)事件。父组件绑定到这个事件属性,并在事件发生时作出回应。
|
||||
|
||||
The child's `EventEmitter` property is an ***output property***,
|
||||
typically adorned with an [@Output decoration](guide/template-syntax#inputs-outputs)
|
||||
as seen in this `VoterComponent`:
|
||||
|
||||
子组件的`EventEmitter`属性是一个**输出属性**,通常带有[@Output装饰器](guide/template-syntax#inputs-outputs),就像在`VoterComponent`中看到的。
|
||||
子组件的 `EventEmitter` 属性是一个**输出属性**,通常带有[@Output 装饰器](guide/template-syntax#inputs-outputs),就像在 `VoterComponent` 中看到的。
|
||||
|
||||
<code-example path="component-interaction/src/app/voter.component.ts" title="component-interaction/src/app/voter.component.ts">
|
||||
|
||||
|
@ -229,12 +229,12 @@ The child's `EventEmitter` property is an ***output property***,
|
|||
|
||||
Clicking a button triggers emission of a `true` or `false`, the boolean *payload*.
|
||||
|
||||
点击按钮会触发`true`或`false`(布尔型*有效载荷*)的事件。
|
||||
点击按钮会触发 `true` 或 `false`(布尔型*有效载荷*)的事件。
|
||||
|
||||
The parent `VoteTakerComponent` binds an event handler called `onVoted()` that responds to the child event
|
||||
payload `$event` and updates a counter.
|
||||
|
||||
父组件`VoteTakerComponent`绑定了一个事件处理器(`onVoted()`),用来响应子组件的事件(`$event`)并更新一个计数器。
|
||||
父组件 `VoteTakerComponent` 绑定了一个事件处理器(`onVoted()`),用来响应子组件的事件(`$event`)并更新一个计数器。
|
||||
|
||||
<code-example path="component-interaction/src/app/votetaker.component.ts" title="component-interaction/src/app/votetaker.component.ts">
|
||||
|
||||
|
@ -243,7 +243,7 @@ payload `$event` and updates a counter.
|
|||
The framework passes the event argument—represented by `$event`—to the handler method,
|
||||
and the method processes it:
|
||||
|
||||
框架(Angular)把事件参数(用`$event`表示)传给事件处理方法,这个方法会处理:
|
||||
框架(Angular)把事件参数(用 `$event` 表示)传给事件处理方法,这个方法会处理:
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/component-interaction/child-to-parent.gif" alt="Child-to-parent">
|
||||
|
@ -283,7 +283,7 @@ The following is a child `CountdownTimerComponent` that repeatedly counts down t
|
|||
It has `start` and `stop` methods that control the clock and it displays a
|
||||
countdown status message in its own template.
|
||||
|
||||
子组件`CountdownTimerComponent`进行倒计时,归零时发射一个导弹。`start`和`stop`方法负责控制时钟并在模板里显示倒计时的状态信息。
|
||||
子组件 `CountdownTimerComponent` 进行倒计时,归零时发射一个导弹。`start` 和 `stop` 方法负责控制时钟并在模板里显示倒计时的状态信息。
|
||||
|
||||
<code-example path="component-interaction/src/app/countdown-timer.component.ts" title="component-interaction/src/app/countdown-timer.component.ts">
|
||||
|
||||
|
@ -291,7 +291,7 @@ countdown status message in its own template.
|
|||
|
||||
The `CountdownLocalVarParentComponent` that hosts the timer component is as follows:
|
||||
|
||||
让我们来看看计时器组件的宿主组件`CountdownLocalVarParentComponent`。
|
||||
让我们来看看计时器组件的宿主组件 `CountdownLocalVarParentComponent`。
|
||||
|
||||
<code-example path="component-interaction/src/app/countdown-parent.component.ts" region="lv" title="component-interaction/src/app/countdown-parent.component.ts">
|
||||
|
||||
|
@ -300,7 +300,7 @@ The `CountdownLocalVarParentComponent` that hosts the timer component is as foll
|
|||
The parent component cannot data bind to the child's
|
||||
`start` and `stop` methods nor to its `seconds` property.
|
||||
|
||||
父组件不能通过数据绑定使用子组件的`start`和`stop`方法,也不能访问子组件的`seconds`属性。
|
||||
父组件不能通过数据绑定使用子组件的 `start` 和 `stop` 方法,也不能访问子组件的 `seconds` 属性。
|
||||
|
||||
You can place a local variable, `#timer`, on the tag `<countdown-timer>` representing the child component.
|
||||
That gives you a reference to the child component and the ability to access
|
||||
|
@ -311,7 +311,7 @@ That gives you a reference to the child component and the ability to access
|
|||
This example wires parent buttons to the child's `start` and `stop` and
|
||||
uses interpolation to display the child's `seconds` property.
|
||||
|
||||
在这个例子中,我们把父组件的按钮绑定到子组件的`start`和`stop`方法,并用插值表达式来显示子组件的`seconds`属性。
|
||||
在这个例子中,我们把父组件的按钮绑定到子组件的 `start` 和 `stop` 方法,并用插值表达式来显示子组件的 `seconds` 属性。
|
||||
|
||||
Here we see the parent and child working together.
|
||||
|
||||
|
@ -382,7 +382,7 @@ is solely for the purpose of demonstration.
|
|||
|
||||
Here is the parent, `CountdownViewChildParentComponent`:
|
||||
|
||||
下面是父组件`CountdownViewChildParentComponent`:
|
||||
下面是父组件 `CountdownViewChildParentComponent`:
|
||||
|
||||
<code-example path="component-interaction/src/app/countdown-parent.component.ts" region="vc" title="component-interaction/src/app/countdown-parent.component.ts">
|
||||
|
||||
|
@ -394,18 +394,18 @@ It takes a bit more work to get the child view into the parent component *class*
|
|||
|
||||
First, you have to import references to the `ViewChild` decorator and the `AfterViewInit` lifecycle hook.
|
||||
|
||||
首先,你要使用`ViewChild`装饰器导入这个引用,并挂上`AfterViewInit`生命周期钩子。
|
||||
首先,你要使用 `ViewChild` 装饰器导入这个引用,并挂上 `AfterViewInit` 生命周期钩子。
|
||||
|
||||
Next, inject the child `CountdownTimerComponent` into the private `timerComponent` property
|
||||
via the `@ViewChild` property decoration.
|
||||
|
||||
接着,通过`@ViewChild`属性装饰器,将子组件`CountdownTimerComponent`注入到私有属性`timerComponent`里面。
|
||||
接着,通过 `@ViewChild` 属性装饰器,将子组件 `CountdownTimerComponent` 注入到私有属性 `timerComponent` 里面。
|
||||
|
||||
The `#timer` local variable is gone from the component metadata.
|
||||
Instead, bind the buttons to the parent component's own `start` and `stop` methods and
|
||||
present the ticking seconds in an interpolation around the parent component's `seconds` method.
|
||||
|
||||
组件元数据里就不再需要`#timer`本地变量了。而是把按钮绑定到父组件自己的`start`和`stop`方法,使用父组件的`seconds`方法的插值表达式来展示秒数变化。
|
||||
组件元数据里就不再需要 `#timer` 本地变量了。而是把按钮绑定到父组件自己的 `start` 和 `stop` 方法,使用父组件的 `seconds` 方法的插值表达式来展示秒数变化。
|
||||
|
||||
These methods access the injected timer component directly.
|
||||
|
||||
|
@ -415,19 +415,19 @@ The `ngAfterViewInit()` lifecycle hook is an important wrinkle.
|
|||
The timer component isn't available until *after* Angular displays the parent view.
|
||||
So it displays `0` seconds initially.
|
||||
|
||||
`ngAfterViewInit()`生命周期钩子是非常重要的一步。被注入的计时器组件只有在Angular显示了父组件视图之后才能访问,所以我们先把秒数显示为0.
|
||||
`ngAfterViewInit()` 生命周期钩子是非常重要的一步。被注入的计时器组件只有在 Angular 显示了父组件视图之后才能访问,所以我们先把秒数显示为 0.
|
||||
|
||||
Then Angular calls the `ngAfterViewInit` lifecycle hook at which time it is *too late*
|
||||
to update the parent view's display of the countdown seconds.
|
||||
Angular's unidirectional data flow rule prevents updating the parent view's
|
||||
in the same cycle. The app has to *wait one turn* before it can display the seconds.
|
||||
|
||||
然后Angular会调用`ngAfterViewInit`生命周期钩子,但这时候再更新父组件视图的倒计时就已经太晚了。Angular的单向数据流规则会阻止在同一个周期内更新父组件视图。我们在显示秒数之前会被迫*再等一轮*。
|
||||
然后 Angular 会调用 `ngAfterViewInit` 生命周期钩子,但这时候再更新父组件视图的倒计时就已经太晚了。Angular 的单向数据流规则会阻止在同一个周期内更新父组件视图。我们在显示秒数之前会被迫*再等一轮*。
|
||||
|
||||
Use `setTimeout()` to wait one tick and then revise the `seconds()` method so
|
||||
that it takes future values from the timer component.
|
||||
|
||||
使用`setTimeout()`来等下一轮,然后改写`seconds()`方法,这样它接下来就会从注入的这个计时器组件里获取秒数的值。
|
||||
使用 `setTimeout()` 来等下一轮,然后改写 `seconds()` 方法,这样它接下来就会从注入的这个计时器组件里获取秒数的值。
|
||||
|
||||
<h3 class="no-toc">Test it</h3>
|
||||
|
||||
|
@ -459,7 +459,7 @@ Components outside this component subtree have no access to the service or their
|
|||
|
||||
This `MissionService` connects the `MissionControlComponent` to multiple `AstronautComponent` children.
|
||||
|
||||
这个`MissionService`把`MissionControlComponent`和多个`AstronautComponent`子组件连接起来。
|
||||
这个 `MissionService` 把 `MissionControlComponent` 和多个 `AstronautComponent` 子组件连接起来。
|
||||
|
||||
<code-example path="component-interaction/src/app/mission.service.ts" title="component-interaction/src/app/mission.service.ts">
|
||||
|
||||
|
@ -468,7 +468,7 @@ This `MissionService` connects the `MissionControlComponent` to multiple `Astron
|
|||
The `MissionControlComponent` both provides the instance of the service that it shares with its children
|
||||
(through the `providers` metadata array) and injects that instance into itself through its constructor:
|
||||
|
||||
`MissionControlComponent`提供服务的实例,并将其共享给它的子组件(通过`providers`元数据数组),子组件可以通过构造函数将该实例注入到自身。
|
||||
`MissionControlComponent` 提供服务的实例,并将其共享给它的子组件(通过 `providers` 元数据数组),子组件可以通过构造函数将该实例注入到自身。
|
||||
|
||||
<code-example path="component-interaction/src/app/missioncontrol.component.ts" title="component-interaction/src/app/missioncontrol.component.ts">
|
||||
|
||||
|
@ -477,7 +477,7 @@ The `MissionControlComponent` both provides the instance of the service that it
|
|||
The `AstronautComponent` also injects the service in its constructor.
|
||||
Each `AstronautComponent` is a child of the `MissionControlComponent` and therefore receives its parent's service instance:
|
||||
|
||||
`AstronautComponent`也通过自己的构造函数注入该服务。由于每个`AstronautComponent`都是`MissionControlComponent`的子组件,所以它们获取到的也是父组件的这个服务实例。
|
||||
`AstronautComponent` 也通过自己的构造函数注入该服务。由于每个 `AstronautComponent` 都是 `MissionControlComponent` 的子组件,所以它们获取到的也是父组件的这个服务实例。
|
||||
|
||||
<code-example path="component-interaction/src/app/astronaut.component.ts" title="component-interaction/src/app/astronaut.component.ts">
|
||||
|
||||
|
@ -490,13 +490,13 @@ This is a memory-leak guard step. There is no actual risk in this app because th
|
|||
lifetime of a `AstronautComponent` is the same as the lifetime of the app itself.
|
||||
That *would not* always be true in a more complex application.
|
||||
|
||||
注意,这个例子保存了`subscription`变量,并在`AstronautComponent`被销毁时调用`unsubscribe()`退订。
|
||||
这是一个用于防止内存泄漏的保护措施。实际上,在这个应用程序中并没有这个风险,因为`AstronautComponent`的生命期和应用程序的生命期一样长。但在更复杂的应用程序环境中就不一定了。
|
||||
注意,这个例子保存了 `subscription` 变量,并在 `AstronautComponent` 被销毁时调用 `unsubscribe()` 退订。
|
||||
这是一个用于防止内存泄漏的保护措施。实际上,在这个应用程序中并没有这个风险,因为 `AstronautComponent` 的生命期和应用程序的生命期一样长。但在更复杂的应用程序环境中就不一定了。
|
||||
|
||||
You don't add this guard to the `MissionControlComponent` because, as the parent,
|
||||
it controls the lifetime of the `MissionService`.
|
||||
|
||||
不需要在`MissionControlComponent`中添加这个保护措施,因为它作为父组件,控制着`MissionService`的生命期。
|
||||
不需要在 `MissionControlComponent` 中添加这个保护措施,因为它作为父组件,控制着 `MissionService` 的生命期。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -504,7 +504,7 @@ The *History* log demonstrates that messages travel in both directions between
|
|||
the parent `MissionControlComponent` and the `AstronautComponent` children,
|
||||
facilitated by the service:
|
||||
|
||||
*History*日志证明了:在父组件`MissionControlComponent`和子组件`AstronautComponent`之间,信息通过该服务实现了双向传递。
|
||||
*History*日志证明了:在父组件 `MissionControlComponent` 和子组件 `AstronautComponent` 之间,信息通过该服务实现了双向传递。
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/component-interaction/bidirectional-service.gif" alt="bidirectional-service">
|
||||
|
@ -517,7 +517,7 @@ facilitated by the service:
|
|||
Tests click buttons of both the parent `MissionControlComponent` and the `AstronautComponent` children
|
||||
and verify that the history meets expectations:
|
||||
|
||||
测试确保点击父组件`MissionControlComponent`和子组件`AstronautComponent`两个的组件的按钮时,*History*日志和预期的一样。
|
||||
测试确保点击父组件 `MissionControlComponent` 和子组件 `AstronautComponent` 两个的组件的按钮时,*History*日志和预期的一样。
|
||||
|
||||
<code-example path="component-interaction/e2e/app.e2e-spec.ts" region="bidirectional-service" title="component-interaction/e2e/app.e2e-spec.ts">
|
||||
|
||||
|
|
|
@ -37,8 +37,8 @@ One way to do this is to set the `styles` property in the component metadata.
|
|||
The `styles` property takes an array of strings that contain CSS code.
|
||||
Usually you give it one string, as in the following example:
|
||||
|
||||
实现方式之一,是在组件的元数据中设置`styles`属性。
|
||||
`styles`属性可以接受一个包含 CSS 代码的字符串数组。
|
||||
实现方式之一,是在组件的元数据中设置 `styles` 属性。
|
||||
`styles` 属性可以接受一个包含 CSS 代码的字符串数组。
|
||||
通常我们只给它一个字符串就行了,如同下例:
|
||||
|
||||
<code-example path="component-styles/src/app/hero-app.component.ts" title="src/app/hero-app.component.ts" linenums="false">
|
||||
|
@ -113,7 +113,7 @@ The following sections describe these selectors.
|
|||
Use the `:host` pseudo-class selector to target styles in the element that *hosts* the component (as opposed to
|
||||
targeting elements *inside* the component's template).
|
||||
|
||||
使用`:host`伪类选择器,用来选择组件*宿主*元素中的元素(相对于组件模板*内部*的元素)。
|
||||
使用 `:host` 伪类选择器,用来选择组件*宿主*元素中的元素(相对于组件模板*内部*的元素)。
|
||||
|
||||
<code-example path="component-styles/src/app/hero-details.component.css" region="host" title="src/app/hero-details.component.css" linenums="false">
|
||||
|
||||
|
@ -129,11 +129,11 @@ component's own template. The host element is in a parent component's template.
|
|||
Use the *function form* to apply host styles conditionally by
|
||||
including another selector inside parentheses after `:host`.
|
||||
|
||||
要把宿主样式作为条件,就要像*函数*一样把其它选择器放在`:host`后面的括号中。
|
||||
要把宿主样式作为条件,就要像*函数*一样把其它选择器放在 `:host` 后面的括号中。
|
||||
|
||||
The next example targets the host element again, but only when it also has the `active` CSS class.
|
||||
|
||||
在下一个例子中,我们又一次把宿主元素作为目标,但是只有当它同时带有`active` CSS 类的时候才会生效。
|
||||
在下一个例子中,我们又一次把宿主元素作为目标,但是只有当它同时带有 `active` CSS 类的时候才会生效。
|
||||
|
||||
<code-example path="component-styles/src/app/hero-details.component.css" region="hostfunction" title="src/app/hero-details.component.css" linenums="false">
|
||||
|
||||
|
@ -148,19 +148,19 @@ For example, a CSS theme class could be applied to the document `<body>` element
|
|||
you want to change how your component looks based on that.
|
||||
|
||||
有时候,基于某些来自组件视图*外部*的条件应用样式是很有用的。
|
||||
例如,在文档的`<body>`元素上可能有一个用于表示样式主题 (theme) 的 CSS 类,而我们应当基于它来决定组件的样式。
|
||||
例如,在文档的 `<body>` 元素上可能有一个用于表示样式主题 (theme) 的 CSS 类,而我们应当基于它来决定组件的样式。
|
||||
|
||||
Use the `:host-context()` pseudo-class selector, which works just like the function
|
||||
form of `:host()`. The `:host-context()` selector looks for a CSS class in any ancestor of the component host element,
|
||||
up to the document root. The `:host-context()` selector is useful when combined with another selector.
|
||||
|
||||
这时可以使用`:host-context()`伪类选择器。它也以类似`:host()`形式使用。它在当前组件宿主元素的*祖先节点*中查找 CSS 类,
|
||||
这时可以使用 `:host-context()` 伪类选择器。它也以类似 `:host()` 形式使用。它在当前组件宿主元素的*祖先节点*中查找 CSS 类,
|
||||
直到文档的根节点为止。在与其它选择器组合使用时,它非常有用。
|
||||
|
||||
The following example applies a `background-color` style to all `<h2>` elements *inside* the component, only
|
||||
if some ancestor element has the CSS class `theme-light`.
|
||||
|
||||
在下面的例子中,只有当某个祖先元素有 CSS 类`theme-light`时,我们才会把`background-color`样式应用到组件*内部*的所有`<h2>`元素中。
|
||||
在下面的例子中,只有当某个祖先元素有 CSS 类 `theme-light` 时,我们才会把 `background-color` 样式应用到组件*内部*的所有 `<h2>` 元素中。
|
||||
|
||||
<code-example path="component-styles/src/app/hero-details.component.css" region="hostcontext" title="src/app/hero-details.component.css" linenums="false">
|
||||
|
||||
|
@ -168,7 +168,7 @@ if some ancestor element has the CSS class `theme-light`.
|
|||
|
||||
### (deprecated) `/deep/`, `>>>`, and `::ng-deep`
|
||||
|
||||
### 已废弃 `/deep/`、`>>>`和`::ng-deep`
|
||||
### 已废弃 `/deep/`、`>>>` 和 `::ng-deep`
|
||||
|
||||
Component styles normally apply only to the HTML in the component's own template.
|
||||
|
||||
|
@ -179,12 +179,12 @@ component tree into all the child component views.
|
|||
The `/deep/` combinator works to any depth of nested components, and it applies to both the view
|
||||
children and content children of the component.
|
||||
|
||||
我们可以使用`/deep/`选择器,来强制一个样式对各级子组件的视图也生效,它*不但作用于组件的子视图,也会作用于组件的内容*。
|
||||
我们可以使用 `/deep/` 选择器,来强制一个样式对各级子组件的视图也生效,它*不但作用于组件的子视图,也会作用于组件的内容*。
|
||||
|
||||
The following example targets all `<h3>` elements, from the host element down
|
||||
through this component to all of its child elements in the DOM.
|
||||
|
||||
在这个例子中,我们以所有的`<h3>`元素为目标,从宿主元素到当前元素再到 DOM 中的所有子元素:
|
||||
在这个例子中,我们以所有的 `<h3>` 元素为目标,从宿主元素到当前元素再到 DOM 中的所有子元素:
|
||||
|
||||
<code-example path="component-styles/src/app/hero-details.component.css" region="deep" title="src/app/hero-details.component.css" linenums="false">
|
||||
|
||||
|
@ -192,7 +192,7 @@ through this component to all of its child elements in the DOM.
|
|||
|
||||
The `/deep/` combinator also has the aliases `>>>`, and `::ng-deep`.
|
||||
|
||||
`/deep/` 组合器还有两个别名:`>>>`和`::ng-deep`。
|
||||
`/deep/` 组合器还有两个别名:`>>>` 和 `::ng-deep`。
|
||||
|
||||
<div class="alert is-important">
|
||||
|
||||
|
@ -200,7 +200,7 @@ Use `/deep/`, `>>>` and `::ng-deep` only with *emulated* view encapsulation.
|
|||
Emulated is the default and most commonly used view encapsulation. For more information, see the
|
||||
[Controlling view encapsulation](guide/component-styles#view-encapsulation) section.
|
||||
|
||||
`/deep/`和`>>>`选择器只能被用在**仿真 (emulated) **模式下。
|
||||
`/deep/` 和 `>>>` 选择器只能被用在**仿真 (emulated) **模式下。
|
||||
这种方式是默认值,也是用得最多的方式。
|
||||
更多信息,见[控制视图封装模式](guide/component-styles#view-encapsulation)一节。
|
||||
|
||||
|
@ -212,9 +212,9 @@ The shadow-piercing descendant combinator is deprecated and [support is being re
|
|||
As such we plan to drop support in Angular (for all 3 of `/deep/`, `>>>` and `::ng-deep`).
|
||||
Until then `::ng-deep` should be preferred for a broader compatibility with the tools.
|
||||
|
||||
CSS标准中用于 "刺穿Shadow DOM" 的组合器已经被废弃,并将[这个特性从主流浏览器和工具中移除](https://www.chromestatus.com/features/6750456638341120)。
|
||||
因此,我们也将在 Angular 中移除对它们的支持(包括`/deep/`、`>>>` 和 `::ng-deep`)。
|
||||
目前,建议先统一使用`::ng-deep`,以便兼容将来的工具。
|
||||
CSS 标准中用于 "刺穿 Shadow DOM" 的组合器已经被废弃,并将[这个特性从主流浏览器和工具中移除](https://www.chromestatus.com/features/6750456638341120)。
|
||||
因此,我们也将在 Angular 中移除对它们的支持(包括 `/deep/`、`>>>` 和 `::ng-deep`)。
|
||||
目前,建议先统一使用 `::ng-deep`,以便兼容将来的工具。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -230,7 +230,7 @@ There are several ways to add styles to a component:
|
|||
|
||||
* By setting `styles` or `styleUrls` metadata.
|
||||
|
||||
设置`styles`或`styleUrls`元数据
|
||||
设置 `styles` 或 `styleUrls` 元数据
|
||||
|
||||
* Inline in the template HTML.
|
||||
|
||||
|
@ -250,7 +250,7 @@ The scoping rules outlined earlier apply to each of these loading patterns.
|
|||
|
||||
You can add a `styles` array property to the `@Component` decorator.
|
||||
|
||||
我们可以给`@Component`装饰器添加一个`styles`数组型属性。
|
||||
我们可以给 `@Component` 装饰器添加一个 `styles` 数组型属性。
|
||||
|
||||
Each string in the array defines some CSS for this component.
|
||||
|
||||
|
@ -331,7 +331,7 @@ ng generate component hero-app
|
|||
You can embed CSS styles directly into the HTML template by putting them
|
||||
inside `<style>` tags.
|
||||
|
||||
我们也可以在组件的 HTML 模板中嵌入`<style>`标签。
|
||||
我们也可以在组件的 HTML 模板中嵌入 `<style>` 标签。
|
||||
|
||||
<code-example path="component-styles/src/app/hero-controls.component.ts" region="inlinestyles" title="src/app/hero-controls.component.ts">
|
||||
|
||||
|
@ -339,11 +339,11 @@ inside `<style>` tags.
|
|||
|
||||
### Template link tags
|
||||
|
||||
### 模板中的link标签
|
||||
### 模板中的 link 标签
|
||||
|
||||
You can also write `<link>` tags into the component's HTML template.
|
||||
|
||||
我们也可以在组件的 HTML 模板中写`<link>`标签。
|
||||
我们也可以在组件的 HTML 模板中写 `<link>` 标签。
|
||||
|
||||
<code-example path="component-styles/src/app/hero-team.component.ts" region="stylelink" title="src/app/hero-team.component.ts">
|
||||
|
||||
|
@ -370,7 +370,7 @@ You can also import CSS files into the CSS files using the standard CSS `@import
|
|||
For details, see [`@import`](https://developer.mozilla.org/en/docs/Web/CSS/@import)
|
||||
on the [MDN](https://developer.mozilla.org) site.
|
||||
|
||||
我们还可以利用标准的 CSS [`@import`规则](https://developer.mozilla.org/en/docs/Web/CSS/@import)来把其它
|
||||
我们还可以利用标准的 CSS [`@import` 规则](https://developer.mozilla.org/en/docs/Web/CSS/@import)来把其它
|
||||
CSS 文件导入到我们的 CSS 文件中。
|
||||
|
||||
In this case, the URL is relative to the CSS file into which you're importing.
|
||||
|
@ -462,14 +462,14 @@ Choose from the following modes:
|
|||
to attach a shadow DOM to the component's host element, and then puts the component
|
||||
view inside that shadow DOM. The component's styles are included within the shadow DOM.
|
||||
|
||||
`Native`模式使用浏览器原生的 [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM)
|
||||
`Native` 模式使用浏览器原生的 [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM)
|
||||
实现来为组件的宿主元素附加一个 Shadow DOM。组件的样式被包裹在这个 Shadow DOM 中。(译注:不进不出,没有样式能进来,组件样式出不去。)
|
||||
|
||||
* `Emulated` view encapsulation (the default) emulates the behavior of shadow DOM by preprocessing
|
||||
(and renaming) the CSS code to effectively scope the CSS to the component's view.
|
||||
For details, see [Appendix 1](guide/component-styles#inspect-generated-css).
|
||||
|
||||
`Emulated`模式(**默认值**)通过预处理(并改名)CSS 代码来模拟 Shadow DOM 的行为,以达到把 CSS 样式局限在组件视图中的目的。
|
||||
`Emulated` 模式(**默认值**)通过预处理(并改名)CSS 代码来模拟 Shadow DOM 的行为,以达到把 CSS 样式局限在组件视图中的目的。
|
||||
更多信息,见[附录 1](guide/component-styles#inspect-generated-css) 。(译注:只进不出,全局样式能进来,组件样式出不去)
|
||||
|
||||
* `None` means that Angular does no view encapsulation.
|
||||
|
@ -477,13 +477,13 @@ Choose from the following modes:
|
|||
The scoping rules, isolations, and protections discussed earlier don't apply.
|
||||
This is essentially the same as pasting the component's styles into the HTML.
|
||||
|
||||
`None`意味着 Angular 不使用视图封装。
|
||||
`None` 意味着 Angular 不使用视图封装。
|
||||
Angular 会把 CSS 添加到全局样式中。而不会应用上前面讨论过的那些作用域规则、隔离和保护等。
|
||||
从本质上来说,这跟把组件的样式直接放进 HTML 是一样的。(译注:能进能出。)
|
||||
|
||||
To set the components encapsulation mode, use the `encapsulation` property in the component metadata:
|
||||
|
||||
通过组件元数据中的`encapsulation`属性来设置组件封装模式:
|
||||
通过组件元数据中的 `encapsulation` 属性来设置组件封装模式:
|
||||
|
||||
<code-example path="component-styles/src/app/quest-summary.component.ts" region="encapsulation.native" title="src/app/quest-summary.component.ts" linenums="false">
|
||||
|
||||
|
@ -533,20 +533,20 @@ There are two kinds of generated attributes:
|
|||
* An element that would be a shadow DOM host in native encapsulation has a
|
||||
generated `_nghost` attribute. This is typically the case for component host elements.
|
||||
|
||||
一个元素在原生封装方式下可能是 Shadow DOM 的宿主,在这里被自动添加上一个`_nghost`属性。
|
||||
一个元素在原生封装方式下可能是 Shadow DOM 的宿主,在这里被自动添加上一个 `_nghost` 属性。
|
||||
这是组件宿主元素的典型情况。
|
||||
|
||||
* An element within a component's view has a `_ngcontent` attribute
|
||||
that identifies to which host's emulated shadow DOM this element belongs.
|
||||
|
||||
组件视图中的每一个元素,都有一个`_ngcontent`属性,它会标记出该元素是哪个宿主的模拟 Shadow DOM。
|
||||
组件视图中的每一个元素,都有一个 `_ngcontent` 属性,它会标记出该元素是哪个宿主的模拟 Shadow DOM。
|
||||
|
||||
The exact values of these attributes aren't important. They are automatically
|
||||
generated and you never refer to them in application code. But they are targeted
|
||||
by the generated component styles, which are in the `<head>` section of the DOM:
|
||||
|
||||
这些属性的具体值并不重要。它们是自动生成的,并且我们永远不会在程序代码中直接引用到它们。
|
||||
但它们会作为生成的组件样式的目标,就像我们在 DOM 的`<head>`区所看到的:
|
||||
但它们会作为生成的组件样式的目标,就像我们在 DOM 的 `<head>` 区所看到的:
|
||||
|
||||
<code-example format="">
|
||||
|
||||
|
@ -567,5 +567,5 @@ with `_nghost` or `_ngcontent` attribute selectors.
|
|||
These extra selectors enable the scoping rules described in this page.
|
||||
|
||||
|
||||
这些就是我们写的那些样式被处理后的结果,于是每个选择器都被增加了`_nghost`或`_ngcontent`属性选择器。
|
||||
这些就是我们写的那些样式被处理后的结果,于是每个选择器都被增加了 `_nghost` 或 `_ngcontent` 属性选择器。
|
||||
在这些附加选择器的帮助下,我们实现了本指南中所描述的这些作用域规则。
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -49,8 +49,8 @@ This `Car` needs an engine and tires. Instead of asking for them,
|
|||
the `Car` constructor instantiates its own copies from
|
||||
the very specific classes `Engine` and `Tires`.
|
||||
|
||||
`Car`类需要一个引擎 (engine) 和一些轮胎 (tire),它没有去请求现成的实例,
|
||||
而是在构造函数中用具体的`Engine`和`Tires`类实例化出自己的副本。
|
||||
`Car` 类需要一个引擎 (engine) 和一些轮胎 (tire),它没有去请求现成的实例,
|
||||
而是在构造函数中用具体的 `Engine` 和 `Tires` 类实例化出自己的副本。
|
||||
|
||||
What if the `Engine` class evolves and its constructor requires a parameter?
|
||||
That would break the `Car` class and it would stay broken until you rewrote it along the lines of
|
||||
|
@ -61,18 +61,18 @@ But you'll *have* to start caring because
|
|||
when the definition of `Engine` changes, the `Car` class must change.
|
||||
That makes `Car` brittle.
|
||||
|
||||
如果`Engine`类升级了,它的构造函数要求传入一个参数,这该怎么办?
|
||||
这个`Car`类就被破坏了,在把创建引擎的代码重写为`this.engine = new Engine(theNewParameter)`之前,它都是坏的。
|
||||
当第一次写`Car`类时,我们不关心`Engine`构造函数的参数,现在也不想关心。
|
||||
但是,当`Engine`类的定义发生变化时,就不得不在乎了,`Car`类也不得不跟着改变。
|
||||
这就会让`Car`类过于脆弱。
|
||||
如果 `Engine` 类升级了,它的构造函数要求传入一个参数,这该怎么办?
|
||||
这个 `Car` 类就被破坏了,在把创建引擎的代码重写为 `this.engine = new Engine(theNewParameter)` 之前,它都是坏的。
|
||||
当第一次写 `Car` 类时,我们不关心 `Engine` 构造函数的参数,现在也不想关心。
|
||||
但是,当 `Engine` 类的定义发生变化时,就不得不在乎了,`Car` 类也不得不跟着改变。
|
||||
这就会让 `Car` 类过于脆弱。
|
||||
|
||||
What if you want to put a different brand of tires on your `Car`? Too bad.
|
||||
You're locked into whatever brand the `Tires` class creates. That makes the
|
||||
`Car` class inflexible.
|
||||
|
||||
如果想在`Car`上使用不同品牌的轮胎会怎样?太糟了。
|
||||
我们被锁定在`Tires`类创建时使用的那个品牌上。这让`Car`类缺乏弹性。
|
||||
如果想在 `Car` 上使用不同品牌的轮胎会怎样?太糟了。
|
||||
我们被锁定在 `Tires` 类创建时使用的那个品牌上。这让 `Car` 类缺乏弹性。
|
||||
|
||||
Right now each new car gets its own `engine`. It can't share an `engine` with other cars.
|
||||
While that makes sense for an automobile engine,
|
||||
|
@ -90,17 +90,17 @@ What does `Engine` depend upon? What does that dependency depend on?
|
|||
Will a new instance of `Engine` make an asynchronous call to the server?
|
||||
You certainly don't want that going on during tests.
|
||||
|
||||
当给`Car`类写测试的时候,我们就会受制于它背后的那些依赖。
|
||||
能在测试环境中成功创建新的`Engine`吗?
|
||||
`Engine`自己又依赖什么?那些依赖本身又依赖什么?
|
||||
`Engine`的新实例会发起到服务器的异步调用吗?
|
||||
当给 `Car` 类写测试的时候,我们就会受制于它背后的那些依赖。
|
||||
能在测试环境中成功创建新的 `Engine` 吗?
|
||||
`Engine` 自己又依赖什么?那些依赖本身又依赖什么?
|
||||
`Engine` 的新实例会发起到服务器的异步调用吗?
|
||||
我们当然不想在测试期间这么一层层追下去。
|
||||
|
||||
What if the `Car` should flash a warning signal when tire pressure is low?
|
||||
How do you confirm that it actually does flash a warning
|
||||
if you can't swap in low-pressure tires during the test?
|
||||
|
||||
如果`Car`应该在轮胎气压低的时候闪动警示灯该怎么办?
|
||||
如果 `Car` 应该在轮胎气压低的时候闪动警示灯该怎么办?
|
||||
如果没法在测试期间换上一个低气压的轮胎,那该如何确认它能正确的闪警示灯?
|
||||
|
||||
You have no control over the car's hidden dependencies.
|
||||
|
@ -111,13 +111,13 @@ When you can't control the dependencies, a class becomes difficult to test.
|
|||
|
||||
How can you make `Car` more robust, flexible, and testable?
|
||||
|
||||
该如何让`Car`更强壮、有弹性以及可测试?
|
||||
该如何让 `Car` 更强壮、有弹性以及可测试?
|
||||
|
||||
{@a ctor-injection}
|
||||
|
||||
That's super easy. Change the `Car` constructor to a version with DI:
|
||||
|
||||
答案非常简单。把`Car`的构造函数改造成使用 DI 的版本:
|
||||
答案非常简单。把 `Car` 的构造函数改造成使用 DI 的版本:
|
||||
|
||||
<code-tabs>
|
||||
|
||||
|
@ -135,7 +135,7 @@ The `Car` class no longer creates an `engine` or `tires`.
|
|||
It just consumes them.
|
||||
|
||||
发生了什么?我们把依赖的定义移到了构造函数中。
|
||||
`Car`类不再创建引擎`engine`或者轮胎`tires`。
|
||||
`Car` 类不再创建引擎 `engine` 或者轮胎 `tires`。
|
||||
它仅仅“消费”它们。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
@ -161,19 +161,19 @@ decoupled from the `Car` class.
|
|||
You can pass in any kind of `engine` or `tires` you like, as long as they
|
||||
conform to the general API requirements of an `engine` or `tires`.
|
||||
|
||||
酷!引擎和轮胎这两个依赖的定义与`Car`类本身解耦了。
|
||||
酷!引擎和轮胎这两个依赖的定义与 `Car` 类本身解耦了。
|
||||
只要喜欢,可以传入任何类型的引擎或轮胎,只要它们能满足引擎或轮胎的通用 API 需求。
|
||||
|
||||
Now, if someone extends the `Engine` class, that is not `Car`'s problem.
|
||||
|
||||
这样一来,如果有人扩展了`Engine`类,那就不再是`Car`类的烦恼了。
|
||||
这样一来,如果有人扩展了 `Engine` 类,那就不再是 `Car` 类的烦恼了。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
The _consumer_ of `Car` has the problem. The consumer must update the car creation code to
|
||||
something like this:
|
||||
|
||||
`Car`的_消费者_也有这个问题。消费者必须更新创建这辆车的代码,就像这样:
|
||||
`Car` 的_消费者_也有这个问题。消费者必须更新创建这辆车的代码,就像这样:
|
||||
|
||||
<code-example path="dependency-injection/src/app/car/car-creations.ts" region="car-ctor-instantiation-with-param" linenums="false">
|
||||
|
||||
|
@ -182,7 +182,7 @@ something like this:
|
|||
The critical point is this: the `Car` class did not have to change.
|
||||
You'll take care of the consumer's problem shortly.
|
||||
|
||||
这里的要点是:`Car`本身不必变化。下面就来解决消费者的问题。
|
||||
这里的要点是:`Car` 本身不必变化。下面就来解决消费者的问题。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -191,7 +191,7 @@ of its dependencies.
|
|||
You can pass mocks to the constructor that do exactly what you want them to do
|
||||
during each test:
|
||||
|
||||
`Car`类非常容易测试,因为现在我们对它的依赖有了完全的控制权。
|
||||
`Car` 类非常容易测试,因为现在我们对它的依赖有了完全的控制权。
|
||||
在每个测试期间,我们可以往构造函数中传入 mock 对象,做想让它们做的事:
|
||||
|
||||
<code-example path="dependency-injection/src/app/car/car-creations.ts" region="car-ctor-instantiation-with-mocks" linenums="false">
|
||||
|
@ -214,8 +214,8 @@ The `Car` class shed its problems at the consumer's expense.
|
|||
You need something that takes care of assembling these parts.
|
||||
|
||||
酷!但是,可怜的消费者怎么办?
|
||||
那些希望得到一个`Car`的人们现在必须创建所有这三部分了:`Car`、`Engine`和`Tires`。
|
||||
`Car`类把它的快乐建立在了消费者的痛苦之上。
|
||||
那些希望得到一个 `Car` 的人们现在必须创建所有这三部分了:`Car`、`Engine` 和 `Tires`。
|
||||
`Car` 类把它的快乐建立在了消费者的痛苦之上。
|
||||
需要某种机制为我们把这三个部分装配好。
|
||||
|
||||
You _could_ write a giant class to do that:
|
||||
|
@ -250,7 +250,7 @@ You register some classes with this injector, and it figures out how to create t
|
|||
|
||||
When you need a `Car`, you simply ask the injector to get it for you and you're good to go.
|
||||
|
||||
当需要一个`Car`时,就简单的找注入器取车就可以了。
|
||||
当需要一个 `Car` 时,就简单的找注入器取车就可以了。
|
||||
|
||||
<code-example path="dependency-injection/src/app/car/car-injector.ts" region="injector-call" title="src/app/car/car-injector.ts" linenums="false">
|
||||
|
||||
|
@ -261,10 +261,10 @@ The consumer knows nothing about creating a `Car`.
|
|||
You don't have a gigantic factory class to maintain.
|
||||
Both `Car` and consumer simply ask for what they need and the injector delivers.
|
||||
|
||||
皆大欢喜。`Car`不需要知道如何创建`Engine`和`Tires`。
|
||||
消费者不需要知道如何创建`Car`。
|
||||
皆大欢喜。`Car` 不需要知道如何创建 `Engine` 和 `Tires`。
|
||||
消费者不需要知道如何创建 `Car`。
|
||||
开发人员不需要维护巨大的工厂类。
|
||||
`Car`和消费者只要简单地请求想要什么,注入器就会交付它们。
|
||||
`Car` 和消费者只要简单地请求想要什么,注入器就会交付它们。
|
||||
|
||||
This is what a **dependency injection framework** is all about.
|
||||
|
||||
|
|
|
@ -186,7 +186,7 @@ The two most important examples are `@Component` and `@NgModule`.
|
|||
|
||||
Here's a revised `HeroesComponent` that registers the `HeroService` in its `providers` array.
|
||||
|
||||
下面是修改过的`HerosComponent`,把`HeroService`注册到了它的`providers`数组中。
|
||||
下面是修改过的 `HerosComponent`,把 `HeroService` 注册到了它的 `providers` 数组中。
|
||||
|
||||
<code-example path="dependency-injection/src/app/heroes/heroes.component.1.ts" title="src/app/heroes/heroes.component.ts" linenums="false">
|
||||
|
||||
|
@ -428,7 +428,7 @@ Listing dependencies as constructor parameters may be all you need to test appli
|
|||
For example, you can create a new `HeroListComponent` with a mock service that you can manipulate
|
||||
under test:
|
||||
|
||||
例如,新建的`HeroListComponent`实例使用一个模拟 (mock) 服务,以便可以在测试中操纵它:
|
||||
例如,新建的 `HeroListComponent` 实例使用一个模拟 (mock) 服务,以便可以在测试中操纵它:
|
||||
|
||||
<code-example path="dependency-injection/src/app/test.component.ts" region="spec" title="src/app/test.component.ts" linenums="false">
|
||||
|
||||
|
@ -450,14 +450,14 @@ Learn more in the [Testing](guide/testing) guide.
|
|||
|
||||
The `HeroService` is very simple. It doesn't have any dependencies of its own.
|
||||
|
||||
这个`HeroService`非常简单。它本身不需要任何依赖。
|
||||
这个 `HeroService` 非常简单。它本身不需要任何依赖。
|
||||
|
||||
What if it had a dependency? What if it reported its activities through a logging service?
|
||||
You'd apply the same *constructor injection* pattern,
|
||||
adding a constructor that takes a `Logger` parameter.
|
||||
|
||||
如果它也有依赖,该怎么办呢?例如,它需要通过日志服务来汇报自己的活动。
|
||||
我们同样用*构造函数注入*模式,来添加一个带有`Logger`参数的构造函数。
|
||||
我们同样用*构造函数注入*模式,来添加一个带有 `Logger` 参数的构造函数。
|
||||
|
||||
Here is the revised `HeroService` that injects the `Logger`, side-by-side with the previous service for comparison.
|
||||
|
||||
|
@ -476,8 +476,8 @@ Here is the revised `HeroService` that injects the `Logger`, side-by-side with t
|
|||
The constructor asks for an injected instance of a `Logger` and stores it in a private field called `logger`.
|
||||
The `getHeroes()` method logs a message when asked to fetch heroes.
|
||||
|
||||
这个构造函数要求注入一个`Logger`类的实例,并把它存到名为`logger`的私有字段中。
|
||||
当请求英雄数据时,`getHeroes()`中就会记录一个消息。
|
||||
这个构造函数要求注入一个 `Logger` 类的实例,并把它存到名为 `logger` 的私有字段中。
|
||||
当请求英雄数据时,`getHeroes()` 中就会记录一个消息。
|
||||
|
||||
{@a logger-service}
|
||||
|
||||
|
@ -615,8 +615,8 @@ Almost all of the accompanying code snippets are extracts from the sample app's
|
|||
There are many ways to *provide* something that looks and behaves like a `Logger`.
|
||||
The `Logger` class itself is an obvious and natural provider.
|
||||
|
||||
有很多方式可以*提供*一些实现 `Logger`类的东西。
|
||||
`Logger`类本身是一个显而易见而且自然而然的提供商。
|
||||
有很多方式可以*提供*一些实现 `Logger` 类的东西。
|
||||
`Logger` 类本身是一个显而易见而且自然而然的提供商。
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-logger">
|
||||
|
||||
|
@ -631,14 +631,14 @@ You could provide a substitute class. You could provide a logger-like object.
|
|||
You could give it a provider that calls a logger factory function.
|
||||
Any of these approaches might be a good choice under the right circumstances.
|
||||
|
||||
可以用其它备选提供商来配置注入器,只要它们能交付一个行为类似于`Logger`的对象就可以了。
|
||||
可以用其它备选提供商来配置注入器,只要它们能交付一个行为类似于 `Logger` 的对象就可以了。
|
||||
可以提供一个替代类。你可以提供一个类似日志的对象。
|
||||
可以给它一个提供商,让它调用可以创建日志服务的工厂函数。
|
||||
所有这些方法,只要用在正确的场合,都可能是一个好的选择。
|
||||
|
||||
What matters is that the injector has a provider to go to when it needs a `Logger`.
|
||||
|
||||
重点是,当注入器需要一个`Logger`时,它得先有一个提供商。
|
||||
重点是,当注入器需要一个 `Logger` 时,它得先有一个提供商。
|
||||
|
||||
{@a provide}
|
||||
|
||||
|
@ -667,7 +667,7 @@ using a _provider_ object literal with two properties:
|
|||
The `provide` property holds the [token](guide/dependency-injection#token) that serves as the key for both locating a dependency value
|
||||
and registering the provider.
|
||||
|
||||
`provide`属性保存的是[令牌 (token)](guide/dependency-injection#token),它作为键值 (key) 使用,用于定位依赖值和注册提供商。
|
||||
`provide` 属性保存的是[令牌 (token)](guide/dependency-injection#token),它作为键值 (key) 使用,用于定位依赖值和注册提供商。
|
||||
|
||||
The second property is always a provider definition object,
|
||||
which you can think of as a *recipe* for creating the dependency value.
|
||||
|
@ -688,7 +688,7 @@ The following code tells the injector
|
|||
to return a `BetterLogger` when something asks for the `Logger`.
|
||||
|
||||
某些时候,我们会请求一个不同的类来提供服务。
|
||||
下列代码告诉注入器,当有人请求`Logger`时,返回`BetterLogger`。
|
||||
下列代码告诉注入器,当有人请求 `Logger` 时,返回 `BetterLogger`。
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-4" >
|
||||
|
||||
|
@ -704,9 +704,9 @@ Maybe an `EvenBetterLogger` could display the user name in the log message.
|
|||
This logger gets the user from the injected `UserService`,
|
||||
which is also injected at the application level.
|
||||
|
||||
假设`EvenBetterLogger`可以在日志消息中显示用户名。
|
||||
这个日志服务从注入的`UserService`中取得用户,
|
||||
`UserService`通常也会在应用级注入。
|
||||
假设 `EvenBetterLogger` 可以在日志消息中显示用户名。
|
||||
这个日志服务从注入的 `UserService` 中取得用户,
|
||||
`UserService` 通常也会在应用级注入。
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="EvenBetterLogger" linenums="false">
|
||||
|
||||
|
@ -714,7 +714,7 @@ which is also injected at the application level.
|
|||
|
||||
Configure it like `BetterLogger`.
|
||||
|
||||
就像之前在`BetterLogger`中那样配置它。
|
||||
就像之前在 `BetterLogger` 中那样配置它。
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-5" linenums="false">
|
||||
|
||||
|
@ -730,27 +730,27 @@ Suppose an old component depends upon an `OldLogger` class.
|
|||
`OldLogger` has the same interface as the `NewLogger`, but for some reason
|
||||
you can't update the old component to use it.
|
||||
|
||||
假设某个旧组件依赖一个`OldLogger`类。
|
||||
`OldLogger`和`NewLogger`具有相同的接口,但是由于某些原因,
|
||||
假设某个旧组件依赖一个 `OldLogger` 类。
|
||||
`OldLogger` 和 `NewLogger` 具有相同的接口,但是由于某些原因,
|
||||
我们不能升级这个旧组件并使用它。
|
||||
|
||||
When the *old* component logs a message with `OldLogger`,
|
||||
you'd like the singleton instance of `NewLogger` to handle it instead.
|
||||
|
||||
当*旧*组件想使用`OldLogger`记录消息时,我们希望改用`NewLogger`的单例对象来记录。
|
||||
当*旧*组件想使用 `OldLogger` 记录消息时,我们希望改用 `NewLogger` 的单例对象来记录。
|
||||
|
||||
The dependency injector should inject that singleton instance
|
||||
when a component asks for either the new or the old logger.
|
||||
The `OldLogger` should be an alias for `NewLogger`.
|
||||
|
||||
不管组件请求的是新的还是旧的日志服务,依赖注入器注入的都应该是同一个单例对象。
|
||||
也就是说,`OldLogger`应该是`NewLogger`的别名。
|
||||
也就是说,`OldLogger` 应该是 `NewLogger` 的别名。
|
||||
|
||||
You certainly do not want two different `NewLogger` instances in your app.
|
||||
Unfortunately, that's what you get if you try to alias `OldLogger` to `NewLogger` with `useClass`.
|
||||
|
||||
我们当然不会希望应用中有两个不同的`NewLogger`实例。
|
||||
不幸的是,如果尝试通过`useClass`来把`OldLogger`作为`NewLogger`的别名,就会导致这样的后果。
|
||||
我们当然不会希望应用中有两个不同的 `NewLogger` 实例。
|
||||
不幸的是,如果尝试通过 `useClass` 来把 `OldLogger` 作为 `NewLogger` 的别名,就会导致这样的后果。
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-6a" linenums="false">
|
||||
|
||||
|
@ -758,7 +758,7 @@ Unfortunately, that's what you get if you try to alias `OldLogger` to `NewLogger
|
|||
|
||||
The solution: alias with the `useExisting` option.
|
||||
|
||||
解决方案:使用`useExisting`选项指定别名。
|
||||
解决方案:使用 `useExisting` 选项指定别名。
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-6b" linenums="false">
|
||||
|
||||
|
@ -781,7 +781,7 @@ Sometimes it's easier to provide a ready-made object rather than ask the injecto
|
|||
Then you register a provider with the `useValue` option,
|
||||
which makes this object play the logger role.
|
||||
|
||||
于是可以通过`useValue`选项来注册提供商,它会让这个对象直接扮演 logger 的角色。
|
||||
于是可以通过 `useValue` 选项来注册提供商,它会让这个对象直接扮演 logger 的角色。
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-7" linenums="false">
|
||||
|
||||
|
@ -791,7 +791,7 @@ See more `useValue` examples in the
|
|||
[Non-class dependencies](guide/dependency-injection#non-class-dependencies) and
|
||||
[InjectionToken](guide/dependency-injection#injection-token) sections.
|
||||
|
||||
查看更多`useValue`的例子,见[非类依赖](guide/dependency-injection#non-class-dependencies)和 [InjectionToken](guide/dependency-injection#injection-token)部分。
|
||||
查看更多 `useValue` 的例子,见[非类依赖](guide/dependency-injection#non-class-dependencies)和 [InjectionToken](guide/dependency-injection#injection-token)部分。
|
||||
|
||||
{@a factory-provider}
|
||||
|
||||
|
@ -827,7 +827,7 @@ It needs to know if the user is authorized to see secret heroes.
|
|||
That authorization can change during the course of a single application session,
|
||||
as when you log in a different user.
|
||||
|
||||
就像`EvenBetterLogger`那样,`HeroService`需要了解此用户的身份。
|
||||
就像 `EvenBetterLogger` 那样,`HeroService` 需要了解此用户的身份。
|
||||
它需要知道,这个用户是否有权看到隐藏英雄。
|
||||
这个授权可能在单一的应用会话中被改变,例如,改用另一个用户的身份登录时。
|
||||
|
||||
|
@ -835,12 +835,12 @@ Unlike `EvenBetterLogger`, you can't inject the `UserService` into the `HeroServ
|
|||
The `HeroService` won't have direct access to the user information to decide
|
||||
who is authorized and who is not.
|
||||
|
||||
与`EvenBetterLogger`不同,不能把`UserService`注入到`HeroService`中。
|
||||
`HeroService`无权访问用户信息,来决定谁有授权谁没有授权。
|
||||
与 `EvenBetterLogger` 不同,不能把 `UserService` 注入到 `HeroService` 中。
|
||||
`HeroService` 无权访问用户信息,来决定谁有授权谁没有授权。
|
||||
|
||||
Instead, the `HeroService` constructor takes a boolean flag to control display of secret heroes.
|
||||
|
||||
让`HeroService`的构造函数带上一个布尔型的标志,来控制是否显示隐藏的英雄。
|
||||
让 `HeroService` 的构造函数带上一个布尔型的标志,来控制是否显示隐藏的英雄。
|
||||
|
||||
<code-example path="dependency-injection/src/app/heroes/hero.service.ts" region="internals" title="src/app/heroes/hero.service.ts (excerpt)" linenums="false">
|
||||
|
||||
|
@ -849,8 +849,8 @@ Instead, the `HeroService` constructor takes a boolean flag to control display o
|
|||
You can inject the `Logger`, but you can't inject the boolean `isAuthorized`.
|
||||
You'll have to take over the creation of new instances of this `HeroService` with a factory provider.
|
||||
|
||||
我们可以注入`Logger`,但是不能注入逻辑型的`isAuthorized`。
|
||||
我们不得不通过通过工厂提供商创建这个`HeroService`的新实例。
|
||||
我们可以注入 `Logger`,但是不能注入逻辑型的 `isAuthorized`。
|
||||
我们不得不通过通过工厂提供商创建这个 `HeroService` 的新实例。
|
||||
|
||||
A factory provider needs a factory function:
|
||||
|
||||
|
@ -862,12 +862,12 @@ A factory provider needs a factory function:
|
|||
|
||||
Although the `HeroService` has no access to the `UserService`, the factory function does.
|
||||
|
||||
虽然`HeroService`不能访问`UserService`,但是工厂方法可以。
|
||||
虽然 `HeroService` 不能访问 `UserService`,但是工厂方法可以。
|
||||
|
||||
You inject both the `Logger` and the `UserService` into the factory provider
|
||||
and let the injector pass them along to the factory function:
|
||||
|
||||
同时把`Logger`和`UserService`注入到工厂提供商中,并且让注入器把它们传给工厂方法:
|
||||
同时把 `Logger` 和 `UserService` 注入到工厂提供商中,并且让注入器把它们传给工厂方法:
|
||||
|
||||
<code-example path="dependency-injection/src/app/heroes/hero.service.provider.ts" region="provider" title="src/app/heroes/hero.service.provider.ts (excerpt)" linenums="false">
|
||||
|
||||
|
@ -878,14 +878,14 @@ and let the injector pass them along to the factory function:
|
|||
The `useFactory` field tells Angular that the provider is a factory function
|
||||
whose implementation is the `heroServiceFactory`.
|
||||
|
||||
`useFactory`字段告诉 Angular:这个提供商是一个工厂方法,它的实现是`heroServiceFactory`。
|
||||
`useFactory` 字段告诉 Angular:这个提供商是一个工厂方法,它的实现是 `heroServiceFactory`。
|
||||
|
||||
The `deps` property is an array of [provider tokens](guide/dependency-injection#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`属性是[提供商令牌](guide/dependency-injection#token)数组。
|
||||
`Logger`和`UserService`类作为它们自身类提供商的令牌。
|
||||
`deps` 属性是[提供商令牌](guide/dependency-injection#token)数组。
|
||||
`Logger` 和 `UserService` 类作为它们自身类提供商的令牌。
|
||||
注入器解析这些令牌,把相应的服务注入到工厂函数中相应的参数中去。
|
||||
|
||||
</div>
|
||||
|
@ -896,14 +896,14 @@ You can register the `HeroService` with this variable wherever you need it.
|
|||
|
||||
注意,我们在一个导出的变量中捕获了这个工厂提供商:`heroServiceProvider`。
|
||||
这个额外的步骤让工厂提供商可被复用。
|
||||
无论哪里需要,都可以使用这个变量注册`HeroService`。
|
||||
无论哪里需要,都可以使用这个变量注册 `HeroService`。
|
||||
|
||||
In this sample, you need it only in the `HeroesComponent`,
|
||||
where it replaces the previous `HeroService` registration in the metadata `providers` array.
|
||||
Here you see the new and the old implementation side-by-side:
|
||||
|
||||
在这个例子中,只在`HeroesComponent`中需要它,
|
||||
这里,它代替了元数据`providers`数组中原来的`HeroService`注册。
|
||||
在这个例子中,只在 `HeroesComponent` 中需要它,
|
||||
这里,它代替了元数据 `providers` 数组中原来的 `HeroService` 注册。
|
||||
对比一下新的和旧的实现:
|
||||
|
||||
<code-tabs>
|
||||
|
@ -935,7 +935,7 @@ the class *type* served as its own lookup key.
|
|||
Here you get a `HeroService` directly from the injector by supplying the `HeroService` type as the token:
|
||||
|
||||
在前面的所有例子中,依赖值都是一个类*实例*,并且类的*类型*作为它自己的查找键值。
|
||||
在下面的代码中,`HeroService`类型作为令牌,直接从注入器中获取`HeroService` 实例:
|
||||
在下面的代码中,`HeroService` 类型作为令牌,直接从注入器中获取 `HeroService` 实例:
|
||||
|
||||
<code-example path="dependency-injection/src/app/injector.component.ts" region="get-hero-service" title="src/app/injector.component.ts" linenums="false">
|
||||
|
||||
|
@ -947,8 +947,8 @@ Angular knows to inject the
|
|||
service associated with that `HeroService` class token:
|
||||
|
||||
编写需要基于类的依赖注入的构造函数对我们来说是很幸运的。
|
||||
只要定义一个`HeroService`类型的构造函数参数,
|
||||
Angular 就会知道把跟`HeroService`类令牌关联的服务注入进来:
|
||||
只要定义一个 `HeroService` 类型的构造函数参数,
|
||||
Angular 就会知道把跟 `HeroService` 类令牌关联的服务注入进来:
|
||||
|
||||
<code-example path="dependency-injection/src/app/heroes/hero-list.component.ts" region="ctor-signature" title="src/app/heroes/hero-list.component.ts">
|
||||
|
||||
|
@ -974,7 +974,7 @@ Applications often define configuration objects with lots of small facts
|
|||
but these configuration objects aren't always instances of a class.
|
||||
They can be object literals such as this one:
|
||||
|
||||
应用程序经常为很多很小的因素定义配置对象(例如应用程序的标题或网络API终点的地址)。
|
||||
应用程序经常为很多很小的因素定义配置对象(例如应用程序的标题或网络 API 终点的地址)。
|
||||
但是这些配置对象不总是类的实例,它们可能是对象,如下面这个:
|
||||
|
||||
<code-example path="dependency-injection/src/app/app.config.ts" region="config" title="src/app/app.config.ts (excerpt)" linenums="false">
|
||||
|
@ -991,7 +991,7 @@ You don't have a class to serve as a token.
|
|||
There is no `AppConfig` class.
|
||||
|
||||
但是,这种情况下用什么作令牌呢?
|
||||
我们没办法找一个类来当作令牌,因为没有`Config`类。
|
||||
我们没办法找一个类来当作令牌,因为没有 `Config` 类。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
|
@ -1002,7 +1002,7 @@ There is no `AppConfig` class.
|
|||
The `HERO_DI_CONFIG` constant conforms to the `AppConfig` interface.
|
||||
Unfortunately, you cannot use a TypeScript interface as a token:
|
||||
|
||||
`HERO_DI_CONFIG`常量有一个接口:`AppConfig`。不幸的是,不能把 TypeScript 接口用作令牌:
|
||||
`HERO_DI_CONFIG` 常量有一个接口:`AppConfig`。不幸的是,不能把 TypeScript 接口用作令牌:
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-9-interface" linenums="false">
|
||||
|
||||
|
@ -1053,7 +1053,7 @@ The token description is another developer aid.
|
|||
|
||||
Register the dependency provider using the `InjectionToken` object:
|
||||
|
||||
使用这个`InjectionToken`对象注册依赖的提供商:
|
||||
使用这个 `InjectionToken` 对象注册依赖的提供商:
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-9" linenums="false">
|
||||
|
||||
|
@ -1062,7 +1062,7 @@ Register the dependency provider using the `InjectionToken` object:
|
|||
Now you can inject the configuration object into any constructor that needs it, with
|
||||
the help of an `@Inject` decorator:
|
||||
|
||||
现在,在`@Inject`装饰器的帮助下,这个配置对象可以注入到任何需要它的构造函数中:
|
||||
现在,在 `@Inject` 装饰器的帮助下,这个配置对象可以注入到任何需要它的构造函数中:
|
||||
|
||||
<code-example path="dependency-injection/src/app/app.component.2.ts" region="ctor" title="src/app/app.component.ts" linenums="false">
|
||||
|
||||
|
@ -1073,13 +1073,13 @@ the help of an `@Inject` decorator:
|
|||
Although the `AppConfig` interface plays no role in dependency injection,
|
||||
it supports typing of the configuration object within the class.
|
||||
|
||||
虽然`AppConfig`接口在依赖注入过程中没有任何作用,但它为该类中的配置对象提供了强类型信息。
|
||||
虽然 `AppConfig` 接口在依赖注入过程中没有任何作用,但它为该类中的配置对象提供了强类型信息。
|
||||
|
||||
</div>
|
||||
|
||||
Alternatively, you can provide and inject the configuration object in an ngModule like `AppModule`.
|
||||
|
||||
或者在 ngModule 中提供并注入这个配置对象,如`AppModule`。
|
||||
或者在 ngModule 中提供并注入这个配置对象,如 `AppModule`。
|
||||
|
||||
<code-example path="dependency-injection/src/app/app.module.ts" region="providers" title="src/app/app.module.ts (providers)"></code-example>
|
||||
|
||||
|
@ -1094,8 +1094,8 @@ a `logger`?
|
|||
You can tell Angular that the dependency is optional by annotating the
|
||||
constructor argument with `@Optional()`:
|
||||
|
||||
`HeroService`*需要*一个`Logger`,但是如果想不提供 Logger 也能得到它,该怎么办呢?
|
||||
可以把构造函数的参数标记为`@Optional()`,告诉 Angular 该依赖是可选的:
|
||||
`HeroService`*需要*一个 `Logger`,但是如果想不提供 Logger 也能得到它,该怎么办呢?
|
||||
可以把构造函数的参数标记为 `@Optional()`,告诉 Angular 该依赖是可选的:
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="import-optional">
|
||||
|
||||
|
@ -1109,8 +1109,8 @@ When using `@Optional()`, your code must be prepared for a null value. If you
|
|||
don't register a `logger` somewhere up the line, the injector will set the
|
||||
value of `logger` to null.
|
||||
|
||||
当使用`@Optional()`时,代码必须准备好如何处理空值。
|
||||
如果其它的代码没有注册一个 `logger`,注入器会设置该`logger`的值为空 null。
|
||||
当使用 `@Optional()` 时,代码必须准备好如何处理空值。
|
||||
如果其它的代码没有注册一个 `logger`,注入器会设置该 `logger` 的值为空 null。
|
||||
|
||||
## Summary
|
||||
|
||||
|
@ -1141,7 +1141,7 @@ Angular 依赖注入比前面描述的更能干。
|
|||
Developers rarely work directly with an injector, but
|
||||
here's an `InjectorComponent` that does.
|
||||
|
||||
这里的`InjectorComponent`直接使用了注入器,
|
||||
这里的 `InjectorComponent` 直接使用了注入器,
|
||||
但我们很少直接使用它。
|
||||
|
||||
<code-example path="dependency-injection/src/app/injector.component.ts" region="injector" title="src/app/injector.component.ts">
|
||||
|
@ -1150,25 +1150,25 @@ here's an `InjectorComponent` that does.
|
|||
|
||||
An `Injector` is itself an injectable service.
|
||||
|
||||
`Injector`本身是可注入的服务。
|
||||
`Injector` 本身是可注入的服务。
|
||||
|
||||
In this example, Angular injects the component's own `Injector` into the component's constructor.
|
||||
The component then asks the injected injector for the services it wants in `ngOnInit()`.
|
||||
|
||||
在这个例子中,Angular 把组件自身的`Injector`注入到了组件的构造函数中。
|
||||
然后,组件在`ngOnInit()`中向注入的注入器请求它所需的服务。
|
||||
在这个例子中,Angular 把组件自身的 `Injector` 注入到了组件的构造函数中。
|
||||
然后,组件在 `ngOnInit()` 中向注入的注入器请求它所需的服务。
|
||||
|
||||
Note that the services themselves are not injected into the component.
|
||||
They are retrieved by calling `injector.get()`.
|
||||
|
||||
注意,这些服务本身没有注入到组件,它们是通过调用`injector.get()`获得的。
|
||||
注意,这些服务本身没有注入到组件,它们是通过调用 `injector.get()` 获得的。
|
||||
|
||||
The `get()` method throws an error if it can't resolve the requested service.
|
||||
You can call `get()` with a second parameter, which is the value to return if the service
|
||||
is not found. Angular can't find the service if it's not registered with this or any ancestor injector.
|
||||
|
||||
`get()`方法如果不能解析所请求的服务,会抛出异常。
|
||||
调用`get()`时,还可以使用第二个参数,一旦获取的服务没有在当前或任何祖先注入器中注册过,
|
||||
`get()` 方法如果不能解析所请求的服务,会抛出异常。
|
||||
调用 `get()` 时,还可以使用第二个参数,一旦获取的服务没有在当前或任何祖先注入器中注册过,
|
||||
就把它作为返回值。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
@ -1217,7 +1217,7 @@ the `HeroesComponent` in the same file,
|
|||
If you define the component before the service,
|
||||
you'll get a runtime null reference error.
|
||||
|
||||
如果我们蔑视这个建议,并且 —— 比如说 —— 把`HeroService`和`HeroesComponent`组合在同一个文件里,
|
||||
如果我们蔑视这个建议,并且 —— 比如说 —— 把 `HeroService` 和 `HeroesComponent` 组合在同一个文件里,
|
||||
**就得把组件定义放在最后面!**
|
||||
如果把组件定义在了服务的前面,
|
||||
在运行时抛出空指针错误。
|
||||
|
@ -1227,7 +1227,7 @@ you'll get a runtime null reference error.
|
|||
You actually can define the component first with the help of the `forwardRef()` method as explained
|
||||
in this [blog post](http://blog.thoughtram.io/angular/2015/09/03/forward-references-in-angular-2.html).
|
||||
|
||||
在`forwardRef()`方法的帮助下,实际上也可以先定义组件,
|
||||
在 `forwardRef()` 方法的帮助下,实际上也可以先定义组件,
|
||||
具体说明见这篇[博客](http://blog.thoughtram.io/angular/2015/09/03/forward-references-in-angular-2.html)。
|
||||
|
||||
But it's best to avoid the problem altogether by defining components and services in separate files.
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
This page describes techniques for deploying your Angular application to a remote server.
|
||||
|
||||
本章会描述在远程服务器上部署Angular应用的工具与技术。
|
||||
本章会描述在远程服务器上部署 Angular 应用的工具与技术。
|
||||
|
||||
{@a dev-deploy}
|
||||
|
||||
|
@ -30,11 +30,11 @@ For the simplest deployment, build for development and copy the output directory
|
|||
|
||||
2. Copy _everything_ within the output folder (`dist/` by default) to a folder on the server.
|
||||
|
||||
把输出目录(默认为`dist/`)下的*每个文件*都复制到到服务器上的某个目录下。
|
||||
把输出目录(默认为 `dist/`)下的*每个文件*都复制到到服务器上的某个目录下。
|
||||
|
||||
3. If you copy the files into a server _sub-folder_, append the build flag, `--base-href` and set the `<base href>` appropriately.<br><br>
|
||||
|
||||
如果要把文件部署到服务器上的*某个子路径*下,构建时还要添加`--base-href`(基地址)标识,并设置合适的`<base href>`。<br><br>
|
||||
如果要把文件部署到服务器上的*某个子路径*下,构建时还要添加 `--base-href`(基地址)标识,并设置合适的 `<base href>`。<br><br>
|
||||
|
||||
For example, if the `index.html` is on the server at `/my/app/index.html`, set the _base href_ to
|
||||
`<base href="/my/app/">` like this.
|
||||
|
@ -145,7 +145,7 @@ for details about available build options and what they do.
|
|||
Angular apps run in development mode by default, as you can see by the following message on the browser
|
||||
console:
|
||||
|
||||
Angular应用默认运行在开发模式下,正如在浏览器控制台中看到的如下信息:
|
||||
Angular 应用默认运行在开发模式下,正如在浏览器控制台中看到的如下信息:
|
||||
|
||||
<code-example format="nocode">
|
||||
|
||||
|
@ -179,7 +179,7 @@ Configure the Angular Router to defer loading of all other modules (and their as
|
|||
or by [_lazy loading_](guide/router#asynchronous-routing "Lazy loading")
|
||||
them on demand.
|
||||
|
||||
配置Angular路由器可以延迟加载所有其它模块(以及与它们相关的代码),无论是[等应用启动](guide/router#preloading "Preloading"),
|
||||
配置 Angular 路由器可以延迟加载所有其它模块(以及与它们相关的代码),无论是[等应用启动](guide/router#preloading "Preloading"),
|
||||
还是在需要时才[惰性加载](guide/router#asynchronous-routing "Lazy loading")。
|
||||
|
||||
#### Don't eagerly import something from a lazy loaded module
|
||||
|
@ -193,7 +193,7 @@ in a file that's eagerly loaded when the app starts, a file such as the root `Ap
|
|||
If you do that, the module will be loaded immediately.
|
||||
|
||||
这是一种常犯的错误。
|
||||
我们本打算惰性加载一个模块,但可能无意中在根模块`AppModule`文件中使用一个JavaScript的`import`语句导入了它。
|
||||
我们本打算惰性加载一个模块,但可能无意中在根模块 `AppModule` 文件中使用一个 JavaScript 的 `import` 语句导入了它。
|
||||
这样一来,该模块就被立即加载了。
|
||||
|
||||
The bundling configuration must take lazy loading into consideration.
|
||||
|
@ -202,7 +202,7 @@ Bundlers don't know about the router configuration and won't create separate bun
|
|||
You have to create these bundles manually.
|
||||
|
||||
关于打包(bundle)方式的配置必须考虑到惰性加载问题。
|
||||
因为惰性加载模块不能在JavaScript中导入(就像刚才说明的),打包器应该默认排除它们。
|
||||
因为惰性加载模块不能在 JavaScript 中导入(就像刚才说明的),打包器应该默认排除它们。
|
||||
打包器不知道路由器的配置,并且不会为延迟加载模块创建单独的包。
|
||||
我们不得不手动创建这些包。
|
||||
|
||||
|
@ -234,7 +234,7 @@ The
|
|||
Chrome DevTools Network Performance page</a> is a good place to start learning about measuring performance.
|
||||
|
||||
<p><a href="https://developers.google.com/web/tools/chrome-devtools/network-performance/understanding-resource-timing" target="_blank" title="Chrome DevTools Network Performance">
|
||||
Chrome开发工具的网络性能页</a>是开始学习度量性能的好地方。</p>
|
||||
Chrome 开发工具的网络性能页</a>是开始学习度量性能的好地方。</p>
|
||||
|
||||
The [WebPageTest](https://www.webpagetest.org/) tool is another good choice
|
||||
that can also help verify that your deployment was successful.
|
||||
|
@ -319,9 +319,9 @@ For example, given the `<base href="/my/app/">`, the browser resolves a URL such
|
|||
into a server request for `my/app/some/place/foo.jpg`.
|
||||
During navigation, the Angular router uses the _base href_ as the base path to component, template, and module files.
|
||||
|
||||
HTML中的[_<base href="..."/>_](https://angular.io/docs/ts/latest/guide/router.html#!)用于指定一个解析相对路径的基地址,如图片、脚本和样式表。
|
||||
比如,指定`<base href="/my/app/">`时,浏览器就会把`some/place/foo.jpg`这样的URL解析成到`my/app/some/place/foo.jpg`的服务端请求。
|
||||
在浏览期间,Angular路由器会使用*base href*作为组件、模板和模块文件的基地址。
|
||||
HTML 中的[_<base href="..."/>_](https://angular.io/docs/ts/latest/guide/router.html#!)用于指定一个解析相对路径的基地址,如图片、脚本和样式表。
|
||||
比如,指定 `<base href="/my/app/">` 时,浏览器就会把 `some/place/foo.jpg` 这样的 URL 解析成到 `my/app/some/place/foo.jpg` 的服务端请求。
|
||||
在浏览期间,Angular 路由器会使用*base href*作为组件、模板和模块文件的基地址。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
|
@ -334,14 +334,14 @@ See also the [*APP_BASE_HREF*](api/common/APP_BASE_HREF "API: APP_BASE_HREF") al
|
|||
In development, you typically start the server in the folder that holds `index.html`.
|
||||
That's the root folder and you'd add `<base href="/">` near the top of `index.html` because `/` is the root of the app.
|
||||
|
||||
在开发期间,我们通常会在`index.html`所在的目录中启动服务器。这个目录就是根目录,因为`/`就是本应用的根,所以我们要在`index.html`的顶部添加`<base href="/">`。
|
||||
在开发期间,我们通常会在 `index.html` 所在的目录中启动服务器。这个目录就是根目录,因为 `/` 就是本应用的根,所以我们要在 `index.html` 的顶部添加 `<base href="/">`。
|
||||
|
||||
But on the shared or production server, you might serve the app from a subfolder.
|
||||
For example, when the URL to load the app is something like `http://www.mysite.com/my/app/`,
|
||||
the subfolder is `my/app/` and you should add `<base href="/my/app/">` to the server version of the `index.html`.
|
||||
|
||||
但是在共享服务器或生产服务器上,我们可能得从子目录下启动服务器。
|
||||
比如,当加载本应用的URL是`http://www.mysite.com/my/app/`时,子目录就是`my/app/`,而我们就要在服务器版的`index.html`中添加`<base href="/my/app/">`。
|
||||
比如,当加载本应用的 URL 是 `http://www.mysite.com/my/app/` 时,子目录就是 `my/app/`,而我们就要在服务器版的 `index.html` 中添加 `<base href="/my/app/">`。
|
||||
|
||||
When the `base` tag is mis-configured, the app fails to load and the browser console displays `404 - Not Found` errors
|
||||
for the missing files. Look at where it _tried_ to find those files and adjust the base tag appropriately.
|
||||
|
@ -415,19 +415,19 @@ This section covers changes you may have make to the server or to files deployed
|
|||
|
||||
### Routed apps must fallback to `index.html`
|
||||
|
||||
### 带路由的应用必须以`index.html`作为后备页面
|
||||
### 带路由的应用必须以 `index.html` 作为后备页面
|
||||
|
||||
Angular apps are perfect candidates for serving with a simple static HTML server.
|
||||
You don't need a server-side engine to dynamically compose application pages because
|
||||
Angular does that on the client-side.
|
||||
|
||||
Angular应用很适合用简单的静态HTML服务器提供服务。
|
||||
我们不需要服务端引擎来动态合成应用页面,因为Angular会在客户端完成这件事。
|
||||
Angular 应用很适合用简单的静态 HTML 服务器提供服务。
|
||||
我们不需要服务端引擎来动态合成应用页面,因为 Angular 会在客户端完成这件事。
|
||||
|
||||
If the app uses the Angular router, you must configure the server
|
||||
to return the application's host page (`index.html`) when asked for a file that it does not have.
|
||||
|
||||
如果该应用使用Angular路由器,我们就必须配置服务器,让它对不存在的文件返回应用的宿主页(`index.html`)。
|
||||
如果该应用使用 Angular 路由器,我们就必须配置服务器,让它对不存在的文件返回应用的宿主页(`index.html`)。
|
||||
|
||||
{@a deep-link}
|
||||
|
||||
|
@ -437,14 +437,14 @@ For example, `http://www.mysite.com/heroes/42` is a _deep link_ to the hero deta
|
|||
that displays the hero with `id: 42`.
|
||||
|
||||
带路由的应用应该支持“深链接”。
|
||||
所谓*深链接*就是指一个URL,它用于指定到应用内某个组件的路径。
|
||||
比如,`http://www.mysite.com/heroes/42`就是一个到英雄详情页面的*深链接*,用于显示`id: 42`的英雄。
|
||||
所谓*深链接*就是指一个 URL,它用于指定到应用内某个组件的路径。
|
||||
比如,`http://www.mysite.com/heroes/42` 就是一个到英雄详情页面的*深链接*,用于显示 `id: 42` 的英雄。
|
||||
|
||||
There is no issue when the user navigates to that URL from within a running client.
|
||||
The Angular router interprets the URL and routes to that page and hero.
|
||||
|
||||
当用户从运行中的客户端应用导航到这个URL时,这没问题。
|
||||
Angular路由器会拦截这个URL,并且把它路由到正确的页面。
|
||||
当用户从运行中的客户端应用导航到这个 URL 时,这没问题。
|
||||
Angular 路由器会拦截这个 URL,并且把它路由到正确的页面。
|
||||
|
||||
But clicking a link in an email, entering it in the browser address bar,
|
||||
or merely refreshing the browser while on the hero detail page —
|
||||
|
@ -452,14 +452,14 @@ all of these actions are handled by the browser itself, _outside_ the running ap
|
|||
The browser makes a direct request to the server for that URL, bypassing the router.
|
||||
|
||||
但是,当从邮件中点击链接或在浏览器地址栏中输入它或仅仅在英雄详情页刷新下浏览器时,所有这些操作都是由浏览器本身处理的,在应用的控制范围之外。
|
||||
浏览器会直接向服务器请求那个URL,路由器没机会插手。
|
||||
浏览器会直接向服务器请求那个 URL,路由器没机会插手。
|
||||
|
||||
A static server routinely returns `index.html` when it receives a request for `http://www.mysite.com/`.
|
||||
But it rejects `http://www.mysite.com/heroes/42` and returns a `404 - Not Found` error *unless* it is
|
||||
configured to return `index.html` instead.
|
||||
|
||||
静态服务器会在收到对`http://www.mysite.com/`的请求时返回`index.html`,但是会拒绝对`http://www.mysite.com/heroes/42`的请求,
|
||||
并返回一个`404 - Not Found`错误,除非,我们把它配置成转而返回`index.html`。
|
||||
静态服务器会在收到对 `http://www.mysite.com/` 的请求时返回 `index.html`,但是会拒绝对 `http://www.mysite.com/heroes/42` 的请求,
|
||||
并返回一个 `404 - Not Found` 错误,除非,我们把它配置成转而返回 `index.html`。
|
||||
|
||||
#### Fallback configuration examples
|
||||
|
||||
|
@ -480,12 +480,12 @@ The list is by no means exhaustive, but should provide you with a good starting
|
|||
* [Lite-Server](https://github.com/johnpapa/lite-server): the default dev server installed with the
|
||||
[Quickstart repo](https://github.com/angular/quickstart) is pre-configured to fallback to `index.html`.
|
||||
|
||||
[Lite-Server](https://github.com/johnpapa/lite-server)是["快速上手"仓库](https://github.com/angular/quickstart)中安装的默认开发服务器,它被预先配置为回退到`index.html`。
|
||||
[Lite-Server](https://github.com/johnpapa/lite-server)是["快速上手"仓库](https://github.com/angular/quickstart)中安装的默认开发服务器,它被预先配置为回退到 `index.html`。
|
||||
|
||||
* [Webpack-Dev-Server](https://github.com/webpack/webpack-dev-server): setup the
|
||||
`historyApiFallback` entry in the dev server options as follows:
|
||||
|
||||
[Webpack-Dev-Server](https://github.com/webpack/webpack-dev-server)在开发服务器的配置中设置了`historyApiFallback`,代码如下:
|
||||
[Webpack-Dev-Server](https://github.com/webpack/webpack-dev-server)在开发服务器的配置中设置了 `historyApiFallback`,代码如下:
|
||||
|
||||
<code-example>
|
||||
|
||||
|
@ -504,7 +504,7 @@ The list is by no means exhaustive, but should provide you with a good starting
|
|||
[rewrite rule](http://httpd.apache.org/docs/current/mod/mod_rewrite.html) to the `.htaccess` file as shown
|
||||
(https://ngmilk.rocks/2015/03/09/angularjs-html5-mode-or-pretty-urls-on-apache-using-htaccess/):
|
||||
|
||||
[Apache](https://httpd.apache.org/):在`.htaccess`文件中添加一个[重写规则](http://httpd.apache.org/docs/current/mod/mod_rewrite.html),
|
||||
[Apache](https://httpd.apache.org/):在 `.htaccess` 文件中添加一个[重写规则](http://httpd.apache.org/docs/current/mod/mod_rewrite.html),
|
||||
代码如下([出处](https://ngmilk.rocks/2015/03/09/angularjs-html5-mode-or-pretty-urls-on-apache-using-htaccess/)):
|
||||
|
||||
<code-example format=".">
|
||||
|
@ -524,7 +524,7 @@ The list is by no means exhaustive, but should provide you with a good starting
|
|||
[Front Controller Pattern Web Apps](https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#front-controller-pattern-web-apps),
|
||||
modified to serve `index.html`:
|
||||
|
||||
[NGinx](http://nginx.org/):使用`try_files`指向`index.html`,详细描述见[Web应用的前端控制器模式](https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#front-controller-pattern-web-apps)。
|
||||
[NGinx](http://nginx.org/):使用 `try_files` 指向 `index.html`,详细描述见[Web 应用的前端控制器模式](https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#front-controller-pattern-web-apps)。
|
||||
|
||||
<code-example format=".">
|
||||
|
||||
|
@ -535,7 +535,7 @@ modified to serve `index.html`:
|
|||
* [IIS](https://www.iis.net/): add a rewrite rule to `web.config`, similar to the one shown
|
||||
[here](http://stackoverflow.com/a/26152011/2116927):
|
||||
|
||||
[IIS](https://www.iis.net/):往`web.config`中添加一条重写规则,类似于[这里](http://stackoverflow.com/a/26152011/2116927):
|
||||
[IIS](https://www.iis.net/):往 `web.config` 中添加一条重写规则,类似于[这里](http://stackoverflow.com/a/26152011/2116927):
|
||||
|
||||
<code-example format='.'>
|
||||
|
||||
|
@ -566,15 +566,15 @@ It's also a good idea to
|
|||
and to
|
||||
[create a `.nojekyll` file](https://www.bennadel.com/blog/3181-including-node-modules-and-vendors-folders-in-your-github-pages-site.htm)
|
||||
|
||||
[GitHub页面服务](https://pages.github.com/):我们没办法[直接配置](https://github.com/isaacs/github/issues/408) Github的页面服务,但可以添加一个404页,只要把`index.html`复制到`404.html`就可以了。
|
||||
它仍然会给出一个404响应,但是浏览器将会正确处理该页,并正常加载该应用。
|
||||
使用[在主分支的`docs/`下启动服务](https://help.github.com/articles/configuring-a-publishing-source-for-github-pages/#publishing-your-github-pages-site-from-a-docs-folder-on-your-master-branch)
|
||||
并[创建一个`.nojekyll`文件](https://www.bennadel.com/blog/3181-including-node-modules-and-vendors-folders-in-your-github-pages-site.htm)也是一个好办法。
|
||||
[GitHub 页面服务](https://pages.github.com/):我们没办法[直接配置](https://github.com/isaacs/github/issues/408) Github 的页面服务,但可以添加一个 404 页,只要把 `index.html` 复制到 `404.html` 就可以了。
|
||||
它仍然会给出一个 404 响应,但是浏览器将会正确处理该页,并正常加载该应用。
|
||||
使用[在主分支的 `docs/` 下启动服务](https://help.github.com/articles/configuring-a-publishing-source-for-github-pages/#publishing-your-github-pages-site-from-a-docs-folder-on-your-master-branch)
|
||||
并[创建一个 `.nojekyll` 文件](https://www.bennadel.com/blog/3181-including-node-modules-and-vendors-folders-in-your-github-pages-site.htm)也是一个好办法。
|
||||
|
||||
* [Firebase hosting](https://firebase.google.com/docs/hosting/): add a
|
||||
[rewrite rule](https://firebase.google.com/docs/hosting/url-redirects-rewrites#section-rewrites).
|
||||
|
||||
[Firebase主机服务](https://firebase.google.com/docs/hosting/):添加一条[重写规则](https://firebase.google.com/docs/hosting/url-redirects-rewrites#section-rewrites)。
|
||||
[Firebase 主机服务](https://firebase.google.com/docs/hosting/):添加一条[重写规则](https://firebase.google.com/docs/hosting/url-redirects-rewrites#section-rewrites)。
|
||||
|
||||
<code-example format=".">
|
||||
|
||||
|
@ -597,7 +597,7 @@ Angular developers may encounter a
|
|||
to a server other than the application's own host server.
|
||||
Browsers forbid such requests unless the server permits them explicitly.
|
||||
|
||||
Angular开发者在向与该应用的宿主服务器不同域的服务器发起请求时,可能会遇到一种<a href="https://en.wikipedia.org/wiki/Cross-origin_resource_sharing" target="_blank" title="Cross-origin resource sharing"><i>跨域资源共享(CORS)</i></a>错误。
|
||||
Angular 开发者在向与该应用的宿主服务器不同域的服务器发起请求时,可能会遇到一种<a href="https://en.wikipedia.org/wiki/Cross-origin_resource_sharing" target="_blank" title="Cross-origin resource sharing"><i>跨域资源共享(CORS)</i></a>错误。
|
||||
浏览器会阻止该请求,除非得到那台服务器的明确许可。
|
||||
|
||||
There isn't anything the client application can do about these errors.
|
||||
|
@ -608,4 +608,4 @@ Read about how to enable CORS for specific servers at
|
|||
|
||||
客户端应用对这种错误无能为力。
|
||||
服务器必须配置成可以接受来自该应用的请求。
|
||||
要了解如何对特定的服务器开启CORS,参见<a href="http://enable-cors.org/server.html" target="_blank" title="Enabling CORS server">enable-cors.org</a>。
|
||||
要了解如何对特定的服务器开启 CORS,参见<a href="http://enable-cors.org/server.html" target="_blank" title="Enabling CORS server">enable-cors.org</a>。
|
||||
|
|
|
@ -41,7 +41,7 @@ is to bind the property name through interpolation.
|
|||
With interpolation, you put the property name in the view template, enclosed in double curly braces: `{{myHero}}`.
|
||||
|
||||
要显示组件的属性,最简单的方式就是通过插值表达式 (interpolation) 来绑定属性名。
|
||||
要使用插值表达式,就把属性名包裹在双花括号里放进视图模板,如`{{myHero}}`。
|
||||
要使用插值表达式,就把属性名包裹在双花括号里放进视图模板,如 `{{myHero}}`。
|
||||
|
||||
Follow the [quickstart](guide/quickstart) instructions for creating a new project
|
||||
named <code>displaying-data</code>.
|
||||
|
@ -55,7 +55,7 @@ Delete the <code>app.component.html</code> file. It is not needed for this examp
|
|||
Then modify the <code>app.component.ts</code> file by
|
||||
changing the template and the body of the component.
|
||||
|
||||
然后,到`app.component.ts`文件中修改组件的模板和代码。
|
||||
然后,到 `app.component.ts` 文件中修改组件的模板和代码。
|
||||
|
||||
When you're done, it should look like this:
|
||||
|
||||
|
@ -67,7 +67,7 @@ When you're done, it should look like this:
|
|||
|
||||
You added two properties to the formerly empty component: `title` and `myHero`.
|
||||
|
||||
再把两个属性`title`和`myHero`添加到之前空白的组件中。
|
||||
再把两个属性 `title` 和 `myHero` 添加到之前空白的组件中。
|
||||
|
||||
The template displays the two component properties using double curly brace
|
||||
interpolation:
|
||||
|
@ -95,7 +95,7 @@ Angular automatically pulls the value of the `title` and `myHero` properties fro
|
|||
inserts those values into the browser. Angular updates the display
|
||||
when these properties change.
|
||||
|
||||
Angular 自动从组件中提取`title`和`myHero`属性的值,并且把这些值插入浏览器中。当这些属性发生变化时,Angular 就会自动刷新显示。
|
||||
Angular 自动从组件中提取 `title` 和 `myHero` 属性的值,并且把这些值插入浏览器中。当这些属性发生变化时,Angular 就会自动刷新显示。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
|
@ -109,13 +109,13 @@ the view, such as a keystroke, a timer completion, or a response to an HTTP requ
|
|||
Notice that you don't call **new** to create an instance of the `AppComponent` class.
|
||||
Angular is creating an instance for you. How?
|
||||
|
||||
注意,我们没有调用 **new** 来创建`AppComponent`类的实例,是 Angular 替我们创建了它。那么它是如何创建的呢?
|
||||
注意,我们没有调用 **new** 来创建 `AppComponent` 类的实例,是 Angular 替我们创建了它。那么它是如何创建的呢?
|
||||
|
||||
The CSS `selector` in the `@Component` decorator specifies an element named `<app-root>`.
|
||||
That element is a placeholder in the body of your `index.html` file:
|
||||
|
||||
注意`@Component`装饰器中指定的 CSS 选择器`selector`,它指定了一个叫`my-app`的元素。
|
||||
该元素是`index.html`的`body`里的占位符。
|
||||
注意 `@Component` 装饰器中指定的 CSS 选择器 `selector`,它指定了一个叫 `my-app` 的元素。
|
||||
该元素是 `index.html` 的 `body` 里的占位符。
|
||||
|
||||
<code-example path="displaying-data/src/index.html" linenums="false" title="src/index.html (body)" region="body">
|
||||
|
||||
|
@ -125,8 +125,8 @@ When you bootstrap with the `AppComponent` class (in <code>main.ts</code>), Angu
|
|||
in the `index.html`, finds it, instantiates an instance of `AppComponent`, and renders it
|
||||
inside the `<app-root>` tag.
|
||||
|
||||
当我们通过`main.ts`中的`AppComponent`类启动时,Angular 在`index.html`中查找一个`<app-root>`元素,
|
||||
然后实例化一个`AppComponent`,并将其渲染到`<app-root>`标签中。
|
||||
当我们通过 `main.ts` 中的 `AppComponent` 类启动时,Angular 在 `index.html` 中查找一个 `<app-root>` 元素,
|
||||
然后实例化一个 `AppComponent`,并将其渲染到 `<app-root>` 标签中。
|
||||
|
||||
Now run the app. It should display the title and hero name:
|
||||
|
||||
|
@ -150,8 +150,8 @@ the template in a separate HTML file and link to it in
|
|||
the component metadata using the `@Component` decorator's `templateUrl` property.
|
||||
|
||||
你可以在两种地方存放组件模板。
|
||||
你可以使用`template`属性把它定义为*内联*的,或者把模板定义在一个独立的 HTML 文件中,
|
||||
再通过`@Component`装饰器中的`templateUrl`属性,
|
||||
你可以使用 `template` 属性把它定义为*内联*的,或者把模板定义在一个独立的 HTML 文件中,
|
||||
再通过 `@Component` 装饰器中的 `templateUrl` 属性,
|
||||
在组件元数据中把它链接到组件。
|
||||
|
||||
The choice between inline and separate HTML is a matter of taste,
|
||||
|
@ -204,7 +204,7 @@ This app uses more terse "variable assignment" style simply for brevity.
|
|||
|
||||
To display a list of heroes, begin by adding an array of hero names to the component and redefine `myHero` to be the first name in the array.
|
||||
|
||||
要显示一个英雄列表,先向组件中添加一个英雄名字数组,然后把`myHero`重定义为数组中的第一个名字。
|
||||
要显示一个英雄列表,先向组件中添加一个英雄名字数组,然后把 `myHero` 重定义为数组中的第一个名字。
|
||||
|
||||
<code-example path="displaying-data/src/app/app.component.2.ts" linenums="false" title="src/app/app.component.ts (class)" region="class">
|
||||
|
||||
|
@ -213,7 +213,7 @@ To display a list of heroes, begin by adding an array of hero names to the compo
|
|||
Now use the Angular `ngFor` directive in the template to display
|
||||
each item in the `heroes` list.
|
||||
|
||||
接着,在模板中使用 Angular 的`ngFor`指令来显示`heroes`列表中的每一项。
|
||||
接着,在模板中使用 Angular 的 `ngFor` 指令来显示 `heroes` 列表中的每一项。
|
||||
|
||||
<code-example path="displaying-data/src/app/app.component.2.ts" linenums="false" title="src/app/app.component.ts (template)" region="template">
|
||||
|
||||
|
@ -223,8 +223,8 @@ This UI uses the HTML unordered list with `<ul>` and `<li>` tags. The `*ngFor`
|
|||
in the `<li>` element is the Angular "repeater" directive.
|
||||
It marks that `<li>` element (and its children) as the "repeater template":
|
||||
|
||||
这个界面使用了由`<ul>`和`<li>`标签组成的无序列表。`<li>`元素里的`*ngFor`是 Angular 的“迭代”指令。
|
||||
它将`<li>`元素及其子级标记为“迭代模板”:
|
||||
这个界面使用了由 `<ul>` 和 `<li>` 标签组成的无序列表。`<li>` 元素里的 `*ngFor` 是 Angular 的“迭代”指令。
|
||||
它将 `<li>` 元素及其子级标记为“迭代模板”:
|
||||
|
||||
<code-example path="displaying-data/src/app/app.component.2.ts" linenums="false" title="src/app/app.component.ts (li)" region="li">
|
||||
|
||||
|
@ -235,7 +235,7 @@ It marks that `<li>` element (and its children) as the "repeater template":
|
|||
Don't forget the leading asterisk (\*) in `*ngFor`. It is an essential part of the syntax.
|
||||
For more information, see the [Template Syntax](guide/template-syntax#ngFor) page.
|
||||
|
||||
不要忘记`*ngFor`中的前导星号 (\*)。它是语法中不可或缺的一部分。
|
||||
不要忘记 `*ngFor` 中的前导星号 (\*)。它是语法中不可或缺的一部分。
|
||||
更多信息,见[模板语法](guide/template-syntax#ngFor)。
|
||||
|
||||
</div>
|
||||
|
@ -245,7 +245,7 @@ it is an example of a template input variable. Read
|
|||
more about template input variables in the [microsyntax](guide/template-syntax#microsyntax) section of
|
||||
the [Template Syntax](guide/template-syntax) page.
|
||||
|
||||
注意看`ngFor`双引号表达式中的`hero`,它是一个模板输入变量。
|
||||
注意看 `ngFor` 双引号表达式中的 `hero`,它是一个模板输入变量。
|
||||
更多模板输入变量的信息,见[模板语法](guide/template-syntax)中的
|
||||
[微语法 (microsyntax)](guide/template-syntax#microsyntax)。
|
||||
|
||||
|
@ -253,16 +253,16 @@ Angular duplicates the `<li>` for each item in the list, setting the `hero` vari
|
|||
to the item (the hero) in the current iteration. Angular uses that variable as the
|
||||
context for the interpolation in the double curly braces.
|
||||
|
||||
Angular 为列表中的每个条目复制一个`<li>`元素,在每个迭代中,把`hero`变量设置为当前条目(英雄)。
|
||||
Angular 把`hero`变量作为双花括号插值表达式的上下文。
|
||||
Angular 为列表中的每个条目复制一个 `<li>` 元素,在每个迭代中,把 `hero` 变量设置为当前条目(英雄)。
|
||||
Angular 把 `hero` 变量作为双花括号插值表达式的上下文。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
In this case, `ngFor` is displaying an array, but `ngFor` can
|
||||
repeat items for any [iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) object.
|
||||
|
||||
本例中,`ngFor`用于显示一个“数组”,
|
||||
但`ngFor`可以为任何[可迭代的 (iterable) ](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols)对象重复渲染条目。
|
||||
本例中,`ngFor` 用于显示一个“数组”,
|
||||
但 `ngFor` 可以为任何[可迭代的 (iterable) ](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols)对象重复渲染条目。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -292,7 +292,7 @@ In real applications, most bindings are to more specialized objects.
|
|||
To convert this binding to use specialized objects, turn the array
|
||||
of hero names into an array of `Hero` objects. For that you'll need a `Hero` class:
|
||||
|
||||
要将此绑定转换成使用对象,需要把这个英雄名字数组变成`Hero`对象数组。但首先得有一个`Hero`类。
|
||||
要将此绑定转换成使用对象,需要把这个英雄名字数组变成 `Hero` 对象数组。但首先得有一个 `Hero` 类。
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
|
||||
|
@ -310,7 +310,7 @@ With the following code:
|
|||
|
||||
You've defined a class with a constructor and two properties: `id` and `name`.
|
||||
|
||||
你定义了一个类,具有一个构造函数和两个属性:`id`和`name`。
|
||||
你定义了一个类,具有一个构造函数和两个属性:`id` 和 `name`。
|
||||
|
||||
It might not look like the class has properties, but it does.
|
||||
The declaration of the constructor parameters takes advantage of a TypeScript shortcut.
|
||||
|
@ -339,7 +339,7 @@ That brief syntax does a lot:
|
|||
|
||||
* Initializes that property with the corresponding argument when creating an instance of the class.
|
||||
|
||||
当我们`new`出该类的一个实例时,把该属性初始化为相应的参数值。
|
||||
当我们 `new` 出该类的一个实例时,把该属性初始化为相应的参数值。
|
||||
|
||||
### Using the Hero class
|
||||
|
||||
|
@ -348,7 +348,7 @@ That brief syntax does a lot:
|
|||
After importing the `Hero` class, the `AppComponent.heroes` property can return a _typed_ array
|
||||
of `Hero` objects:
|
||||
|
||||
导入了`Hero`类之后,组件的`heroes`属性就可以返回一个*类型化的*`Hero`对象数组了。
|
||||
导入了 `Hero` 类之后,组件的 `heroes` 属性就可以返回一个*类型化的*`Hero` 对象数组了。
|
||||
|
||||
<code-example path="displaying-data/src/app/app.component.3.ts" linenums="false" title="src/app/app.component.ts (heroes)" region="heroes">
|
||||
|
||||
|
@ -359,8 +359,8 @@ At the moment it displays the hero's `id` and `name`.
|
|||
Fix that to display only the hero's `name` property.
|
||||
|
||||
接着,更新一下模板。
|
||||
现在它显示的是英雄的`id`和`name`。
|
||||
要修复它,只显示英雄的`name`属性就行了。
|
||||
现在它显示的是英雄的 `id` 和 `name`。
|
||||
要修复它,只显示英雄的 `name` 属性就行了。
|
||||
|
||||
<code-example path="displaying-data/src/app/app.component.3.ts" linenums="false" title="src/app/app.component.ts (template)" region="template">
|
||||
|
||||
|
@ -387,7 +387,7 @@ Let's change the example to display a message if there are more than three heroe
|
|||
The Angular `ngIf` directive inserts or removes an element based on a _truthy/falsy_ condition.
|
||||
To see it in action, add the following paragraph at the bottom of the template:
|
||||
|
||||
Angular 的`ngIf`指令会根据一个布尔条件来显示或移除一个元素。
|
||||
Angular 的 `ngIf` 指令会根据一个布尔条件来显示或移除一个元素。
|
||||
来看看实际效果,把下列语句加到模板的底部:
|
||||
|
||||
<code-example path="displaying-data/src/app/app.component.ts" linenums="false" title="src/app/app.component.ts (message)" region="message">
|
||||
|
@ -399,8 +399,8 @@ Angular 的`ngIf`指令会根据一个布尔条件来显示或移除一个元素
|
|||
Don't forget the leading asterisk (\*) in `*ngIf`. It is an essential part of the syntax.
|
||||
Read more about `ngIf` and `*` in the [ngIf section](guide/template-syntax#ngIf) of the [Template Syntax](guide/template-syntax) page.
|
||||
|
||||
不要忘了`*ngIf`中的前导星号 (\*)。它是本语法中不可或缺的一部分。
|
||||
更多`ngIf`和`* `的内容,见[模板语法](guide/template-syntax)中的[ngIf](guide/template-syntax#ngIf)。
|
||||
不要忘了 `*ngIf` 中的前导星号 (\*)。它是本语法中不可或缺的一部分。
|
||||
更多 `ngIf` 和 `* ` 的内容,见[模板语法](guide/template-syntax)中的[ngIf](guide/template-syntax#ngIf)。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -412,7 +412,7 @@ paragraph, so no message appears. For more information,
|
|||
see the [template expressions](guide/template-syntax#template-expressions) section of the
|
||||
[Template Syntax](guide/template-syntax) page.
|
||||
|
||||
双引号中的模板表达式`*ngIf="heros.length > 3"`,外观和行为很象 TypeScript 。
|
||||
双引号中的模板表达式 `*ngIf="heros.length > 3"`,外观和行为很象 TypeScript 。
|
||||
当组件中的英雄列表有三个以上的条目时,Angular 把这个段落添加到 DOM 中,于是消息显示了出来。
|
||||
更多信息,见[模板语法](guide/template-syntax)中的[模板表达式](guide/template-syntax#template-expressions)。
|
||||
|
||||
|
@ -431,7 +431,7 @@ Go back into <code>app.component.ts"</code> and delete or comment out one of the
|
|||
The browser should refresh automatically and the message should disappear.
|
||||
|
||||
试一下。因为这个数组中有四个条目,所以消息应该显示出来。
|
||||
回到`app.component.ts`,从英雄数组中删除或注释掉一个元素。
|
||||
回到 `app.component.ts`,从英雄数组中删除或注释掉一个元素。
|
||||
浏览器应该自动刷新,消息应该会消失。
|
||||
|
||||
## Summary
|
||||
|
|
|
@ -8,7 +8,7 @@ Component templates are not always fixed. An application may need to load new co
|
|||
|
||||
This cookbook shows you how to use `ComponentFactoryResolver` to add components dynamically.
|
||||
|
||||
这本烹饪书为你展示如何使用`ComponentFactoryResolver`来动态添加组件。
|
||||
这本烹饪书为你展示如何使用 `ComponentFactoryResolver` 来动态添加组件。
|
||||
|
||||
See the <live-example name="dynamic-component-loader"></live-example>
|
||||
of the code in this cookbook.
|
||||
|
@ -40,7 +40,7 @@ reference to the component in the ad banner's template.
|
|||
|
||||
Angular comes with its own API for loading components dynamically.
|
||||
|
||||
Angular 自带的API就能支持动态加载组件。
|
||||
Angular 自带的 API 就能支持动态加载组件。
|
||||
|
||||
{@a directive}
|
||||
|
||||
|
@ -51,12 +51,12 @@ Angular 自带的API就能支持动态加载组件。
|
|||
Before you can add components you have to define an anchor point
|
||||
to tell Angular where to insert components.
|
||||
|
||||
在添加组件之前,先要定义一个锚点来告诉Angular要把组件插入到什么地方。
|
||||
在添加组件之前,先要定义一个锚点来告诉 Angular 要把组件插入到什么地方。
|
||||
|
||||
The ad banner uses a helper directive called `AdDirective` to
|
||||
mark valid insertion points in the template.
|
||||
|
||||
广告条使用一个名叫`AdDirective`的辅助指令来在模板中标记出有效的插入点。
|
||||
广告条使用一个名叫 `AdDirective` 的辅助指令来在模板中标记出有效的插入点。
|
||||
|
||||
<code-example path="dynamic-component-loader/src/app/ad.directive.ts" title="src/app/ad.directive.ts" linenums="false">
|
||||
|
||||
|
@ -65,13 +65,13 @@ mark valid insertion points in the template.
|
|||
`AdDirective` injects `ViewContainerRef` to gain access to the view
|
||||
container of the element that will host the dynamically added component.
|
||||
|
||||
`AdDirective`注入了`ViewContainerRef`来获取对容器视图的访问权,这个容器就是那些动态加入的组件的宿主。
|
||||
`AdDirective` 注入了 `ViewContainerRef` 来获取对容器视图的访问权,这个容器就是那些动态加入的组件的宿主。
|
||||
|
||||
In the `@Directive` decorator, notice the selector name, `ad-host`;
|
||||
that's what you use to apply the directive to the element.
|
||||
The next section shows you how.
|
||||
|
||||
在`@Directive`装饰器中,要注意选择器的名称:`ad-host`,它就是我们将应用到元素上的指令。下一节我们会展示如何做。
|
||||
在 `@Directive` 装饰器中,要注意选择器的名称:`ad-host`,它就是我们将应用到元素上的指令。下一节我们会展示如何做。
|
||||
|
||||
{@a loading-components}
|
||||
|
||||
|
@ -83,17 +83,17 @@ Most of the ad banner implementation is in `ad-banner.component.ts`.
|
|||
To keep things simple in this example, the HTML is in the `@Component`
|
||||
decorator's `template` property as a template string.
|
||||
|
||||
广告条的大部分实现代码都在`ad-banner.component.ts`中。
|
||||
为了让这个例子简单点,我们把HTML直接放在了`@Component`装饰器的`template`属性中。
|
||||
广告条的大部分实现代码都在 `ad-banner.component.ts` 中。
|
||||
为了让这个例子简单点,我们把 HTML 直接放在了 `@Component` 装饰器的 `template` 属性中。
|
||||
|
||||
The `<ng-template>` element is where you apply the directive you just made.
|
||||
To apply the `AdDirective`, recall the selector from `ad.directive.ts`,
|
||||
`ad-host`. Apply that to `<ng-template>` without the square brackets. Now Angular knows
|
||||
where to dynamically load components.
|
||||
|
||||
`<ng-template>`元素就是刚才制作的指令将应用到的地方。
|
||||
要应用`AdDirective`,回忆一下来自`ad.directive.ts`的选择器`ad-host`。把它应用到`<ng-template>`(不用带方括号)。
|
||||
这下,Angular就知道该把组件动态加载到哪里了。
|
||||
`<ng-template>` 元素就是刚才制作的指令将应用到的地方。
|
||||
要应用 `AdDirective`,回忆一下来自 `ad.directive.ts` 的选择器 `ad-host`。把它应用到 `<ng-template>`(不用带方括号)。
|
||||
这下,Angular 就知道该把组件动态加载到哪里了。
|
||||
|
||||
<code-example path="dynamic-component-loader/src/app/ad-banner.component.ts" region="ad-host" title="src/app/ad-banner.component.ts (template)" linenums="false">
|
||||
|
||||
|
@ -102,7 +102,7 @@ where to dynamically load components.
|
|||
The `<ng-template>` element is a good choice for dynamic components
|
||||
because it doesn't render any additional output.
|
||||
|
||||
`<ng-template>`元素是动态加载组件的最佳选择,因为它不会渲染任何额外的输出。
|
||||
`<ng-template>` 元素是动态加载组件的最佳选择,因为它不会渲染任何额外的输出。
|
||||
|
||||
{@a resolving-components}
|
||||
|
||||
|
@ -112,26 +112,26 @@ because it doesn't render any additional output.
|
|||
|
||||
Take a closer look at the methods in `ad-banner.component.ts`.
|
||||
|
||||
深入看看`ad-banner.component.ts`中的方法。
|
||||
深入看看 `ad-banner.component.ts` 中的方法。
|
||||
|
||||
`AdBannerComponent` takes an array of `AdItem` objects as input,
|
||||
which ultimately comes from `AdService`. `AdItem` objects specify
|
||||
the type of component to load and any data to bind to the
|
||||
component.`AdService` returns the actual ads making up the ad campaign.
|
||||
|
||||
`AdBannerComponent`接收一个`AdItem`对象的数组作为输入,它最终来自`AdService`。
|
||||
`AdItem`对象指定要加载的组件类,以及绑定到该组件上的任意数据。
|
||||
`AdService`可以返回广告活动中的那些广告。
|
||||
`AdBannerComponent` 接收一个 `AdItem` 对象的数组作为输入,它最终来自 `AdService`。
|
||||
`AdItem` 对象指定要加载的组件类,以及绑定到该组件上的任意数据。
|
||||
`AdService` 可以返回广告活动中的那些广告。
|
||||
|
||||
Passing an array of components to `AdBannerComponent` allows for a
|
||||
dynamic list of ads without static elements in the template.
|
||||
|
||||
给`AdBannerComponent`传入一个组件数组可以让我们在模板中放入一个广告的动态列表,而不用写死在模板中。
|
||||
给 `AdBannerComponent` 传入一个组件数组可以让我们在模板中放入一个广告的动态列表,而不用写死在模板中。
|
||||
|
||||
With its `getAds()` method, `AdBannerComponent` cycles through the array of `AdItems`
|
||||
and loads a new component every 3 seconds by calling `loadComponent()`.
|
||||
|
||||
通过`getAds()`方法,`AdBannerComponent`可以循环遍历`AdItems`的数组,并且每三秒调用一次`loadComponent()`来加载新组件。
|
||||
通过 `getAds()` 方法,`AdBannerComponent` 可以循环遍历 `AdItems` 的数组,并且每三秒调用一次 `loadComponent()` 来加载新组件。
|
||||
|
||||
<code-example path="dynamic-component-loader/src/app/ad-banner.component.ts" region="class" title="src/app/ad-banner.component.ts (excerpt)" linenums="false">
|
||||
|
||||
|
@ -140,26 +140,26 @@ and loads a new component every 3 seconds by calling `loadComponent()`.
|
|||
The `loadComponent()` method is doing a lot of the heavy lifting here.
|
||||
Take it step by step. First, it picks an ad.
|
||||
|
||||
这里的`loadComponent()`方法很重要。
|
||||
这里的 `loadComponent()` 方法很重要。
|
||||
我们来一步步看看。首先,它选取了一个广告。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
**How _loadComponent()_ chooses an ad**
|
||||
|
||||
**`loadComponent()`如何选择广告**
|
||||
**`loadComponent()` 如何选择广告**
|
||||
|
||||
The `loadComponent()` method chooses an ad using some math.
|
||||
|
||||
`loadComponent()`方法使用某种算法选择了一个广告。
|
||||
`loadComponent()` 方法使用某种算法选择了一个广告。
|
||||
|
||||
First, it sets the `currentAddIndex` by taking whatever it
|
||||
currently is plus one, dividing that by the length of the `AdItem` array, and
|
||||
using the _remainder_ as the new `currentAddIndex` value. Then, it uses that
|
||||
value to select an `adItem` from the array.
|
||||
|
||||
(译注:循环选取算法)首先,它把`currentAddIndex`递增一,然后用它除以`AdItem`数组长度的*余数*作为新的`currentAddIndex`的值,
|
||||
最后用这个值来从数组中选取一个`adItem`。
|
||||
(译注:循环选取算法)首先,它把 `currentAddIndex` 递增一,然后用它除以 `AdItem` 数组长度的*余数*作为新的 `currentAddIndex` 的值,
|
||||
最后用这个值来从数组中选取一个 `adItem`。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -167,31 +167,31 @@ After `loadComponent()` selects an ad, it uses `ComponentFactoryResolver`
|
|||
to resolve a `ComponentFactory` for each specific component.
|
||||
The `ComponentFactory` then creates an instance of each component.
|
||||
|
||||
在`loadComponent()`选取了一个广告之后,它使用`ComponentFactoryResolver`来为每个具体的组件解析出一个`ComponentFactory`。
|
||||
然后`ComponentFactory`会为每一个组件创建一个实例。
|
||||
在 `loadComponent()` 选取了一个广告之后,它使用 `ComponentFactoryResolver` 来为每个具体的组件解析出一个 `ComponentFactory`。
|
||||
然后 `ComponentFactory` 会为每一个组件创建一个实例。
|
||||
|
||||
Next, you're targeting the `viewContainerRef` that
|
||||
exists on this specific instance of the component. How do you know it's
|
||||
this specific instance? Because it's referring to `adHost` and `adHost` is the
|
||||
directive you set up earlier to tell Angular where to insert dynamic components.
|
||||
|
||||
接下来,我们要把`viewContainerRef`指向这个组件的现有实例。但我们怎么才能找到这个实例呢?
|
||||
很简单,因为它指向了`adHost`,而这个`adHost`就是我们以前设置过的指令,用来告诉Angular该把动态组件插入到什么位置。
|
||||
接下来,我们要把 `viewContainerRef` 指向这个组件的现有实例。但我们怎么才能找到这个实例呢?
|
||||
很简单,因为它指向了 `adHost`,而这个 `adHost` 就是我们以前设置过的指令,用来告诉 Angular 该把动态组件插入到什么位置。
|
||||
|
||||
As you may recall, `AdDirective` injects `ViewContainerRef` into its constructor.
|
||||
This is how the directive accesses the element that you want to use to host the dynamic component.
|
||||
|
||||
回忆一下,`AdDirective`曾在它的构造函数中注入了一个`ViewContainerRef`。
|
||||
回忆一下,`AdDirective` 曾在它的构造函数中注入了一个 `ViewContainerRef`。
|
||||
因此这个指令可以访问到这个被我们用作动态组件宿主的元素。
|
||||
|
||||
To add the component to the template, you call `createComponent()` on `ViewContainerRef`.
|
||||
|
||||
要把这个组件添加到模板中,我们可以调用`ViewContainerRef`的`createComponent()`。
|
||||
要把这个组件添加到模板中,我们可以调用 `ViewContainerRef` 的 `createComponent()`。
|
||||
|
||||
The `createComponent()` method returns a reference to the loaded component.
|
||||
Use that reference to interact with the component by assigning to its properties or calling its methods.
|
||||
|
||||
`createComponent()`方法返回一个引用,指向这个刚刚加载的组件。
|
||||
`createComponent()` 方法返回一个引用,指向这个刚刚加载的组件。
|
||||
使用这个引用就可以与该组件进行交互,比如设置它的属性或调用它的方法。
|
||||
|
||||
{@a selector-references}
|
||||
|
@ -205,13 +205,13 @@ for any component referenced in a template. However, there are
|
|||
no selector references in the templates for
|
||||
dynamically loaded components since they load at runtime.
|
||||
|
||||
通常,Angular编译器会为模板中所引用的每个组件都生成一个`ComponentFactory`类。
|
||||
通常,Angular 编译器会为模板中所引用的每个组件都生成一个 `ComponentFactory` 类。
|
||||
但是,对于动态加载的组件,模板中不会出现对它们的选择器的引用。
|
||||
|
||||
To ensure that the compiler still generates a factory,
|
||||
add dynamically loaded components to the `NgModule`'s `entryComponents` array:
|
||||
|
||||
要想确保编译器照常生成工厂类,就要把这些动态加载的组件添加到`NgModule`的`entryComponents`数组中:
|
||||
要想确保编译器照常生成工厂类,就要把这些动态加载的组件添加到 `NgModule` 的 `entryComponents` 数组中:
|
||||
|
||||
<code-example path="dynamic-component-loader/src/app/app.module.ts" region="entry-components" title="src/app/app.module.ts (entry components)" linenums="false">
|
||||
|
||||
|
@ -221,16 +221,16 @@ add dynamically loaded components to the `NgModule`'s `entryComponents` array:
|
|||
|
||||
## The _AdComponent_ interface
|
||||
|
||||
## 公共的`AdComponent`接口
|
||||
## 公共的 `AdComponent` 接口
|
||||
|
||||
In the ad banner, all components implement a common `AdComponent` interface to
|
||||
standardize the API for passing data to the components.
|
||||
|
||||
在广告条中,所有组件都实现了一个公共接口`AdComponent`,它定义了一个标准化的API,让我们把数据传给组件。
|
||||
在广告条中,所有组件都实现了一个公共接口 `AdComponent`,它定义了一个标准化的 API,让我们把数据传给组件。
|
||||
|
||||
Here are two sample components and the `AdComponent` interface for reference:
|
||||
|
||||
下面就是两个范例组件及其`AdComponent`接口:
|
||||
下面就是两个范例组件及其 `AdComponent` 接口:
|
||||
|
||||
<code-tabs>
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ It's a primitive start.
|
|||
It might evolve to support a much richer variety of questions, more graceful rendering, and superior user experience.
|
||||
All such greatness has humble beginnings.
|
||||
|
||||
在此烹饪宝典中,我们会展示如何利用`formGroup`来动态渲染一个简单的表单,包括各种控件类型和验证规则。
|
||||
在此烹饪宝典中,我们会展示如何利用 `formGroup` 来动态渲染一个简单的表单,包括各种控件类型和验证规则。
|
||||
这个起点很简陋,但可以在这个基础上添加丰富多彩的问卷问题、更优美的渲染以及更卓越的用户体验。
|
||||
|
||||
The example in this cookbook is a dynamic form to build an
|
||||
|
@ -45,7 +45,7 @@ See the <live-example name="dynamic-form"></live-example>.
|
|||
|
||||
Start by creating an `NgModule` called `AppModule`.
|
||||
|
||||
让我们从创建一个名叫`AppModule`的`NgModule`开始。
|
||||
让我们从创建一个名叫 `AppModule` 的 `NgModule` 开始。
|
||||
|
||||
This cookbook uses [reactive forms](guide/reactive-forms).
|
||||
|
||||
|
@ -55,11 +55,11 @@ Reactive forms belongs to a different `NgModule` called `ReactiveFormsModule`,
|
|||
so in order to access any reactive forms directives, you have to import
|
||||
`ReactiveFormsModule` from the `@angular/forms` library.
|
||||
|
||||
响应式表单属于另外一个叫做`ReactiveFormsModule`的`NgModule`,所以,为了使用响应式表单类的指令,我们得从`@angular/forms`库中引入`ReactiveFormsModule`模块。
|
||||
响应式表单属于另外一个叫做 `ReactiveFormsModule` 的 `NgModule`,所以,为了使用响应式表单类的指令,我们得从 `@angular/forms` 库中引入 `ReactiveFormsModule` 模块。
|
||||
|
||||
Bootstrap the `AppModule` in `main.ts`.
|
||||
|
||||
我们在`main.ts`中启动`AppModule`。
|
||||
我们在 `main.ts` 中启动 `AppModule`。
|
||||
|
||||
<code-tabs>
|
||||
|
||||
|
@ -87,7 +87,7 @@ The _question_ is the most fundamental object in the model.
|
|||
|
||||
The following `QuestionBase` is a fundamental question class.
|
||||
|
||||
下面是我们建立的最基础的问卷问题基类,名叫`QuestionBase`。
|
||||
下面是我们建立的最基础的问卷问题基类,名叫 `QuestionBase`。
|
||||
|
||||
<code-example path="dynamic-form/src/app/question-base.ts" title="src/app/question-base.ts">
|
||||
|
||||
|
@ -98,12 +98,12 @@ that represent textbox and dropdown questions.
|
|||
The idea is that the form will be bound to specific question types and render the
|
||||
appropriate controls dynamically.
|
||||
|
||||
在这个基础上,我们派生出两个新类`TextboxQuestion` 和 `DropdownQuestion`,分别代表文本框和下拉框。这么做的初衷是,表单能动态绑定到特定的问卷问题类型,并动态渲染出合适的控件。
|
||||
在这个基础上,我们派生出两个新类 `TextboxQuestion` 和 `DropdownQuestion`,分别代表文本框和下拉框。这么做的初衷是,表单能动态绑定到特定的问卷问题类型,并动态渲染出合适的控件。
|
||||
|
||||
`TextboxQuestion` supports multiple HTML5 types such as text, email, and url
|
||||
via the `type` property.
|
||||
|
||||
`TextboxQuestion`可以通过`type`属性来支持多种HTML5元素类型,比如文本、邮件、网址等。
|
||||
`TextboxQuestion` 可以通过 `type` 属性来支持多种 HTML5 元素类型,比如文本、邮件、网址等。
|
||||
|
||||
<code-example path="dynamic-form/src/app/question-textbox.ts" title="src/app/question-textbox.ts" linenums="false">
|
||||
|
||||
|
@ -111,7 +111,7 @@ via the `type` property.
|
|||
|
||||
`DropdownQuestion` presents a list of choices in a select box.
|
||||
|
||||
`DropdownQuestion`表示一个带可选项列表的选择框。
|
||||
`DropdownQuestion` 表示一个带可选项列表的选择框。
|
||||
|
||||
<code-example path="dynamic-form/src/app/question-dropdown.ts" title="src/app/question-dropdown.ts" linenums="false">
|
||||
|
||||
|
@ -121,8 +121,8 @@ Next is `QuestionControlService`, a simple service for transforming the question
|
|||
In a nutshell, the form group consumes the metadata from the question model and
|
||||
allows you to specify default values and validation rules.
|
||||
|
||||
接下来,我们定义了`QuestionControlService`,一个可以把问卷问题转换为`FormGroup`的服务。
|
||||
简而言之,这个`FormGroup`使用问卷模型的元数据,并允许我们设置默认值和验证规则。
|
||||
接下来,我们定义了 `QuestionControlService`,一个可以把问卷问题转换为 `FormGroup` 的服务。
|
||||
简而言之,这个 `FormGroup` 使用问卷模型的元数据,并允许我们设置默认值和验证规则。
|
||||
|
||||
<code-example path="dynamic-form/src/app/question-control.service.ts" title="src/app/question-control.service.ts" linenums="false">
|
||||
|
||||
|
@ -141,7 +141,7 @@ to create components to represent the dynamic form.
|
|||
|
||||
`DynamicFormComponent` is the entry point and the main container for the form.
|
||||
|
||||
`DynamicFormComponent`是表单的主要容器和入口点。
|
||||
`DynamicFormComponent` 是表单的主要容器和入口点。
|
||||
|
||||
<code-tabs>
|
||||
|
||||
|
@ -160,8 +160,8 @@ The `<app-question>` tag matches the `DynamicFormQuestionComponent`,
|
|||
the component responsible for rendering the details of each _individual_
|
||||
question based on values in the data-bound question object.
|
||||
|
||||
它代表了问卷问题列表,每个问题都被绑定到一个`<app-question>`组件元素。
|
||||
`<app-question>`标签匹配到的是组件`DynamicFormQuestionComponent`,该组件的职责是根据各个问卷问题对象的值来动态渲染表单控件。
|
||||
它代表了问卷问题列表,每个问题都被绑定到一个 `<app-question>` 组件元素。
|
||||
`<app-question>` 标签匹配到的是组件 `DynamicFormQuestionComponent`,该组件的职责是根据各个问卷问题对象的值来动态渲染表单控件。
|
||||
|
||||
<code-tabs>
|
||||
|
||||
|
@ -179,18 +179,18 @@ Notice this component can present any type of question in your model.
|
|||
You only have two types of questions at this point but you can imagine many more.
|
||||
The `ngSwitch` determines which type of question to display.
|
||||
|
||||
请注意,这个组件能代表模型里的任何问题类型。目前,还只有两种问题类型,但可以添加更多类型。可以用`ngSwitch`决定显示哪种类型的问题。
|
||||
请注意,这个组件能代表模型里的任何问题类型。目前,还只有两种问题类型,但可以添加更多类型。可以用 `ngSwitch` 决定显示哪种类型的问题。
|
||||
|
||||
In both components you're relying on Angular's **formGroup** to connect the template HTML to the
|
||||
underlying control objects, populated from the question model with display and validation rules.
|
||||
|
||||
在这两个组件中,我们依赖Angular的**formGroup**来把模板HTML和底层控件对象连接起来,该对象从问卷问题模型里获取渲染和验证规则。
|
||||
在这两个组件中,我们依赖 Angular 的**formGroup**来把模板 HTML 和底层控件对象连接起来,该对象从问卷问题模型里获取渲染和验证规则。
|
||||
|
||||
`formControlName` and `formGroup` are directives defined in
|
||||
`ReactiveFormsModule`. The templates can access these directives
|
||||
directly since you imported `ReactiveFormsModule` from `AppModule`.
|
||||
|
||||
`formControlName`和`formGroup`是在`ReactiveFormsModule`中定义的指令。我们之所以能在模板中使用它们,是因为我们往`AppModule`中导入了`ReactiveFormsModule`。
|
||||
`formControlName` 和 `formGroup` 是在 `ReactiveFormsModule` 中定义的指令。我们之所以能在模板中使用它们,是因为我们往 `AppModule` 中导入了 `ReactiveFormsModule`。
|
||||
|
||||
{@a questionnaire-data}
|
||||
|
||||
|
@ -200,20 +200,20 @@ directly since you imported `ReactiveFormsModule` from `AppModule`.
|
|||
|
||||
`DynamicFormComponent` expects the list of questions in the form of an array bound to `@Input() questions`.
|
||||
|
||||
`DynamicForm`期望得到一个问题列表,该列表被绑定到`@Input() questions`属性。
|
||||
`DynamicForm` 期望得到一个问题列表,该列表被绑定到 `@Input() questions` 属性。
|
||||
|
||||
The set of questions you've defined for the job application is returned from the `QuestionService`.
|
||||
In a real app you'd retrieve these questions from storage.
|
||||
|
||||
`QuestionService`会返回为工作申请表定义的那组问题列表。在真实的应用程序环境中,我们会从数据库里获得这些问题列表。
|
||||
`QuestionService` 会返回为工作申请表定义的那组问题列表。在真实的应用程序环境中,我们会从数据库里获得这些问题列表。
|
||||
|
||||
The key point is that you control the hero job application questions
|
||||
entirely through the objects returned from `QuestionService`.
|
||||
Questionnaire maintenance is a simple matter of adding, updating,
|
||||
and removing objects from the `questions` array.
|
||||
|
||||
关键是,我们完全根据`QuestionService`返回的对象来控制英雄的工作申请表。
|
||||
要维护这份问卷,只要非常简单的添加、更新和删除`questions`数组中的对象就可以了。
|
||||
关键是,我们完全根据 `QuestionService` 返回的对象来控制英雄的工作申请表。
|
||||
要维护这份问卷,只要非常简单的添加、更新和删除 `questions` 数组中的对象就可以了。
|
||||
|
||||
<code-example path="dynamic-form/src/app/question.service.ts" title="src/app/question.service.ts">
|
||||
|
||||
|
@ -221,7 +221,7 @@ directly since you imported `ReactiveFormsModule` from `AppModule`.
|
|||
|
||||
Finally, display an instance of the form in the `AppComponent` shell.
|
||||
|
||||
最后,在`AppComponent`里显示出表单。
|
||||
最后,在 `AppComponent` 里显示出表单。
|
||||
|
||||
<code-example path="dynamic-form/src/app/app.component.ts" title="app.component.ts">
|
||||
|
||||
|
@ -237,7 +237,7 @@ Although in this example you're modelling a job application for heroes, there ar
|
|||
no references to any specific hero question
|
||||
outside the objects returned by `QuestionService`.
|
||||
|
||||
在这个例子中,虽然我们是在为英雄的工作申请表建模,但是除了`QuestionService`返回的那些对象外,没有其它任何地方是与英雄有关的。
|
||||
在这个例子中,虽然我们是在为英雄的工作申请表建模,但是除了 `QuestionService` 返回的那些对象外,没有其它任何地方是与英雄有关的。
|
||||
|
||||
This is very important since it allows you to repurpose the components for any type of survey
|
||||
as long as it's compatible with the *question* object model.
|
||||
|
@ -253,7 +253,7 @@ When the form is valid, you can click *Save* and the app renders the current for
|
|||
This proves that any user input is bound back to the data model.
|
||||
Saving and retrieving the data is an exercise for another time.
|
||||
|
||||
表单验证通过之前,*保存*按钮是禁用的。验证通过后,就可以点击*保存*按钮,程序会把当前值渲染成JSON显示出来。
|
||||
表单验证通过之前,*保存*按钮是禁用的。验证通过后,就可以点击*保存*按钮,程序会把当前值渲染成 JSON 显示出来。
|
||||
这表明任何用户输入都被传到了数据模型里。至于如何储存和提取数据则是另一话题了。
|
||||
|
||||
The final form looks like this:
|
||||
|
|
|
@ -29,19 +29,19 @@ To add validation to a template-driven form, you add the same validation attribu
|
|||
would with [native HTML form validation](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation).
|
||||
Angular uses directives to match these attributes with validator functions in the framework.
|
||||
|
||||
为了往模板驱动表单中添加验证机制,我们要添加一些验证属性,就像[原生的HTML表单验证器](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation)。
|
||||
为了往模板驱动表单中添加验证机制,我们要添加一些验证属性,就像[原生的 HTML 表单验证器](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation)。
|
||||
Angular 会用指令来匹配这些具有验证功能的指令。
|
||||
|
||||
Every time the value of a form control changes, Angular runs validation and generates
|
||||
either a list of validation errors, which results in an INVALID status, or null, which results in a VALID status.
|
||||
|
||||
每当表单控件中的值发生变化时,Angular 就会进行验证,并生成一个验证错误的列表(对应着INVALID状态)或者null(对应着VALID状态)。
|
||||
每当表单控件中的值发生变化时,Angular 就会进行验证,并生成一个验证错误的列表(对应着 INVALID 状态)或者 null(对应着 VALID 状态)。
|
||||
|
||||
You can then inspect the control's state by exporting `ngModel` to a local template variable.
|
||||
The following example exports `NgModel` into a variable called `name`:
|
||||
|
||||
我们可以通过把`ngModel`导出成局部模板变量来查看该控件的状态。
|
||||
比如下面这个例子就把`NgModel`导出成了一个名叫`name`的变量:
|
||||
我们可以通过把 `ngModel` 导出成局部模板变量来查看该控件的状态。
|
||||
比如下面这个例子就把 `NgModel` 导出成了一个名叫 `name` 的变量:
|
||||
|
||||
<code-example path="form-validation/src/app/template/hero-form-template.component.html" region="name-with-error-msg" title="template/hero-form-template.component.html (name)" linenums="false">
|
||||
|
||||
|
@ -55,23 +55,23 @@ Note the following:
|
|||
also carries a custom validator directive, `forbiddenName`. For more
|
||||
information, see [Custom validators](guide/form-validation#custom-validators) section.
|
||||
|
||||
`<input>`元素带有一些HTML验证属性:`required` 和 `minlength`。它还带有一个自定义的验证器指令`forbiddenName`。要了解更多信息,参见[自定义验证器](guide/form-validation#custom-validators)一节。
|
||||
`<input>` 元素带有一些 HTML 验证属性:`required` 和 `minlength`。它还带有一个自定义的验证器指令 `forbiddenName`。要了解更多信息,参见[自定义验证器](guide/form-validation#custom-validators)一节。
|
||||
|
||||
* `#name="ngModel"` exports `NgModel` into a local variable called `name`. `NgModel` mirrors many of the properties of its underlying
|
||||
`FormControl` instance, so you can use this in the template to check for control states such as `valid` and `dirty`. For a full list of control properties, see the [AbstractControl](api/forms/AbstractControl)
|
||||
API reference.
|
||||
|
||||
`#name="ngModel"`把`NgModel`导出成了一个名叫`name`的局部变量。`NgModel`把自己控制的`FormControl`实例的属性映射出去,让我们能在模板中检查控件的状态,比如`valid`和`dirty`。要了解完整的控件属性,参见 API 参考手册中的[AbstractControl](api/forms/AbstractControl)。
|
||||
`#name="ngModel"` 把 `NgModel` 导出成了一个名叫 `name` 的局部变量。`NgModel` 把自己控制的 `FormControl` 实例的属性映射出去,让我们能在模板中检查控件的状态,比如 `valid` 和 `dirty`。要了解完整的控件属性,参见 API 参考手册中的[AbstractControl](api/forms/AbstractControl)。
|
||||
|
||||
* The `*ngIf` on the `<div>` element reveals a set of nested message `divs`
|
||||
but only if the `name` is invalid and the control is either `dirty` or `touched`.
|
||||
|
||||
`<div>`元素的`*ngIf`揭露了一套嵌套消息`divs`,但是只在有“name”错误和控制器为`dirty`或者`touched`。
|
||||
`<div>` 元素的 `*ngIf` 揭露了一套嵌套消息 `divs`,但是只在有“name”错误和控制器为 `dirty` 或者 `touched`。
|
||||
|
||||
* Each nested `<div>` can present a custom message for one of the possible validation errors.
|
||||
There are messages for `required`, `minlength`, and `forbiddenName`.
|
||||
|
||||
每个嵌套的`<div>`为其中一个可能出现的验证错误显示一条自定义消息。比如 `required`、`minlength`和 `forbiddenName`。
|
||||
每个嵌套的 `<div>` 为其中一个可能出现的验证错误显示一条自定义消息。比如 `required`、`minlength` 和 `forbiddenName`。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
|
@ -85,7 +85,7 @@ does one of two things: changes the value,
|
|||
turning the control dirty; or blurs the form control element, setting the control to touched.
|
||||
|
||||
我们肯定不希望应用在用户还没有编辑过表单的时候就给他们显示错误提示。
|
||||
对`dirty`和`touched`的检查可以避免这种问题。改变控件的值会改变控件的`dirty`(脏)状态,而当控件失去焦点时,就会改变控件的`touched`(碰过)状态。
|
||||
对 `dirty` 和 `touched` 的检查可以避免这种问题。改变控件的值会改变控件的 `dirty`(脏)状态,而当控件失去焦点时,就会改变控件的 `touched`(碰过)状态。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -107,13 +107,13 @@ There are two types of validator functions: sync validators and async validators
|
|||
|
||||
* **Sync validators**: functions that take a control instance and immediately return either a set of validation errors or `null`. You can pass these in as the second argument when you instantiate a `FormControl`.
|
||||
|
||||
**同步验证器**函数接受一个控件实例,然后返回一组验证错误或`null`。我们可以在实例化一个`FormControl`时把它作为构造函数的第二个参数传进去。
|
||||
**同步验证器**函数接受一个控件实例,然后返回一组验证错误或 `null`。我们可以在实例化一个 `FormControl` 时把它作为构造函数的第二个参数传进去。
|
||||
|
||||
* **Async validators**: functions that take a control instance and return a Promise
|
||||
or Observable that later emits a set of validation errors or `null`. You can
|
||||
pass these in as the third argument when you instantiate a `FormControl`.
|
||||
|
||||
**异步验证器**函数接受一个控件实例,并返回一个承诺(Promise)或可观察对象(Observable),它们稍后会发出一组验证错误或者`null`。我们可以在实例化一个`FormControl`时把它作为构造函数的第三个参数传进去。
|
||||
**异步验证器**函数接受一个控件实例,并返回一个承诺(Promise)或可观察对象(Observable),它们稍后会发出一组验证错误或者 `null`。我们可以在实例化一个 `FormControl` 时把它作为构造函数的第三个参数传进去。
|
||||
|
||||
Note: for performance reasons, Angular only runs async validators if all sync validators pass. Each must complete before errors are set.
|
||||
|
||||
|
@ -130,7 +130,7 @@ Angular's built-in validators.
|
|||
|
||||
The same built-in validators that are available as attributes in template-driven forms, such as `required` and `minlength`, are all available to use as functions from the `Validators` class. For a full list of built-in validators, see the [Validators](api/forms/Validators) API reference.
|
||||
|
||||
模板驱动表单中可用的那些属性型验证器(如`required`、`minlength`等)对应于`Validators`类中的同名函数。要想查看内置验证器的全列表,参见 API 参考手册中的[验证器](api/forms/Validators)部分。
|
||||
模板驱动表单中可用的那些属性型验证器(如 `required`、`minlength` 等)对应于 `Validators` 类中的同名函数。要想查看内置验证器的全列表,参见 API 参考手册中的[验证器](api/forms/Validators)部分。
|
||||
|
||||
To update the hero form to be a reactive form, you can use some of the same
|
||||
built-in validators—this time, in function form. See below:
|
||||
|
@ -149,7 +149,7 @@ Note that:
|
|||
|
||||
* The name control sets up two built-in validators—`Validators.required` and `Validators.minLength(4)`—and one custom validator, `forbiddenNameValidator`. For more details see the [Custom validators](guide/form-validation#custom-validators) section in this guide.
|
||||
|
||||
`name`控件设置了两个内置验证器:`Validators.required` 和 `Validators.minLength(4)`。要了解更多信息,参见本章的[自定义验证器](guide/form-validation#custom-validators)一节。
|
||||
`name` 控件设置了两个内置验证器:`Validators.required` 和 `Validators.minLength(4)`。要了解更多信息,参见本章的[自定义验证器](guide/form-validation#custom-validators)一节。
|
||||
|
||||
* As these validators are all sync validators, you pass them in as the second argument.
|
||||
|
||||
|
@ -162,11 +162,11 @@ Note that:
|
|||
* This example adds a few getter methods. In a reactive form, you can always access any form control through the `get` method on its parent group, but sometimes it's useful to define getters as shorthands
|
||||
for the template.
|
||||
|
||||
这个例子添加了一些getter方法。在响应式表单中,我们通常会通过它所属的控件组(FormGroup)的`get`方法来访问表单控件,但有时候为模板定义一些getter作为简短形式。
|
||||
这个例子添加了一些 getter 方法。在响应式表单中,我们通常会通过它所属的控件组(FormGroup)的 `get` 方法来访问表单控件,但有时候为模板定义一些 getter 作为简短形式。
|
||||
|
||||
If you look at the template for the name input again, it is fairly similar to the template-driven example.
|
||||
|
||||
如果我们到模板中找到name输入框,就会发现它和模板驱动的例子很相似。
|
||||
如果我们到模板中找到 name 输入框,就会发现它和模板驱动的例子很相似。
|
||||
|
||||
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.html" region="name-with-error-msg" title="reactive/hero-form-reactive.component.html (name with error msg)" linenums="false">
|
||||
|
||||
|
@ -179,12 +179,12 @@ Key takeaways:
|
|||
* The form no longer exports any directives, and instead uses the `name` getter defined in
|
||||
the component class.
|
||||
|
||||
该表单不再导出任何指令,而是使用组件类中定义的`name`读取器。
|
||||
该表单不再导出任何指令,而是使用组件类中定义的 `name` 读取器。
|
||||
|
||||
* The `required` attribute is still present. While it's not necessary for validation purposes,
|
||||
you may want to keep it in your template for CSS styling or accessibility reasons.
|
||||
|
||||
`required`属性仍然存在,虽然验证不再需要它,但我们仍然在模板中保留它,以支持 CSS 样式或可访问性。
|
||||
`required` 属性仍然存在,虽然验证不再需要它,但我们仍然在模板中保留它,以支持 CSS 样式或可访问性。
|
||||
|
||||
## Custom validators
|
||||
|
||||
|
@ -198,7 +198,7 @@ Consider the `forbiddenNameValidator` function from previous
|
|||
[examples](guide/form-validation#reactive-component-class) in
|
||||
this guide. Here's what the definition of that function looks like:
|
||||
|
||||
考虑前面的[例子](guide/form-validation#reactive-component-class)中的`forbiddenNameValidator`函数。该函数的定义看起来是这样的:
|
||||
考虑前面的[例子](guide/form-validation#reactive-component-class)中的 `forbiddenNameValidator` 函数。该函数的定义看起来是这样的:
|
||||
|
||||
<code-example path="form-validation/src/app/shared/forbidden-name.directive.ts" region="custom-validator" title="shared/forbidden-name.directive.ts (forbiddenNameValidator)" linenums="false">
|
||||
|
||||
|
@ -221,8 +221,8 @@ null if the control value is valid _or_ a validation error object.
|
|||
The validation error object typically has a property whose name is the validation key, `'forbiddenName'`,
|
||||
and whose value is an arbitrary dictionary of values that you could insert into an error message, `{name}`.
|
||||
|
||||
`forbiddenNameValidator`工厂函数返回配置好的验证器函数。
|
||||
该函数接受一个Angular控制器对象,并在控制器值有效时返回null,或无效时返回验证错误对象。
|
||||
`forbiddenNameValidator` 工厂函数返回配置好的验证器函数。
|
||||
该函数接受一个 Angular 控制器对象,并在控制器值有效时返回 null,或无效时返回验证错误对象。
|
||||
验证错误对象通常有一个名为验证秘钥(`forbiddenName`)的属性。其值为一个任意词典,我们可以用来插入错误信息(`{name}`)。
|
||||
|
||||
Custom async validators are similar to sync validators, but they must instead return a Promise or Observable
|
||||
|
@ -251,16 +251,16 @@ to the `FormControl`.
|
|||
In template-driven forms, you don't have direct access to the `FormControl` instance, so you can't pass the
|
||||
validator in like you can for reactive forms. Instead, you need to add a directive to the template.
|
||||
|
||||
在模板驱动表单中,我们不用直接访问`FormControl`实例。所以我们不能像响应式表单中那样把验证器传进去,而应该在模板中添加一个指令。
|
||||
在模板驱动表单中,我们不用直接访问 `FormControl` 实例。所以我们不能像响应式表单中那样把验证器传进去,而应该在模板中添加一个指令。
|
||||
|
||||
The corresponding `ForbiddenValidatorDirective` serves as a wrapper around the `forbiddenNameValidator`.
|
||||
|
||||
`ForbiddenValidatorDirective`指令相当于`forbiddenNameValidator`的包装器。
|
||||
`ForbiddenValidatorDirective` 指令相当于 `forbiddenNameValidator` 的包装器。
|
||||
|
||||
Angular recognizes the directive's role in the validation process because the directive registers itself
|
||||
with the `NG_VALIDATORS` provider, a provider with an extensible collection of validators.
|
||||
|
||||
Angular在验证流程中的识别出指令的作用,是因为指令把自己注册到了`NG_VALIDATORS`提供商中,该提供商拥有一组可扩展的验证器。
|
||||
Angular 在验证流程中的识别出指令的作用,是因为指令把自己注册到了 `NG_VALIDATORS` 提供商中,该提供商拥有一组可扩展的验证器。
|
||||
|
||||
<code-example path="form-validation/src/app/shared/forbidden-name.directive.ts" region="directive-providers" title="shared/forbidden-name.directive.ts (providers)" linenums="false">
|
||||
|
||||
|
@ -270,7 +270,7 @@ The directive class then implements the `Validator` interface, so that it can ea
|
|||
with Angular forms. Here is the rest of the directive to help you get an idea of how it all
|
||||
comes together:
|
||||
|
||||
然后该指令类实现了`Validator`接口,以便它能简单的与 Angular 表单集成在一起。这个指令的其余部分有助于你理解它们是如何协作的:
|
||||
然后该指令类实现了 `Validator` 接口,以便它能简单的与 Angular 表单集成在一起。这个指令的其余部分有助于你理解它们是如何协作的:
|
||||
|
||||
<code-example path="form-validation/src/app/shared/forbidden-name.directive.ts" region="directive" title="shared/forbidden-name.directive.ts (directive)">
|
||||
|
||||
|
@ -278,7 +278,7 @@ comes together:
|
|||
|
||||
Once the `ForbiddenValidatorDirective` is ready, you can simply add its selector, `appForbiddenName`, to any input element to activate it. For example:
|
||||
|
||||
一旦 `ForbiddenValidatorDirective` 写好了,我们只要把`forbiddenName`选择器添加到输入框上就可以激活这个验证器了。比如:
|
||||
一旦 `ForbiddenValidatorDirective` 写好了,我们只要把 `forbiddenName` 选择器添加到输入框上就可以激活这个验证器了。比如:
|
||||
|
||||
<code-example path="form-validation/src/app/template/hero-form-template.component.html" region="name-input" title="template/hero-form-template.component.html (forbidden-name-input)" linenums="false">
|
||||
|
||||
|
@ -293,7 +293,7 @@ its `forbiddenName` property bound to “bob". If you were to replace
|
|||
`useExisting` with `useClass`, then you’d be registering a new class instance, one that
|
||||
doesn’t have a `forbiddenName`.
|
||||
|
||||
你可能注意到了自定义验证器指令是用`useExisting`而不是`useClass`来实例化的。注册的验证器必须是这个 `ForbiddenValidatorDirective` 实例本身,也就是表单中 `forbiddenName` 属性被绑定到了"bob"的那个。如果用`useClass`来代替`useExisting`,就会注册一个新的类实例,而它是没有`forbiddenName`的。
|
||||
你可能注意到了自定义验证器指令是用 `useExisting` 而不是 `useClass` 来实例化的。注册的验证器必须是这个 `ForbiddenValidatorDirective` 实例本身,也就是表单中 `forbiddenName` 属性被绑定到了"bob"的那个。如果用 `useClass` 来代替 `useExisting`,就会注册一个新的类实例,而它是没有 `forbiddenName` 的。
|
||||
|
||||
</div>
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ This page shows you how to build a simple form from scratch. Along the way you'l
|
|||
|
||||
* Use `ngModel` to create two-way data bindings for reading and writing input-control values.
|
||||
|
||||
用`ngModel`创建双向数据绑定,以读取和写入输入控件的值
|
||||
用 `ngModel` 创建双向数据绑定,以读取和写入输入控件的值
|
||||
|
||||
* Track state changes and the validity of form controls.
|
||||
|
||||
|
@ -37,7 +37,7 @@ This page shows you how to build a simple form from scratch. Along the way you'l
|
|||
|
||||
* Provide visual feedback using special CSS classes that track the state of the controls.
|
||||
|
||||
使用特殊的CSS类来跟踪控件的状态并给出视觉反馈
|
||||
使用特殊的 CSS 类来跟踪控件的状态并给出视觉反馈
|
||||
|
||||
* Display validation errors to users and enable/disable form controls.
|
||||
|
||||
|
@ -128,7 +128,7 @@ You'll build this form in small steps:
|
|||
|
||||
1. Create the `Hero` model class.
|
||||
|
||||
创建`Hero`模型类
|
||||
创建 `Hero` 模型类
|
||||
|
||||
1. Create the component that controls the form.
|
||||
|
||||
|
@ -140,11 +140,11 @@ You'll build this form in small steps:
|
|||
|
||||
1. Bind data properties to each form control using the `ngModel` two-way data-binding syntax.
|
||||
|
||||
使用`ngModel`双向数据绑定语法把数据属性绑定到每个表单输入控件。
|
||||
使用 `ngModel` 双向数据绑定语法把数据属性绑定到每个表单输入控件。
|
||||
|
||||
1. Add a `name` attribute to each form-input control.
|
||||
|
||||
往每个表单输入控件上添加`name`属性 (attribute)。
|
||||
往每个表单输入控件上添加 `name` 属性 (attribute)。
|
||||
|
||||
1. Add custom CSS to provide visual feedback.
|
||||
|
||||
|
@ -195,7 +195,7 @@ and one optional field (`alterEgo`).
|
|||
|
||||
Using the Angular CLI, generate a new class named `Hero`:
|
||||
|
||||
使用 Angular CLI 生成一个名叫`Hero`的新类:
|
||||
使用 Angular CLI 生成一个名叫 `Hero` 的新类:
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
|
||||
|
@ -218,11 +218,11 @@ It's an anemic model with few requirements and no behavior. Perfect for the demo
|
|||
The TypeScript compiler generates a public field for each `public` constructor parameter and
|
||||
automatically assigns the parameter’s value to that field when you create heroes.
|
||||
|
||||
TypeScript 编译器为每个`public`构造函数参数生成一个公共字段,在创建新的英雄实例时,自动把参数值赋给这些公共字段。
|
||||
TypeScript 编译器为每个 `public` 构造函数参数生成一个公共字段,在创建新的英雄实例时,自动把参数值赋给这些公共字段。
|
||||
|
||||
The `alterEgo` is optional, so the constructor lets you omit it; note the question mark (?) in `alterEgo?`.
|
||||
|
||||
`alterEgo`是可选的,调用构造函数时可省略,注意`alterEgo?`中的问号 (?)。
|
||||
`alterEgo` 是可选的,调用构造函数时可省略,注意 `alterEgo?` 中的问号 (?)。
|
||||
|
||||
You can create a new hero like this:
|
||||
|
||||
|
@ -272,19 +272,19 @@ Understanding this component requires only the Angular concepts covered in previ
|
|||
|
||||
* The code imports the Angular core library and the `Hero` model you just created.
|
||||
|
||||
这段代码导入了Angular核心库以及我们刚刚创建的`Hero`模型。
|
||||
这段代码导入了 Angular 核心库以及我们刚刚创建的 `Hero` 模型。
|
||||
|
||||
* The `@Component` selector value of "hero-form" means you can drop this form in a parent template with a `<hero-form>` tag.
|
||||
|
||||
`@Component`选择器“hero-form”表示可以用`<hero-form>`标签把这个表单放进父模板。
|
||||
`@Component` 选择器“hero-form”表示可以用 `<hero-form>` 标签把这个表单放进父模板。
|
||||
|
||||
* The `templateUrl` property points to a separate file for the template HTML.
|
||||
|
||||
`moduleId: module.id`属性设置了基地址,用于从相对模块路径加载`templateUrl`。
|
||||
`moduleId: module.id` 属性设置了基地址,用于从相对模块路径加载 `templateUrl`。
|
||||
|
||||
* You defined dummy data for `model` and `powers`, as befits a demo.
|
||||
|
||||
`templateUrl`属性指向一个独立的 HTML 模板文件。
|
||||
`templateUrl` 属性指向一个独立的 HTML 模板文件。
|
||||
|
||||
Down the road, you can inject a data service to get and save real data
|
||||
or perhaps expose these properties as inputs and outputs
|
||||
|
@ -297,7 +297,7 @@ parent component. This is not a concern now and these future changes won't affec
|
|||
* You added a `diagnostic` property to return a JSON representation of the model.
|
||||
It'll help you see what you're doing during development; you've left yourself a cleanup note to discard it later.
|
||||
|
||||
我们添加一个`diagnostic`属性,以返回这个模型的 JSON 形式。在开发过程中,它用于调试,最后清理时会丢弃它。
|
||||
我们添加一个 `diagnostic` 属性,以返回这个模型的 JSON 形式。在开发过程中,它用于调试,最后清理时会丢弃它。
|
||||
|
||||
## Revise *app.module.ts*
|
||||
|
||||
|
@ -306,12 +306,12 @@ It'll help you see what you're doing during development; you've left yourself a
|
|||
`app.module.ts` defines the application's root module. In it you identify the external modules you'll use in the application
|
||||
and declare the components that belong to this module, such as the `HeroFormComponent`.
|
||||
|
||||
`app.module.ts`定义了应用的根模块。其中标识即将用到的外部模块,以及声明属于本模块中的组件,例如`HeroFormComponent`。
|
||||
`app.module.ts` 定义了应用的根模块。其中标识即将用到的外部模块,以及声明属于本模块中的组件,例如 `HeroFormComponent`。
|
||||
|
||||
Because template-driven forms are in their own module, you need to add the `FormsModule` to the array of
|
||||
`imports` for the application module before you can use forms.
|
||||
|
||||
因为模板驱动的表单位于它们自己的模块,所以在使用表单之前,需要将`FormsModule`添加到应用模块的`imports`数组中。
|
||||
因为模板驱动的表单位于它们自己的模块,所以在使用表单之前,需要将 `FormsModule` 添加到应用模块的 `imports` 数组中。
|
||||
|
||||
Update it with the following:
|
||||
|
||||
|
@ -329,12 +329,12 @@ Update it with the following:
|
|||
|
||||
1. You import `FormsModule`.
|
||||
|
||||
导入`FormsModule`。
|
||||
导入 `FormsModule`。
|
||||
|
||||
1. You add the `FormsModule` to the list of `imports` defined in the `@NgModule` decorator. This gives the application
|
||||
access to all of the template-driven forms features, including `ngModel`.
|
||||
|
||||
把`FormsModule`添加到`ngModule`装饰器的`imports`列表中,这样应用就能访问模板驱动表单的所有特性,包括`ngModel`。
|
||||
把 `FormsModule` 添加到 `ngModule` 装饰器的 `imports` 列表中,这样应用就能访问模板驱动表单的所有特性,包括 `ngModel`。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -343,8 +343,8 @@ Update it with the following:
|
|||
If a component, directive, or pipe belongs to a module in the `imports` array, _don't_ re-declare it in the `declarations` array.
|
||||
If you wrote it and it should belong to this module, _do_ declare it in the `declarations` array.
|
||||
|
||||
如果某个组件、指令或管道是属于`imports`中所导入的某个模块的,那就_不能再_把它再声明到本模块的`declarations`数组中。
|
||||
如果它是你自己写的,并且确实属于当前模块,*才应该*把它声明在`declarations`数组中。
|
||||
如果某个组件、指令或管道是属于 `imports` 中所导入的某个模块的,那就_不能再_把它再声明到本模块的 `declarations` 数组中。
|
||||
如果它是你自己写的,并且确实属于当前模块,*才应该*把它声明在 `declarations` 数组中。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -354,7 +354,7 @@ Update it with the following:
|
|||
|
||||
`AppComponent` is the application's root component. It will host the new `HeroFormComponent`.
|
||||
|
||||
`AppComponent`是应用的根组件,`HeroFormComponent`将被放在其中。
|
||||
`AppComponent` 是应用的根组件,`HeroFormComponent` 将被放在其中。
|
||||
|
||||
Replace the contents of its template with the following:
|
||||
|
||||
|
@ -372,8 +372,8 @@ Replace the contents of its template with the following:
|
|||
Don't forget to remove the `name` field from the class body as well.
|
||||
|
||||
这里只做了两处修改。
|
||||
`template`中只剩下这个新的元素标签,即组件的`selector`属性。这样当应用组件被加载时,就会显示这个英雄表单。
|
||||
同样别忘了从类中移除了`name`字段。
|
||||
`template` 中只剩下这个新的元素标签,即组件的 `selector` 属性。这样当应用组件被加载时,就会显示这个英雄表单。
|
||||
同样别忘了从类中移除了 `name` 字段。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -392,12 +392,12 @@ Update the template file with the following contents:
|
|||
The language is simply HTML5. You're presenting two of the `Hero` fields, `name` and `alterEgo`, and
|
||||
opening them up for user input in input boxes.
|
||||
|
||||
这只是一段普通的旧式 HTML 5 代码。这里有两个`Hero`字段,`name`和`alterEgo`,供用户输入。
|
||||
这只是一段普通的旧式 HTML 5 代码。这里有两个 `Hero` 字段,`name` 和 `alterEgo`,供用户输入。
|
||||
|
||||
The *Name* `<input>` control has the HTML5 `required` attribute;
|
||||
the *Alter Ego* `<input>` control does not because `alterEgo` is optional.
|
||||
|
||||
*Name* `<input>`控件具有 HTML5 的`required`属性;但 *Alter Ego* `<input>`控件没有,因为`alterEgo`字段是可选的。
|
||||
*Name* `<input>` 控件具有 HTML5 的 `required` 属性;但 *Alter Ego* `<input>` 控件没有,因为 `alterEgo` 字段是可选的。
|
||||
|
||||
You added a *Submit* button at the bottom with some classes on it for styling.
|
||||
|
||||
|
@ -405,14 +405,14 @@ You added a *Submit* button at the bottom with some classes on it for styling.
|
|||
|
||||
*You're not using Angular yet*. There are no bindings or extra directives, just layout.
|
||||
|
||||
**我们还没有真正用到Angular**。没有绑定,没有额外的指令,只有布局。
|
||||
**我们还没有真正用到 Angular**。没有绑定,没有额外的指令,只有布局。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
In template driven forms, if you've imported `FormsModule`, you don't have to do anything
|
||||
to the `<form>` tag in order to make use of `FormsModule`. Continue on to see how this works.
|
||||
|
||||
在模板驱动表单中,你只要导入了`FormsModule`就不用对`<form>`做任何改动来使用`FormsModule`。接下来你会看到它的原理。
|
||||
在模板驱动表单中,你只要导入了 `FormsModule` 就不用对 `<form>` 做任何改动来使用 `FormsModule`。接下来你会看到它的原理。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -420,7 +420,7 @@ The `container`, `form-group`, `form-control`, and `btn` classes
|
|||
come from [Twitter Bootstrap](http://getbootstrap.com/css/). These classes are purely cosmetic.
|
||||
Bootstrap gives the form a little style.
|
||||
|
||||
`container`、`form-group`、`form-control`和`btn`类来自 [Twitter Bootstrap](http://getbootstrap.com/css/)。纯粹是装饰。
|
||||
`container`、`form-group`、`form-control` 和 `btn` 类来自 [Twitter Bootstrap](http://getbootstrap.com/css/)。纯粹是装饰。
|
||||
我们使用 Bootstrap 来美化表单。嘿,一点样式都没有的表单算个啥!
|
||||
|
||||
<div class="callout is-important">
|
||||
|
@ -432,14 +432,14 @@ Bootstrap gives the form a little style.
|
|||
Angular makes no use of the `container`, `form-group`, `form-control`, and `btn` classes or
|
||||
the styles of any external library. Angular apps can use any CSS library or none at all.
|
||||
|
||||
Angular 不需要`container`、`form-group`、`form-control`和`btn`类,
|
||||
Angular 不需要 `container`、`form-group`、`form-control` 和 `btn` 类,
|
||||
或者外部库的任何样式。Angular 应用可以使用任何 CSS 库…… ,或者啥都不用。
|
||||
|
||||
</div>
|
||||
|
||||
To add the stylesheet, open `styles.css` and add the following import line at the top:
|
||||
|
||||
我们来添加样式表。打开`index.html`,并把下列链接添加到`<head>`中:
|
||||
我们来添加样式表。打开 `index.html`,并把下列链接添加到 `<head>` 中:
|
||||
|
||||
<code-example path="forms/src/styles.1.css" linenums="false" title="src/styles.css">
|
||||
|
||||
|
@ -453,14 +453,14 @@ The hero must choose one superpower from a fixed list of agency-approved powers.
|
|||
You maintain that list internally (in `HeroFormComponent`).
|
||||
|
||||
我们的英雄必须从认证过的固定列表中选择一项超能力。
|
||||
这个列表位于`HeroFormComponent`中。
|
||||
这个列表位于 `HeroFormComponent` 中。
|
||||
|
||||
You'll add a `select` to the
|
||||
form and bind the options to the `powers` list using `ngFor`,
|
||||
a technique seen previously in the [Displaying Data](guide/displaying-data) page.
|
||||
|
||||
在表单中添加`select`,用`ngFor`把`powers`列表绑定到列表选项。
|
||||
我们在之前的[显示数据](guide/displaying-data)一章中见过`ngFor`。
|
||||
在表单中添加 `select`,用 `ngFor` 把 `powers` 列表绑定到列表选项。
|
||||
我们在之前的[显示数据](guide/displaying-data)一章中见过 `ngFor`。
|
||||
|
||||
Add the following HTML *immediately below* the *Alter Ego* group:
|
||||
|
||||
|
@ -474,8 +474,8 @@ This code repeats the `<option>` tag for each power in the list of powers.
|
|||
The `pow` template input variable is a different power in each iteration;
|
||||
you display its name using the interpolation syntax.
|
||||
|
||||
列表中的每一项超能力都会渲染成`<option>`标签。
|
||||
模板输入变量`pow`在每个迭代指向不同的超能力,使用双花括号插值表达式语法来显示它的名称。
|
||||
列表中的每一项超能力都会渲染成 `<option>` 标签。
|
||||
模板输入变量 `pow` 在每个迭代指向不同的超能力,使用双花括号插值表达式语法来显示它的名称。
|
||||
|
||||
{@a ngModel}
|
||||
|
||||
|
@ -511,11 +511,11 @@ instead you'll use the new `[(ngModel)]` syntax, which
|
|||
makes binding the form to the model easy.
|
||||
|
||||
虽然可以在表单中再次使用这些技术。
|
||||
但是,这里将介绍个新东西,`[(ngModel)]`语法,使表单绑定到模型的工作变得超级简单。
|
||||
但是,这里将介绍个新东西,`[(ngModel)]` 语法,使表单绑定到模型的工作变得超级简单。
|
||||
|
||||
Find the `<input>` tag for *Name* and update it like this:
|
||||
|
||||
找到 *Name* 对应的`<input>`标签,并且像这样修改它:
|
||||
找到 *Name* 对应的 `<input>` 标签,并且像这样修改它:
|
||||
|
||||
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (excerpt)" region="ngModelName-1">
|
||||
|
||||
|
@ -534,13 +534,13 @@ Find the `<input>` tag for *Name* and update it like this:
|
|||
|
||||
Focus on the binding syntax: `[(ngModel)]="..."`.
|
||||
|
||||
聚焦到绑定语法`[(ngModel)]="..."`上。
|
||||
聚焦到绑定语法 `[(ngModel)]="..."` 上。
|
||||
|
||||
You need one more addition to display the data. Declare
|
||||
a template variable for the form. Update the `<form>` tag with
|
||||
`#heroForm="ngForm"` as follows:
|
||||
|
||||
我们需要更多的工作来显示数据。在表单中声明一个模板变量。往`<form>`标签中加入`#heroForm="ngForm"`,代码如下:
|
||||
我们需要更多的工作来显示数据。在表单中声明一个模板变量。往 `<form>` 标签中加入 `#heroForm="ngForm"`,代码如下:
|
||||
|
||||
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (excerpt)" region="template-variable">
|
||||
|
||||
|
@ -548,7 +548,7 @@ a template variable for the form. Update the `<form>` tag with
|
|||
|
||||
The variable `heroForm` is now a reference to the `NgForm` directive that governs the form as a whole.
|
||||
|
||||
`heroForm`变量是一个到`NgForm`指令的引用,它代表该表单的整体。
|
||||
`heroForm` 变量是一个到 `NgForm` 指令的引用,它代表该表单的整体。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
|
@ -561,12 +561,12 @@ The variable `heroForm` is now a reference to the `NgForm` directive that govern
|
|||
What `NgForm` directive?
|
||||
You didn't add an [NgForm](api/forms/NgForm) directive.
|
||||
|
||||
什么是`NgForm`指令?
|
||||
什么是 `NgForm` 指令?
|
||||
但我们明明没有添加过[NgForm](api/forms/NgForm)指令啊!
|
||||
|
||||
Angular did. Angular automatically creates and attaches an `NgForm` directive to the `<form>` tag.
|
||||
|
||||
Angular替你做了。Angular会在`<form>`标签上自动创建并附加一个`NgForm`指令。
|
||||
Angular 替你做了。Angular 会在 `<form>` 标签上自动创建并附加一个 `NgForm` 指令。
|
||||
|
||||
The `NgForm` directive supplements the `form` element with additional features.
|
||||
It holds the controls you created for the elements with an `ngModel` directive
|
||||
|
@ -574,9 +574,9 @@ The variable `heroForm` is now a reference to the `NgForm` directive that govern
|
|||
It also has its own `valid` property which is true only *if every contained
|
||||
control* is valid.
|
||||
|
||||
`NgForm`指令为`form`增补了一些额外特性。
|
||||
它会控制那些带有`ngModel`指令和`name`属性的元素,监听他们的属性(包括其有效性)。
|
||||
它还有自己的`valid`属性,这个属性只有在*它包含的每个控件*都有效时才是真。
|
||||
`NgForm` 指令为 `form` 增补了一些额外特性。
|
||||
它会控制那些带有 `ngModel` 指令和 `name` 属性的元素,监听他们的属性(包括其有效性)。
|
||||
它还有自己的 `valid` 属性,这个属性只有在*它包含的每个控件*都有效时才是真。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -604,7 +604,7 @@ back again.
|
|||
[Two-way binding with NgModel](guide/template-syntax#ngModel) on the
|
||||
the [Template Syntax](guide/template-syntax) page.
|
||||
|
||||
**这就是双向数据绑定!**要了解更多信息,参见[模板语法](guide/template-syntax)页的[使用NgModel进行双向绑定](guide/template-syntax#ngModel)。
|
||||
**这就是双向数据绑定!**要了解更多信息,参见[模板语法](guide/template-syntax)页的[使用 NgModel 进行双向绑定](guide/template-syntax#ngModel)。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -612,9 +612,9 @@ Notice that you also added a `name` attribute to the `<input>` tag and set it to
|
|||
which makes sense for the hero's name. Any unique value will do, but using a descriptive name is helpful.
|
||||
Defining a `name` attribute is a requirement when using `[(ngModel)]` in combination with a form.
|
||||
|
||||
注意,`<input>`标签还添加了`name`属性 (attribute),并设置为 "name",表示英雄的名字。
|
||||
注意,`<input>` 标签还添加了 `name` 属性 (attribute),并设置为 "name",表示英雄的名字。
|
||||
使用任何唯一的值都可以,但使用具有描述性的名字会更有帮助。
|
||||
当在表单中使用`[(ngModel)]`时,必须要定义`name`属性。
|
||||
当在表单中使用 `[(ngModel)]` 时,必须要定义 `name` 属性。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
|
@ -623,8 +623,8 @@ Defining a `name` attribute is a requirement when using `[(ngModel)]` in combina
|
|||
Each `FormControl` is registered under the name you assigned to the `name` attribute.
|
||||
Read more in the previous section, [The NgForm directive](guide/forms#ngForm).
|
||||
|
||||
在内部,Angular 创建了一些`FormControl`,并把它们注册到`NgForm`指令,再将该指令附加到`<form>`标签。
|
||||
注册每个`FormControl`时,使用`name`属性值作为键值。[本章后面](guide/forms#ngForm)会讨论`NgForm`。
|
||||
在内部,Angular 创建了一些 `FormControl`,并把它们注册到 `NgForm` 指令,再将该指令附加到 `<form>` 标签。
|
||||
注册每个 `FormControl` 时,使用 `name` 属性值作为键值。[本章后面](guide/forms#ngForm)会讨论 `NgForm`。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -633,8 +633,8 @@ You'll ditch the input box binding message
|
|||
and add a new binding (at the top) to the component's `diagnostic` property.
|
||||
Then you can confirm that two-way data binding works *for the entire hero model*.
|
||||
|
||||
为*第二人格*和*超能力*属性添加类似的`[(ngModel)]`绑定和`name`属性。
|
||||
抛弃输入框的绑定消息,在组件顶部添加到`diagnostic`属性的新绑定。
|
||||
为*第二人格*和*超能力*属性添加类似的 `[(ngModel)]` 绑定和 `name` 属性。
|
||||
抛弃输入框的绑定消息,在组件顶部添加到 `diagnostic` 属性的新绑定。
|
||||
这样就能确认双向数据绑定*在整个 Hero 模型上*都能正常工作了。
|
||||
|
||||
After revision, the core of the form should look like this:
|
||||
|
@ -650,11 +650,11 @@ After revision, the core of the form should look like this:
|
|||
* Each input element has an `id` property that is used by the `label` element's `for` attribute
|
||||
to match the label to its input control.
|
||||
|
||||
每个 input 元素都有`id`属性,`label`元素的`for`属性用它来匹配到对应的输入控件。
|
||||
每个 input 元素都有 `id` 属性,`label` 元素的 `for` 属性用它来匹配到对应的输入控件。
|
||||
|
||||
* Each input element has a `name` property that is required by Angular forms to register the control with the form.
|
||||
|
||||
每个 input 元素都有`name`属性,Angular 表单用它注册控件。
|
||||
每个 input 元素都有 `name` 属性,Angular 表单用它注册控件。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -673,7 +673,7 @@ confirms that all of your changes are reflected in the model.
|
|||
|
||||
*Delete* the `{{diagnostic}}` binding at the top as it has served its purpose.
|
||||
|
||||
表单顶部的`{{diagnostic}}`绑定已经完成了它的使命,**删除**它。
|
||||
表单顶部的 `{{diagnostic}}` 绑定已经完成了它的使命,**删除**它。
|
||||
|
||||
## Track control state and validity with _ngModel_
|
||||
|
||||
|
@ -682,7 +682,7 @@ confirms that all of your changes are reflected in the model.
|
|||
Using `ngModel` in a form gives you more than just two-way data binding. It also tells
|
||||
you if the user touched the control, if the value changed, or if the value became invalid.
|
||||
|
||||
在表单中使用`ngModel`可以获得比仅使用双向数据绑定更多的控制权。它还会告诉我们很多信息:用户碰过此控件吗?它的值变化了吗?数据变得无效了吗?
|
||||
在表单中使用 `ngModel` 可以获得比仅使用双向数据绑定更多的控制权。它还会告诉我们很多信息:用户碰过此控件吗?它的值变化了吗?数据变得无效了吗?
|
||||
|
||||
The *NgModel* directive doesn't just track state; it updates the control with special Angular CSS classes that reflect the state.
|
||||
You can leverage those class names to change the appearance of the control.
|
||||
|
@ -797,7 +797,7 @@ You can leverage those class names to change the appearance of the control.
|
|||
Temporarily add a [template reference variable](guide/template-syntax#ref-vars) named `spy`
|
||||
to the _Name_ `<input>` tag and use it to display the input's CSS classes.
|
||||
|
||||
往姓名`<input>`标签上添加名叫 **spy** 的临时[模板引用变量](guide/template-syntax#ref-vars),
|
||||
往姓名 `<input>` 标签上添加名叫 **spy** 的临时[模板引用变量](guide/template-syntax#ref-vars),
|
||||
然后用这个 spy 来显示它上面的所有 CSS 类。
|
||||
|
||||
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (excerpt)" region="ngModelName-2">
|
||||
|
@ -851,7 +851,7 @@ To create such visual feedback, add definitions for the `ng-*` CSS classes.
|
|||
|
||||
*Delete* the `#spy` template reference variable and the `TODO` as they have served their purpose.
|
||||
|
||||
**删除**模板引用变量`#spy`和`TODO`,因为它们已经完成了使命。
|
||||
**删除**模板引用变量 `#spy` 和 `TODO`,因为它们已经完成了使命。
|
||||
|
||||
## Add custom CSS for visual feedback
|
||||
|
||||
|
@ -869,7 +869,7 @@ on the left of the input box:
|
|||
You achieve this effect by adding these class definitions to a new `forms.css` file
|
||||
that you add to the project as a sibling to `index.html`:
|
||||
|
||||
在新建的`forms.css`文件中,添加两个样式来实现这一效果。把这个文件添加到项目中,与`index.html`相邻。
|
||||
在新建的 `forms.css` 文件中,添加两个样式来实现这一效果。把这个文件添加到项目中,与 `index.html` 相邻。
|
||||
|
||||
<code-example path="forms/src/assets/forms.css" title="src/assets/forms.css">
|
||||
|
||||
|
@ -877,7 +877,7 @@ that you add to the project as a sibling to `index.html`:
|
|||
|
||||
Update the `<head>` of `index.html` to include this style sheet:
|
||||
|
||||
更新`index.html`中的`<head>`,以包含这个样式表:
|
||||
更新 `index.html` 中的 `<head>`,以包含这个样式表:
|
||||
|
||||
<code-example path="forms/src/index.html" linenums="false" title="src/index.html (styles)" region="styles">
|
||||
|
||||
|
@ -892,7 +892,7 @@ That says something is wrong but the user doesn't know *what* is wrong or what t
|
|||
Leverage the control's state to reveal a helpful message.
|
||||
|
||||
我们能做的更好。“Name” 输入框是必填的,清空它会让左侧的条变红。这表示*某些东西*是错的,但我们不知道错在哪里,或者如何纠正。
|
||||
可以借助`ng-invalid`类来给出有用的提示。
|
||||
可以借助 `ng-invalid` 类来给出有用的提示。
|
||||
|
||||
When the user deletes the name, the form should look like this:
|
||||
|
||||
|
@ -904,7 +904,7 @@ When the user deletes the name, the form should look like this:
|
|||
|
||||
To achieve this effect, extend the `<input>` tag with the following:
|
||||
|
||||
要达到这个效果,在`<input>`标签中添加:
|
||||
要达到这个效果,在 `<input>` 标签中添加:
|
||||
|
||||
* A [template reference variable](guide/template-syntax#ref-vars).
|
||||
|
||||
|
@ -912,7 +912,7 @@ To achieve this effect, extend the `<input>` tag with the following:
|
|||
|
||||
* The "*is required*" message in a nearby `<div>`, which you'll display only if the control is invalid.
|
||||
|
||||
“is required”消息,放在邻近的`<div>`元素中,只有当控件无效时,才显示它。
|
||||
“is required”消息,放在邻近的 `<div>` 元素中,只有当控件无效时,才显示它。
|
||||
|
||||
Here's an example of an error message added to the _name_ input box:
|
||||
|
||||
|
@ -926,7 +926,7 @@ You need a template reference variable to access the input box's Angular control
|
|||
Here you created a variable called `name` and gave it the value "ngModel".
|
||||
|
||||
模板引用变量可以访问模板中输入框的 Angular 控件。
|
||||
这里,创建了名叫`name`的变量,并且赋值为 "ngModel"。
|
||||
这里,创建了名叫 `name` 的变量,并且赋值为 "ngModel"。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
|
@ -937,14 +937,14 @@ Here you created a variable called `name` and gave it the value "ngModel".
|
|||
|
||||
为什么是 “ngModel”?
|
||||
指令的 [exportAs](api/core/Directive) 属性告诉 Angular 如何链接模板引用变量到指令。
|
||||
这里把`name`设置为`ngModel`是因为`ngModel`指令的`exportAs`属性设置成了 “ngModel”。
|
||||
这里把 `name` 设置为 `ngModel` 是因为 `ngModel` 指令的 `exportAs` 属性设置成了 “ngModel”。
|
||||
|
||||
</div>
|
||||
|
||||
You control visibility of the name error message by binding properties of the `name`
|
||||
control to the message `<div>` element's `hidden` property.
|
||||
|
||||
我们把`div`元素的`hidden`属性绑定到`name`控件的属性,这样就可以控制“姓名”字段错误信息的可见性了。
|
||||
我们把 `div` 元素的 `hidden` 属性绑定到 `name` 控件的属性,这样就可以控制“姓名”字段错误信息的可见性了。
|
||||
|
||||
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (hidden-error-msg)" region="hidden-error-msg">
|
||||
|
||||
|
@ -962,7 +962,7 @@ If you arrive in this component with a new (blank) hero or an invalid hero,
|
|||
you'll see the error message immediately, before you've done anything.
|
||||
|
||||
这种用户体验取决于开发人员的选择。有些人会希望任何时候都显示这条消息。
|
||||
如果忽略了`pristine`状态,就会只在值有效时隐藏此消息。
|
||||
如果忽略了 `pristine` 状态,就会只在值有效时隐藏此消息。
|
||||
如果往这个组件中传入全新(空)的英雄,或者无效的英雄,将立刻看到错误信息 —— 虽然我们还啥都没做。
|
||||
|
||||
Some developers want the message to display only when the user makes an invalid change.
|
||||
|
@ -983,14 +983,14 @@ but it's not imperative because the selection box already constrains the
|
|||
power to valid values.
|
||||
|
||||
英雄的*超能力*选项是必填的。
|
||||
只要愿意,可以往`<select>`上添加相同的错误处理。
|
||||
只要愿意,可以往 `<select>` 上添加相同的错误处理。
|
||||
但没有必要,这个选择框已经限制了“超能力”只能选有效值。
|
||||
|
||||
Now you'll add a new hero in this form.
|
||||
Place a *New Hero* button at the bottom of the form and bind its click event to a `newHero` component method.
|
||||
|
||||
我们希望在这个表单中添加新的英雄。
|
||||
在表单的底部放置“New Hero(新增英雄)”按钮,并把它的点击事件绑定到`newHero`组件。
|
||||
在表单的底部放置“New Hero(新增英雄)”按钮,并把它的点击事件绑定到 `newHero` 组件。
|
||||
|
||||
<code-example path="forms/src/app/hero-form/hero-form.component.html" region="new-hero-button-no-reset" title="src/app/hero-form/hero-form.component.html (New Hero button)">
|
||||
|
||||
|
@ -1006,7 +1006,7 @@ That's understandable as these are required fields.
|
|||
The error messages are hidden because the form is pristine; you haven't changed anything yet.
|
||||
|
||||
再次运行应用,点击 *New Hero* 按钮,表单被清空了。
|
||||
输入框左侧的*必填项*竖条是红色的,表示`name`和`power`属性是无效的。
|
||||
输入框左侧的*必填项*竖条是红色的,表示 `name` 和 `power` 属性是无效的。
|
||||
这可以理解,因为有一些必填字段。
|
||||
错误信息是隐藏的,因为表单还是全新的,还没有修改任何东西。
|
||||
|
||||
|
@ -1029,7 +1029,7 @@ Replacing the hero object *did not restore the pristine state* of the form contr
|
|||
You have to clear all of the flags imperatively, which you can do
|
||||
by calling the form's `reset()` method after calling the `newHero()` method.
|
||||
|
||||
我们必须清除所有标记,在调用`newHero()`方法后调用表单的`reset()`方法即可。
|
||||
我们必须清除所有标记,在调用 `newHero()` 方法后调用表单的 `reset()` 方法即可。
|
||||
|
||||
<code-example path="forms/src/app/hero-form/hero-form.component.html" region="new-hero-button-form-reset" title="src/app/hero-form/hero-form.component.html (Reset the form)">
|
||||
|
||||
|
@ -1056,7 +1056,7 @@ To make it useful, bind the form's `ngSubmit` event property
|
|||
to the hero form component's `onSubmit()` method:
|
||||
|
||||
现在这样仅仅触发“表单提交”是没用的。
|
||||
要让它有用,就要把该表单的`ngSubmit`事件属性绑定到英雄表单组件的`onSubmit()`方法上:
|
||||
要让它有用,就要把该表单的 `ngSubmit` 事件属性绑定到英雄表单组件的 `onSubmit()` 方法上:
|
||||
|
||||
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (ngSubmit)" region="ngSubmit">
|
||||
|
||||
|
@ -1066,14 +1066,14 @@ You'd already defined a template reference variable,
|
|||
`#heroForm`, and initialized it with the value "ngForm".
|
||||
Now, use that variable to access the form with the Submit button.
|
||||
|
||||
我们已经定义了一个模板引用变量`#heroForm`,并且把赋值为“ngForm”。
|
||||
我们已经定义了一个模板引用变量 `#heroForm`,并且把赋值为“ngForm”。
|
||||
现在,就可以在“Submit”按钮中访问这个表单了。
|
||||
|
||||
You'll bind the form's overall validity via
|
||||
the `heroForm` variable to the button's `disabled` property
|
||||
using an event binding. Here's the code:
|
||||
|
||||
我们要把表单的总体有效性通过`heroForm`变量绑定到此按钮的`disabled`属性上,代码如下:
|
||||
我们要把表单的总体有效性通过 `heroForm` 变量绑定到此按钮的 `disabled` 属性上,代码如下:
|
||||
|
||||
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (submit-button)" region="submit-button">
|
||||
|
||||
|
@ -1093,7 +1093,7 @@ The *Submit* button is also disabled.
|
|||
Not impressed? Think about it for a moment. What would you have to do to
|
||||
wire the button's enable/disabled state to the form's validity without Angular's help?
|
||||
|
||||
没感动吗?再想一会儿。如果没有 Angular `NgForm`的帮助,又该怎么让按钮的禁用/启用状态和表单的有效性关联起来呢?
|
||||
没感动吗?再想一会儿。如果没有 Angular `NgForm` 的帮助,又该怎么让按钮的禁用/启用状态和表单的有效性关联起来呢?
|
||||
|
||||
For you, it was as simple as this:
|
||||
|
||||
|
@ -1138,7 +1138,7 @@ hide the data entry area and display something else.
|
|||
Wrap the form in a `<div>` and bind
|
||||
its `hidden` property to the `HeroFormComponent.submitted` property.
|
||||
|
||||
先把表单包裹进`<div>`中,再把它的`hidden`属性绑定到`HeroFormComponent.submitted`属性。
|
||||
先把表单包裹进 `<div>` 中,再把它的 `hidden` 属性绑定到 `HeroFormComponent.submitted` 属性。
|
||||
|
||||
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (excerpt)" region="edit-div">
|
||||
|
||||
|
@ -1148,8 +1148,8 @@ The main form is visible from the start because the
|
|||
`submitted` property is false until you submit the form,
|
||||
as this fragment from the `HeroFormComponent` shows:
|
||||
|
||||
主表单从一开始就是可见的,因为`submitted`属性是 false,直到提交了这个表单。
|
||||
来自`HeroFormComponent`的代码片段告诉了我们这一点:
|
||||
主表单从一开始就是可见的,因为 `submitted` 属性是 false,直到提交了这个表单。
|
||||
来自 `HeroFormComponent` 的代码片段告诉了我们这一点:
|
||||
|
||||
<code-example path="forms/src/app/hero-form/hero-form.component.ts" linenums="false" title="src/app/hero-form/hero-form.component.ts (submitted)" region="submitted">
|
||||
|
||||
|
@ -1158,13 +1158,13 @@ as this fragment from the `HeroFormComponent` shows:
|
|||
When you click the *Submit* button, the `submitted` flag becomes true and the form disappears
|
||||
as planned.
|
||||
|
||||
当点击 Submit 按钮时,`submitted`标志会变成 true,并且表单像预想中一样消失了。
|
||||
当点击 Submit 按钮时,`submitted` 标志会变成 true,并且表单像预想中一样消失了。
|
||||
|
||||
Now the app needs to show something else while the form is in the submitted state.
|
||||
Add the following HTML below the `<div>` wrapper you just wrote:
|
||||
|
||||
现在,当表单处于已提交状态时,需要显示一些别的东西。
|
||||
在刚刚写的`<div>`包装下方,添加下列 HTML 语句:
|
||||
在刚刚写的 `<div>` 包装下方,添加下列 HTML 语句:
|
||||
|
||||
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (excerpt)" region="submitted">
|
||||
|
||||
|
@ -1179,7 +1179,7 @@ This `<div>` appears only while the component is in the submitted state.
|
|||
The HTML includes an *Edit* button whose click event is bound to an expression
|
||||
that clears the `submitted` flag.
|
||||
|
||||
这段HTML包含一个 “Edit(编辑)”按钮,将 click 事件绑定到表达式,用于清除`submitted`标志。
|
||||
这段 HTML 包含一个 “Edit(编辑)”按钮,将 click 事件绑定到表达式,用于清除 `submitted` 标志。
|
||||
|
||||
When you click the *Edit* button, this block disappears and the editable form reappears.
|
||||
|
||||
|
@ -1200,31 +1200,31 @@ framework features to provide support for data modification, validation, and mor
|
|||
|
||||
* A form component class with a `@Component` decorator.
|
||||
|
||||
带有`@Component`装饰器的表单组件类。
|
||||
带有 `@Component` 装饰器的表单组件类。
|
||||
|
||||
* Handling form submission by binding to the `NgForm.ngSubmit` event property.
|
||||
|
||||
通过绑定到`NgForm.ngSubmit`事件属性来处理表单提交。
|
||||
通过绑定到 `NgForm.ngSubmit` 事件属性来处理表单提交。
|
||||
|
||||
* Template-reference variables such as `#heroForm` and `#name`.
|
||||
|
||||
模板引用变量,例如`#heroForm`和`#name`。
|
||||
模板引用变量,例如 `#heroForm` 和 `#name`。
|
||||
|
||||
* `[(ngModel)]` syntax for two-way data binding.
|
||||
|
||||
`[(ngModel)]`语法用来实现双向数据绑定。
|
||||
`[(ngModel)]` 语法用来实现双向数据绑定。
|
||||
|
||||
* The use of `name` attributes for validation and form-element change tracking.
|
||||
|
||||
`name`属性的用途是有效性验证和对表单元素的变更进行追踪。
|
||||
`name` 属性的用途是有效性验证和对表单元素的变更进行追踪。
|
||||
|
||||
* The reference variable’s `valid` property on input controls to check if a control is valid and show/hide error messages.
|
||||
|
||||
指向 input 控件的引用变量上的`valid`属性,可用于检查控件是否有效、是否显示/隐藏错误信息。
|
||||
指向 input 控件的引用变量上的 `valid` 属性,可用于检查控件是否有效、是否显示/隐藏错误信息。
|
||||
|
||||
* Controlling the *Submit* button's enabled state by binding to `NgForm` validity.
|
||||
|
||||
通过绑定到`NgForm`的有效性状态,控制*Submit*按钮的禁用状态。
|
||||
通过绑定到 `NgForm` 的有效性状态,控制*Submit*按钮的禁用状态。
|
||||
|
||||
* Custom CSS classes that provide visual feedback to users about invalid controls.
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ By compiling your application using the compiler-cli, `ngc`, you can bootstrap d
|
|||
Ahead-of-time compiled applications also benefit from decreased load time and increased performance.
|
||||
|
||||
开发者可以在构造时 (build-time) 编译 Angular 应用程序。
|
||||
通过`compiler-cli` - `ngc`编译应用程序,应用可以从一个模块工厂直接启动,
|
||||
通过 `compiler-cli` - `ngc` 编译应用程序,应用可以从一个模块工厂直接启动,
|
||||
意味着不再需要把 Angular 编译器添加到 JavaScript 包中。
|
||||
预编译的应用程序加载迅速,具有更高的性能。
|
||||
|
||||
|
@ -60,7 +60,7 @@ as HTML attributes, hence the name.
|
|||
|
||||
For example, you can use the `ngClass` directive to add and remove CSS class names.
|
||||
|
||||
例如,`ngClass`指令就是典型的属性型指令。它可以添加或移除 CSS 类名。
|
||||
例如,`ngClass` 指令就是典型的属性型指令。它可以添加或移除 CSS 类名。
|
||||
|
||||
Learn about them in the [_Attribute Directives_](guide/attribute-directives) guide.
|
||||
|
||||
|
@ -80,7 +80,7 @@ The barrel itself is an ES2015 module file that re-exports *selected* exports of
|
|||
|
||||
For example, imagine three ES2015 modules in a `heroes` folder:
|
||||
|
||||
例如,设想在`heroes`目录下有三个 ES2015 模块:
|
||||
例如,设想在 `heroes` 目录下有三个 ES2015 模块:
|
||||
|
||||
<code-example>
|
||||
|
||||
|
@ -109,7 +109,7 @@ Without a barrel, a consumer needs three import statements:
|
|||
|
||||
You can add a barrel to the `heroes` folder (called `index`, by convention) that exports all of these items:
|
||||
|
||||
在`heroes`目录下添加一个封装桶(按约定叫做`index`),它导出所有这三项:
|
||||
在 `heroes` 目录下添加一个封装桶(按约定叫做 `index`),它导出所有这三项:
|
||||
|
||||
<code-example>
|
||||
|
||||
|
@ -131,7 +131,7 @@ Now a consumer can import what it needs from the barrel.
|
|||
|
||||
The Angular [scoped packages](guide/glossary#scoped-package) each have a barrel named `index`.
|
||||
|
||||
Angular 的每个[范围化包 (scoped package)](guide/glossary#scoped-package) 都有一个名为`index`的封装桶。
|
||||
Angular 的每个[范围化包 (scoped package)](guide/glossary#scoped-package) 都有一个名为 `index` 的封装桶。
|
||||
|
||||
<div class="alert is-important">
|
||||
|
||||
|
@ -172,7 +172,7 @@ which is the first component that is loaded for the application.
|
|||
|
||||
You can bootstrap multiple apps in the same `index.html`, each app with its own top-level root.
|
||||
|
||||
你可以在同一个`index.html`中引导多个应用,每个应用都有它自己的顶级根组件。
|
||||
你可以在同一个 `index.html` 中引导多个应用,每个应用都有它自己的顶级根组件。
|
||||
|
||||
{@a C}
|
||||
|
||||
|
@ -187,7 +187,7 @@ _except the first letter, which is lowercase_.
|
|||
|
||||
Function, property, and method names are typically spelled in camelCase. For example, `square`, `firstName`, and `getHeroes`. Notice that `square` is an example of how you write a single word in camelCase.
|
||||
|
||||
通常,函数、属性和方法命名使用驼峰式拼写法。例如,`square`, `firstName` 和 `getHeroes`。注意这里的`square`是如何用驼峰式命名法表示单一词的例子。
|
||||
通常,函数、属性和方法命名使用驼峰式拼写法。例如,`square`, `firstName` 和 `getHeroes`。注意这里的 `square` 是如何用驼峰式命名法表示单一词的例子。
|
||||
|
||||
camelCase is also known as *lower camel case* to distinguish it from *upper camel case*, or [PascalCase](guide/glossary#pascalcase).
|
||||
In Angular documentation, "camelCase" always means *lower camel case*.
|
||||
|
@ -222,7 +222,7 @@ the component class, thereby attaching to the class the essential component meta
|
|||
that Angular needs to create a component instance and render the component with its template
|
||||
as a view.
|
||||
|
||||
需要将`#@Component`[装饰器](guide/glossary#decorator)应用到一个组件类,从而把必要的组件元数据附加到类上。
|
||||
需要将 `#@Component`[装饰器](guide/glossary#decorator)应用到一个组件类,从而把必要的组件元数据附加到类上。
|
||||
Angular 会需要元数据来创建一个组件实例,并把组件的模板作为视图渲染出来。
|
||||
|
||||
Those familiar with "MVC" and "MVVM" patterns will recognize
|
||||
|
@ -246,7 +246,7 @@ This form is also known as kebab-case.
|
|||
the root of filenames (such as `hero-list.component.ts`) are often
|
||||
spelled in dash-case.
|
||||
|
||||
[指令](guide/glossary#directive)的选择器(例如`my-app`)和文件名(例如`hero-list.component.ts`)通常是用中线命名法来命名。
|
||||
[指令](guide/glossary#directive)的选择器(例如 `my-app`)和文件名(例如 `hero-list.component.ts`)通常是用中线命名法来命名。
|
||||
|
||||
## Data binding
|
||||
|
||||
|
@ -263,7 +263,7 @@ Data binding is an alternative to manually pushing application data values into
|
|||
event listeners, pulling changed values from the screen, and
|
||||
updating application data values.
|
||||
|
||||
在数据绑定机制下,我们只要声明一下HTML部件和数据源之间的关系,把细节交给框架去处理。
|
||||
在数据绑定机制下,我们只要声明一下 HTML 部件和数据源之间的关系,把细节交给框架去处理。
|
||||
而以前的手动操作过程是:将数据推送到 HTML 页面中、添加事件监听器、从屏幕获取变化后的数据,并更新应用中的值。
|
||||
|
||||
Angular has a rich data-binding framework with a variety of data-binding
|
||||
|
@ -317,7 +317,7 @@ A *function* that adds metadata to a class, its members (properties, methods) an
|
|||
|
||||
Decorators are an experimental (stage 2), JavaScript language [feature](https://github.com/wycats/javascript-decorators). TypeScript adds support for decorators.
|
||||
|
||||
装饰器是一个 JavaScript 的语言[特性](https://github.com/wycats/javascript-decorators),装饰器在 TypeScript 里已经实现,并被推荐到了ES2016(也就是ES7)。
|
||||
装饰器是一个 JavaScript 的语言[特性](https://github.com/wycats/javascript-decorators),装饰器在 TypeScript 里已经实现,并被推荐到了 ES2016(也就是 ES7)。
|
||||
|
||||
To apply a decorator, position it immediately above or to the left of the item it decorates.
|
||||
|
||||
|
@ -329,9 +329,9 @@ class as an Angular [component](guide/glossary#component) and an `@Input` decora
|
|||
of that component. The elided object argument to the `@Component` decorator would contain the pertinent component metadata.
|
||||
|
||||
Angular 使用自己的一套装饰器来实现应用程序各部件之间的相互操作。
|
||||
下面的例子中使用了`@Component`装饰器来将一个类标记为 Angular [组件 (component)](guide/glossary#component),
|
||||
并将`@Input`装饰器来应用到组件的`name`属性。
|
||||
`@Component`装饰器中省略的参数对象会包含与组件有关的元数据。
|
||||
下面的例子中使用了 `@Component` 装饰器来将一个类标记为 Angular [组件 (component)](guide/glossary#component),
|
||||
并将 `@Input` 装饰器来应用到组件的 `name` 属性。
|
||||
`@Component` 装饰器中省略的参数对象会包含与组件有关的元数据。
|
||||
|
||||
```
|
||||
|
||||
|
@ -354,7 +354,7 @@ classes that follow it in the file.
|
|||
|
||||
Always include parentheses `()` when applying a decorator.
|
||||
|
||||
永远别忘了在装饰器后面加括号`()`。
|
||||
永远别忘了在装饰器后面加括号 `()`。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -403,7 +403,7 @@ At the core, an [`injector`](guide/glossary#injector) returns dependency values
|
|||
The expression `injector.get(token)` returns the value associated with the given token.
|
||||
|
||||
在 Angular 内核中有一个[注入器 (injector)](guide/glossary#injector),当请求时返回依赖值。
|
||||
表达式`injector.get(token)`返回与该token(令牌)参数相关的值。
|
||||
表达式 `injector.get(token)` 返回与该 token(令牌)参数相关的值。
|
||||
|
||||
A token is an Angular type (`InjectionToken`). You rarely need to work with tokens directly; most
|
||||
methods accept a class name (`Foo`) or a string ("foo") and Angular converts it
|
||||
|
@ -412,7 +412,7 @@ the value associated with the token for the `Foo` class, typically an instance o
|
|||
|
||||
令牌是一个 Angular 中的类型 (`InjectionToken`)。我们很少直接处理令牌。
|
||||
绝大多数方法都接受类名 (`Foo`) 或字符串 ("foo"), Angular 会把这些类名称和字符串转换成令牌。
|
||||
当调用`injector.get(Foo)`时,注入器返回用`Foo`类生成的令牌所对应的依赖值,该依赖值通常是`Foo`类的实例。
|
||||
当调用 `injector.get(Foo)` 时,注入器返回用 `Foo` 类生成的令牌所对应的依赖值,该依赖值通常是 `Foo` 类的实例。
|
||||
|
||||
During many of its operations, Angular makes similar requests internally, such as when it creates a [`component`](guide/glossary#component) for display.
|
||||
|
||||
|
@ -479,7 +479,7 @@ associate with your custom directives. You add this custom markup to HTML templa
|
|||
as if you were writing native HTML. In this way, directives become extensions of
|
||||
HTML itself.
|
||||
|
||||
你可以自定义 HTML 标签(例如`<my-directive>`)来关联自定义指令。
|
||||
你可以自定义 HTML 标签(例如 `<my-directive>`)来关联自定义指令。
|
||||
然后,可以像写原生 HTML 一样把这些自定义标签放到 HTML 模板里。
|
||||
这样,指令就变成了 HTML 本身的拓展。
|
||||
|
||||
|
@ -531,8 +531,8 @@ Most modern browsers only support the much older "ECMAScript 5" (also known as "
|
|||
Applications written in ES2017, ES2016, ES2015, or one of their dialects must be [transpiled](guide/glossary#transpile)
|
||||
to ES5 JavaScript.
|
||||
|
||||
目前,几乎所有现代游览器只支持很老的“ECMAScript 5” (也称ES5)标准。
|
||||
使用ES2016、ES2015或者其它方言开发的应用程序,必须“[转译 (transpile)](guide/glossary#transpile)”成 ES5 JavaScript。
|
||||
目前,几乎所有现代游览器只支持很老的“ECMAScript 5” (也称 ES5)标准。
|
||||
使用 ES2016、ES2015 或者其它方言开发的应用程序,必须“[转译 (transpile)](guide/glossary#transpile)”成 ES5 JavaScript。
|
||||
|
||||
Angular developers can write in ES5 directly.
|
||||
|
||||
|
@ -665,7 +665,7 @@ one or more of the lifecycle hook interfaces.
|
|||
Each interface has a single hook method whose name is the interface name prefixed with `ng`.
|
||||
For example, the `OnInit` interface has a hook method named `ngOnInit`.
|
||||
|
||||
每个接口只有一个钩子方法,方法名是接口名加前缀 `ng`。例如,`OnInit`接口的钩子方法名为 `ngOnInit`。
|
||||
每个接口只有一个钩子方法,方法名是接口名加前缀 `ng`。例如,`OnInit` 接口的钩子方法名为 `ngOnInit`。
|
||||
|
||||
Angular calls these hook methods in the following order:
|
||||
|
||||
|
@ -677,7 +677,7 @@ Angular 会按以下顺序调用钩子方法:
|
|||
|
||||
* `ngOnInit`: after the first `ngOnChanges`.
|
||||
|
||||
`ngOnInit` - 在第一次`ngOnChanges`完成后调用。
|
||||
`ngOnInit` - 在第一次 `ngOnChanges` 完成后调用。
|
||||
|
||||
* `ngDoCheck`: developer's custom change detection.
|
||||
|
||||
|
@ -717,7 +717,7 @@ Read more in the [Lifecycle Hooks](guide/lifecycle-hooks) page.
|
|||
|
||||
Angular has the following types of modules:
|
||||
|
||||
Angular有下列模块类型:
|
||||
Angular 有下列模块类型:
|
||||
|
||||
* [NgModules](guide/glossary#ngmodule).
|
||||
For details and examples, see the [NgModules](guide/ngmodules) page.
|
||||
|
@ -726,7 +726,7 @@ For details and examples, see the [NgModules](guide/ngmodules) page.
|
|||
|
||||
* ES2015 modules, as described in this section.
|
||||
|
||||
ES2015模块,如本节所述。
|
||||
ES2015 模块,如本节所述。
|
||||
|
||||
For a comparison, see [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
|
||||
|
||||
|
@ -764,19 +764,19 @@ for any particular third-party library.
|
|||
You can use any module library that conforms to the standard.
|
||||
|
||||
采用这个标准的应用程序需要一个模块加载器来按需加载模块,并解析模块间的依赖关系。
|
||||
Angular 不附带模块加载器,也不偏爱任何第三方库(虽然大多数例子使用SystemJS)。
|
||||
Angular 不附带模块加载器,也不偏爱任何第三方库(虽然大多数例子使用 SystemJS)。
|
||||
你可以选择任何与这个标准兼容的模块化库。
|
||||
|
||||
Modules are typically named after the file in which the exported thing is defined.
|
||||
The Angular [DatePipe](https://github.com/angular/angular/blob/master/packages/common/src/pipes/date_pipe.ts)
|
||||
class belongs to a feature module named `date_pipe` in the file `date_pipe.ts`.
|
||||
|
||||
模块一般与它定义导出物的文件同名。例如,Angular 的 [DatePipe](https://github.com/angular/angular/blob/master/modules/angular2/src/common/pipes/date_pipe.ts) 类属于名叫`date_pipe`的特性模块,位于`date_pipe.ts`文件中。
|
||||
模块一般与它定义导出物的文件同名。例如,Angular 的 [DatePipe](https://github.com/angular/angular/blob/master/modules/angular2/src/common/pipes/date_pipe.ts) 类属于名叫 `date_pipe` 的特性模块,位于 `date_pipe.ts` 文件中。
|
||||
|
||||
You rarely access Angular feature modules directly. You usually import them from an Angular [scoped package](guide/glossary#scoped-package) such as `@angular/core`.
|
||||
|
||||
你很少需要直接访问 Angular 的特性模块。
|
||||
而通常会从一个 Angular [范围化包 (scoped package)](guide/glossary#scoped-package)中导入它们,例如`@angular/core`。
|
||||
而通常会从一个 Angular [范围化包 (scoped package)](guide/glossary#scoped-package)中导入它们,例如 `@angular/core`。
|
||||
|
||||
{@a N}
|
||||
|
||||
|
@ -803,15 +803,15 @@ An array whose items arrive asynchronously over time.
|
|||
Observables help you manage asynchronous data, such as data coming from a backend service.
|
||||
Observables are used within Angular itself, including Angular's event system and its HTTP client service.
|
||||
|
||||
一个`Observable`是一个数组,其中的元素随着时间的流逝异步地到达。
|
||||
`Observable`帮助我们管理异步数据,例如来自后台服务的数据。
|
||||
Angular 自身使用了`Observable`,包括 Angular 的事件系统和它的 http 客户端服务。
|
||||
一个 `Observable` 是一个数组,其中的元素随着时间的流逝异步地到达。
|
||||
`Observable` 帮助我们管理异步数据,例如来自后台服务的数据。
|
||||
Angular 自身使用了 `Observable`,包括 Angular 的事件系统和它的 http 客户端服务。
|
||||
|
||||
To use observables, Angular uses a third-party library called Reactive Extensions (RxJS).
|
||||
Observables are a proposed feature for ES2016, the next version of JavaScript.
|
||||
|
||||
为了使用`Observable`, Angular 采用了名为 Reactive Extensions (RxJS) 的第三方包。
|
||||
在下个版本的 JavaScript - ES 2016 中,`Observable`是建议的特性之一。
|
||||
为了使用 `Observable`, Angular 采用了名为 Reactive Extensions (RxJS) 的第三方包。
|
||||
在下个版本的 JavaScript - ES 2016 中,`Observable` 是建议的特性之一。
|
||||
|
||||
## Output
|
||||
|
||||
|
@ -840,7 +840,7 @@ The practice of writing individual words, compound words, or phrases such that e
|
|||
Class names are typically spelled in PascalCase. For example, `Person` and `HeroDetailComponent`.
|
||||
|
||||
Pascal 命名法是书写单词、复合词或短语的一种形式,每个单词或缩写都以大写开头。
|
||||
类名一般都采用 Pascal 命名法。例如`Person`和`HeroDetailComponent`。
|
||||
类名一般都采用 Pascal 命名法。例如 `Person` 和 `HeroDetailComponent`。
|
||||
|
||||
This form is also known as *upper camel case* to distinguish it from *lower camel case* or simply [camelCase](guide/glossary#camelcase).
|
||||
In this documentation, "PascalCase" means *upper camel case* and "camelCase" means *lower camel case*.
|
||||
|
@ -858,7 +858,7 @@ Here's an example that uses the built-in `currency` pipe to display
|
|||
a numeric value in the local currency.
|
||||
|
||||
Angular 管道是一个函数,用于把输入值转换成输出值以供[视图 (view)](guide/glossary#view)显示。
|
||||
下面这个例子中,用内置的`currency`管道把数字值显示为本地货币格式。
|
||||
下面这个例子中,用内置的 `currency` 管道把数字值显示为本地货币格式。
|
||||
|
||||
<code-example language="html" escape="html">
|
||||
|
||||
|
@ -907,15 +907,15 @@ When building reactive forms:
|
|||
|
||||
* Each control is explicitly created in the component class with `new FormControl()` or with `FormBuilder`.
|
||||
|
||||
在组件类中,使用`new FormControl()`或者`FormBuilder`显性地创建每个控件。
|
||||
在组件类中,使用 `new FormControl()` 或者 `FormBuilder` 显性地创建每个控件。
|
||||
|
||||
* The template input elements do *not* use `ngModel`.
|
||||
|
||||
模板中的`input`元素**不**使用`ngModel`。
|
||||
模板中的 `input` 元素**不**使用 `ngModel`。
|
||||
|
||||
* The associated Angular directives are all prefixed with `Form`, such as `FormGroup`, `FormControl`, and `FormControlName`.
|
||||
|
||||
相关联的 Angular 指令全部以`Form`开头,例如`FormGroup`、`FormControl`和`FormControlName`。
|
||||
相关联的 Angular 指令全部以 `Form` 开头,例如 `FormGroup`、`FormControl` 和 `FormControlName`。
|
||||
|
||||
Reactive forms are powerful, flexible, and a good choice for more complex data-entry form scenarios, such as dynamic generation of form controls.
|
||||
|
||||
|
@ -941,17 +941,17 @@ Angular 的组件路由器是一个特性丰富的机制,可以配置和管理
|
|||
In most cases, components become attached to a router by means
|
||||
of a `RouterConfig` that defines routes to views.
|
||||
|
||||
多数情况下,组件会通过`RouterConfig`中定义的路由到视图的对照表来附加到[路由器](guide/glossary#router)上。
|
||||
多数情况下,组件会通过 `RouterConfig` 中定义的路由到视图的对照表来附加到[路由器](guide/glossary#router)上。
|
||||
|
||||
A [routing component's](guide/glossary#routing-component) template has a `RouterOutlet` element
|
||||
where it can display views produced by the router.
|
||||
|
||||
[路由组件](guide/glossary#routing-component)的模板中带有一个`RouterOutlet`元素,那是显示路由器生成的视图的地方。
|
||||
[路由组件](guide/glossary#routing-component)的模板中带有一个 `RouterOutlet` 元素,那是显示路由器生成的视图的地方。
|
||||
|
||||
Other views in the application likely have anchor tags or buttons with `RouterLink`
|
||||
directives that users can click to navigate.
|
||||
|
||||
应用中的其它视图中某些锚标签或按钮上带有`RouterLink`指令,用户可以点击它们进行导航。
|
||||
应用中的其它视图中某些锚标签或按钮上带有 `RouterLink` 指令,用户可以点击它们进行导航。
|
||||
|
||||
For more information, see the [Routing & Navigation](guide/router) page.
|
||||
|
||||
|
@ -995,14 +995,14 @@ Read more at the [npm-scope](https://docs.npmjs.com/misc/scope) page.
|
|||
NgModules are delivered within *scoped packages* such as `@angular/core`,
|
||||
`@angular/common`, `@angular/platform-browser-dynamic`, `@angular/http`, and `@angular/router`.
|
||||
|
||||
Angular 模块是用一系列*范围化包*的形式发布的,例如`@angular/core`、`@angular/common`、`@angular/platform-browser-dynamic`、`@angular/http`和`@angular/router`。
|
||||
Angular 模块是用一系列*范围化包*的形式发布的,例如 `@angular/core`、`@angular/common`、`@angular/platform-browser-dynamic`、`@angular/http` 和 `@angular/router`。
|
||||
|
||||
Import a scoped package the same way that you import a normal package.
|
||||
The only difference, from a consumer perspective,
|
||||
is that the scoped package name begins with the Angular *scope name*, `@angular`.
|
||||
|
||||
导入范围化包与导入*普通*包方式相同。
|
||||
从消费者的视角看,唯一的不同是那些包的名字是用 Angular 的*范围化包名*`@angular`开头的。
|
||||
从消费者的视角看,唯一的不同是那些包的名字是用 Angular 的*范围化包名*`@angular` 开头的。
|
||||
|
||||
<code-example path="architecture/src/app/app.component.ts" linenums="false" title="architecture/src/app/app.component.ts (import)" region="import">
|
||||
|
||||
|
@ -1062,8 +1062,8 @@ shape or reshape HTML layout, typically by adding and removing elements in the D
|
|||
The `ngIf` "conditional element" directive and the `ngFor` "repeater" directive are well-known examples.
|
||||
|
||||
结构型指令是[指令 (directive)](guide/glossary#directive)一种,
|
||||
可以通过在DOM中添加、删除或操作元素和其各级子元素来塑造或重塑 HTML 布局。
|
||||
例如,`ngIf`这个“条件化元素”指令,`ngFor`这个“重复器”指令都是众所周知的例子。
|
||||
可以通过在 DOM 中添加、删除或操作元素和其各级子元素来塑造或重塑 HTML 布局。
|
||||
例如,`ngIf` 这个“条件化元素”指令,`ngFor` 这个“重复器”指令都是众所周知的例子。
|
||||
|
||||
Read more in the [Structural Directives](guide/structural-directives) page.
|
||||
|
||||
|
@ -1102,15 +1102,15 @@ When building template-driven forms:
|
|||
|
||||
* [Two-way binding](guide/glossary#data-binding) with `ngModel` keeps the component model synchronized with the user's entry into the input elements.
|
||||
|
||||
使用`ngModel`进行[双向绑定](guide/glossary#data-binding),保持组件模型和用户输入之间的同步。
|
||||
使用 `ngModel` 进行[双向绑定](guide/glossary#data-binding),保持组件模型和用户输入之间的同步。
|
||||
|
||||
* Behind the scenes, Angular creates a new control for each input element, provided you have set up a `name` attribute and two-way binding for each input.
|
||||
|
||||
在幕后,Angular 为每个带有`name`属性和双向绑定的输入元素创建了一个新的控件。
|
||||
在幕后,Angular 为每个带有 `name` 属性和双向绑定的输入元素创建了一个新的控件。
|
||||
|
||||
* The associated Angular directives are all prefixed with `ng` such as `ngForm`, `ngModel`, and `ngModelGroup`.
|
||||
|
||||
相关的 Angular 指令都带有`ng`前缀,例如`ngForm`、`ngModel`和`ngModelGroup`。
|
||||
相关的 Angular 指令都带有 `ng` 前缀,例如 `ngForm`、`ngModel` 和 `ngModelGroup`。
|
||||
|
||||
Template-driven forms are convenient, quick, and simple. They are a good choice for many basic data-entry form scenarios.
|
||||
|
||||
|
@ -1128,7 +1128,7 @@ in the [Forms](guide/forms) page.
|
|||
A TypeScript-like syntax that Angular evaluates within
|
||||
a [data binding](guide/glossary#data-binding).
|
||||
|
||||
Angular 用来在[数据绑定 (data binding)](guide/glossary#data-binding)内求值的、**类似**JavaScript语法的表达式。
|
||||
Angular 用来在[数据绑定 (data binding)](guide/glossary#data-binding)内求值的、**类似**JavaScript 语法的表达式。
|
||||
|
||||
Read about how to write template expressions
|
||||
in the [Template expressions](guide/template-syntax#template-expressions) section
|
||||
|
|
|
@ -60,9 +60,9 @@ The `HeroesListComponent` holds and manages multiple instances of the `HeroTaxRe
|
|||
The following diagram represents the state of the this guide's three-level component tree when there are three instances of `HeroTaxReturnComponent`
|
||||
open simultaneously.
|
||||
|
||||
考虑《英雄指南》应用的一个简单变种。它的顶层是`AppComponent`组件,它有一些子组件。
|
||||
`HeroesListComponent`组件保存和管理着`HeroTaxReturnComponent`的多个实例。
|
||||
下图展示了当`HeroesCardComponent`的三个 `HeroTaxReturnComponent` 实例同时展开时的三级组件树状态。
|
||||
考虑《英雄指南》应用的一个简单变种。它的顶层是 `AppComponent` 组件,它有一些子组件。
|
||||
`HeroesListComponent` 组件保存和管理着 `HeroTaxReturnComponent` 的多个实例。
|
||||
下图展示了当 `HeroesCardComponent` 的三个 `HeroTaxReturnComponent` 实例同时展开时的三级组件树状态。
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/dependency-injection/component-hierarchy.png" alt="injector tree">
|
||||
|
@ -118,8 +118,8 @@ It effectively "reconfigures" and "shadows" a provider at a higher level in the
|
|||
If you only specify providers at the top level (typically the root `AppModule`), the tree of injectors appears to be flat.
|
||||
All requests bubble up to the root <code>NgModule</code> injector that you configured with the `bootstrapModule` method.
|
||||
|
||||
如果我们只在顶级(通常是根模块`AppModule`),这三个注入器看起来将是“平面”的。
|
||||
所有的申请都会冒泡到根<code>NgModule</code>进行处理,也就是我们在`bootstrapModule`方法中配置的那个。
|
||||
如果我们只在顶级(通常是根模块 `AppModule`),这三个注入器看起来将是“平面”的。
|
||||
所有的申请都会冒泡到根<code>NgModule</code>进行处理,也就是我们在 `bootstrapModule` 方法中配置的那个。
|
||||
|
||||
## Component injectors
|
||||
|
||||
|
@ -140,22 +140,22 @@ Architectural reasons may lead you to restrict access to a service to the applic
|
|||
The guide sample includes a `VillainsListComponent` that displays a list of villains.
|
||||
It gets those villains from a `VillainsService`.
|
||||
|
||||
本章的范例中包括一个`VillainsListComponent`,它显示一个反派的列表。
|
||||
本章的范例中包括一个 `VillainsListComponent`,它显示一个反派的列表。
|
||||
|
||||
While you _could_ provide `VillainsService` in the root `AppModule` (that's where you'll find the `HeroesService`),
|
||||
that would make the `VillainsService` available everywhere in the application, including the _Hero_ workflows.
|
||||
|
||||
虽然我们也可以在根模块`AppModule`中提供`VillainsService`(就像`HeroesService`那样),不过那样一来就会导致在整个应用中到处都能访问到`VillainsService`,包括在*英雄*工作流中。
|
||||
虽然我们也可以在根模块 `AppModule` 中提供 `VillainsService`(就像 `HeroesService` 那样),不过那样一来就会导致在整个应用中到处都能访问到 `VillainsService`,包括在*英雄*工作流中。
|
||||
|
||||
If you later modified the `VillainsService`, you could break something in a hero component somewhere.
|
||||
That's not supposed to happen but providing the service in the root `AppModule` creates that risk.
|
||||
|
||||
如果我们以后修改了`VillainsService`,那就可能会破坏英雄组件中的某些部分。
|
||||
这可不妙,但是在根模块`AppModule`中提供这个服务可能会导致这种风险。
|
||||
如果我们以后修改了 `VillainsService`,那就可能会破坏英雄组件中的某些部分。
|
||||
这可不妙,但是在根模块 `AppModule` 中提供这个服务可能会导致这种风险。
|
||||
|
||||
Instead, provide the `VillainsService` in the `providers` metadata of the `VillainsListComponent` like this:
|
||||
|
||||
我们可以换一种方案:在`VillainsListComponent`元数据的`providers`中提供`VillainsService`,就像这样:
|
||||
我们可以换一种方案:在 `VillainsListComponent` 元数据的 `providers` 中提供 `VillainsService`,就像这样:
|
||||
|
||||
<code-example path="hierarchical-dependency-injection/src/app/villains-list.component.ts" linenums="false" title="src/app/villains-list.component.ts (metadata)" region="metadata">
|
||||
|
||||
|
@ -165,7 +165,7 @@ By providing `VillainsService` in the `VillainsListComponent` metadata and nowhe
|
|||
the service becomes available only in the `VillainsListComponent` and its sub-component tree.
|
||||
It's still a singleton, but it's a singleton that exist solely in the _villain_ domain.
|
||||
|
||||
在`VillainsListComponent`的元数据中而不是其它地方提供`VillainsService`服务,该服务就会只在`VillainsListComponent`及其子组件树中可用。
|
||||
在 `VillainsListComponent` 的元数据中而不是其它地方提供 `VillainsService` 服务,该服务就会只在 `VillainsListComponent` 及其子组件树中可用。
|
||||
它仍然是单例,但是这个单例只存在于*反派(villain)*这个领域中。
|
||||
|
||||
Now you know that a hero component can't access it. You've reduced your exposure to error.
|
||||
|
@ -187,7 +187,7 @@ This guide demonstrates that scenario with an example in the Tour of Heroes them
|
|||
Imagine an outer `HeroListComponent` that displays a list of super heroes.
|
||||
|
||||
本章要示范的场景仍然是基于《英雄指南》的。
|
||||
想象一个外层的`HeroListComponent`,它显示一个超级英雄的列表。
|
||||
想象一个外层的 `HeroListComponent`,它显示一个超级英雄的列表。
|
||||
|
||||
To open a hero's tax return, the preparer clicks on a hero name, which opens a component for editing that return.
|
||||
Each selected hero tax return opens in its own component and multiple returns can be open at the same time.
|
||||
|
@ -220,7 +220,7 @@ That would be a pretty easy task for a simple hero tax return.
|
|||
In the real world, with a rich tax return data model, the change management would be tricky.
|
||||
You might delegate that management to a helper service, as this example does.
|
||||
|
||||
实现方式之一就是让`HeroTaxReturnComponent`有逻辑来管理和还原那些更改。
|
||||
实现方式之一就是让 `HeroTaxReturnComponent` 有逻辑来管理和还原那些更改。
|
||||
这对于简单的报税单来说是很容易的。
|
||||
不过,在现实世界中,报税单的数据模型非常复杂,对这些修改的管理可能不得不投机取巧。
|
||||
于是我们可以把这种管理任务委托给一个辅助服务,就像这个例子中所做的。
|
||||
|
@ -229,9 +229,9 @@ Here is the `HeroTaxReturnService`.
|
|||
It caches a single `HeroTaxReturn`, tracks changes to that return, and can save or restore it.
|
||||
It also delegates to the application-wide singleton `HeroService`, which it gets by injection.
|
||||
|
||||
这是一个报税单服务`HeroTaxReturnService`。
|
||||
它缓存了单条`HeroTaxReturn`,用于跟踪那个申报单的变更,并且可以保存或还原它。
|
||||
它还委托给了全应用级的单例服务`HeroService`,它是通过依赖注入机制取得的。
|
||||
这是一个报税单服务 `HeroTaxReturnService`。
|
||||
它缓存了单条 `HeroTaxReturn`,用于跟踪那个申报单的变更,并且可以保存或还原它。
|
||||
它还委托给了全应用级的单例服务 `HeroService`,它是通过依赖注入机制取得的。
|
||||
|
||||
<code-example path="hierarchical-dependency-injection/src/app/hero-tax-return.service.ts" title="src/app/hero-tax-return.service.ts">
|
||||
|
||||
|
@ -239,7 +239,7 @@ It also delegates to the application-wide singleton `HeroService`, which it gets
|
|||
|
||||
Here is the `HeroTaxReturnComponent` that makes use of it.
|
||||
|
||||
下面是正在使用它的`HeroTaxReturnComponent`组件。
|
||||
下面是正在使用它的 `HeroTaxReturnComponent` 组件。
|
||||
|
||||
<code-example path="hierarchical-dependency-injection/src/app/hero-tax-return.component.ts" title="src/app/hero-tax-return.component.ts">
|
||||
|
||||
|
@ -251,7 +251,7 @@ The getter always returns what that service says is the current state of the her
|
|||
The component also asks the service to save and restore this tax return.
|
||||
|
||||
我们通过输入属性得到*要编辑的报税单*,我们把它实现成了读取器(getter)和设置器(setter)。
|
||||
设置器根据传进来的报税单初始化了组件自己的`HeroTaxReturnService`实例。
|
||||
设置器根据传进来的报税单初始化了组件自己的 `HeroTaxReturnService` 实例。
|
||||
读取器总是返回该服务所存英雄的当前状态。
|
||||
组件也会请求该服务来保存或还原这个报税单。
|
||||
|
||||
|
@ -264,7 +264,7 @@ What a mess!
|
|||
|
||||
Look closely at the metadata for the `HeroTaxReturnComponent`. Notice the `providers` property.
|
||||
|
||||
但仔细看`HeroTaxReturnComponent`的元数据,注意`providers`属性。
|
||||
但仔细看 `HeroTaxReturnComponent` 的元数据,注意 `providers` 属性。
|
||||
|
||||
<code-example path="hierarchical-dependency-injection/src/app/hero-tax-return.component.ts" linenums="false" title="src/app/hero-tax-return.component.ts (providers)" region="providers">
|
||||
|
||||
|
@ -275,7 +275,7 @@ Recall that every component _instance_ has its own injector.
|
|||
Providing the service at the component level ensures that _every_ instance of the component gets its own, private instance of the service.
|
||||
No tax return overwriting. No mess.
|
||||
|
||||
`HeroTaxReturnComponent`有它自己的`HeroTaxReturnService`提供商。
|
||||
`HeroTaxReturnComponent` 有它自己的 `HeroTaxReturnService` 提供商。
|
||||
回忆一下,每个组件的*实例*都有它自己的注入器。
|
||||
在组件级提供服务可以确保组件的*每个*实例都得到一个自己的、私有的服务实例。
|
||||
报税单不会再被意外覆盖,这下清楚了。
|
||||
|
@ -285,7 +285,7 @@ No tax return overwriting. No mess.
|
|||
The rest of the scenario code relies on other Angular features and techniques that you can learn about elsewhere in the documentation.
|
||||
You can review it and download it from the <live-example></live-example>.
|
||||
|
||||
该场景代码中的其它部分依赖另一些Angular的特性和技术,我们将会在本文档的其它章节学到。
|
||||
该场景代码中的其它部分依赖另一些 Angular 的特性和技术,我们将会在本文档的其它章节学到。
|
||||
你可以到<live-example></live-example>查看代码和下载它。
|
||||
|
||||
</div>
|
||||
|
@ -304,7 +304,7 @@ Suppose you configured the root injector (marked as A) with _generic_ providers
|
|||
`CarService`, `EngineService` and `TiresService`.
|
||||
|
||||
再次考虑[依赖注入](guide/dependency-injection)一章中车辆(Car)的例子。
|
||||
假设我们在根注入器(代号A)中配置了*通用的*提供商:`CarService`、`EngineService`和`TiresService`。
|
||||
假设我们在根注入器(代号 A)中配置了*通用的*提供商:`CarService`、`EngineService` 和 `TiresService`。
|
||||
|
||||
You create a car component (A) that displays a car constructed from these three generic services.
|
||||
|
||||
|
@ -313,11 +313,11 @@ You create a car component (A) that displays a car constructed from these three
|
|||
Then you create a child component (B) that defines its own, _specialized_ providers for `CarService` and `EngineService`
|
||||
that have special capabilites suitable for whatever is going on in component (B).
|
||||
|
||||
然后,我们创建一个子组件(B),它为`CarService`和`EngineService`定义了自己的*特殊的*提供商,它们具有更特殊的能力,适用于组件B的。
|
||||
然后,我们创建一个子组件(B),它为 `CarService` 和 `EngineService` 定义了自己的*特殊的*提供商,它们具有更特殊的能力,适用于组件 B 的。
|
||||
|
||||
Component (B) is the parent of another component (C) that defines its own, even _more specialized_ provider for `CarService`.
|
||||
|
||||
组件B是另一个组件C的父组件,而组件C又定义了自己的,*更特殊的*`CarService`提供商。
|
||||
组件 B 是另一个组件 C 的父组件,而组件 C 又定义了自己的,*更特殊的*`CarService` 提供商。
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/dependency-injection/car-components.png" alt="car components">
|
||||
|
@ -325,13 +325,13 @@ Component (B) is the parent of another component (C) that defines its own, even
|
|||
|
||||
Behind the scenes, each component sets up its own injector with zero, one, or more providers defined for that component itself.
|
||||
|
||||
在幕后,每个组件都有自己的注入器,这个注入器带有为组件本身准备的0个、1个或多个提供商。
|
||||
在幕后,每个组件都有自己的注入器,这个注入器带有为组件本身准备的 0 个、1 个或多个提供商。
|
||||
|
||||
When you resolve an instance of `Car` at the deepest component (C),
|
||||
its injector produces an instance of `Car` resolved by injector (C) with an `Engine` resolved by injector (B) and
|
||||
`Tires` resolved by the root injector (A).
|
||||
|
||||
当我们在最深层的组件C解析`Car`的实例时,它使用注入器C解析生成了一个`Car`的实例,使用注入器B解析了`Engine`,而`Tires`则是由根注入器A解析的。
|
||||
当我们在最深层的组件 C 解析 `Car` 的实例时,它使用注入器 C 解析生成了一个 `Car` 的实例,使用注入器 B 解析了 `Engine`,而 `Tires` 则是由根注入器 A 解析的。
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/dependency-injection/injector-tree.png" alt="car injector tree">
|
||||
|
@ -342,6 +342,6 @@ its injector produces an instance of `Car` resolved by injector (C) with an `Eng
|
|||
The code for this _cars_ scenario is in the `car.components.ts` and `car.services.ts` files of the sample
|
||||
which you can review and download from the <live-example></live-example>.
|
||||
|
||||
*车辆*场景下的代码位于`car.components.ts`和`car.services.ts`文件中,这个例子你可以在<live-example></live-example>查看和下载。
|
||||
*车辆*场景下的代码位于 `car.components.ts` 和 `car.services.ts` 文件中,这个例子你可以在<live-example></live-example>查看和下载。
|
||||
|
||||
</div>
|
||||
|
|
|
@ -8,8 +8,8 @@ The `HttpClient` in `@angular/common/http` offers a simplified client HTTP API f
|
|||
that rests on the `XMLHttpRequest` interface exposed by browsers.
|
||||
Additional benefits of `HttpClient` include testability features, typed request and response objects, request and response interception, `Observable` apis, and streamlined error handling.
|
||||
|
||||
`@angular/common/http`中的`HttpClient`类为 Angular 应用程序提供了一个简化的 API 来实现 HTTP 客户端功能。它基于浏览器提供的`XMLHttpRequest`接口。
|
||||
`HttpClient`带来的其它优点包括:可测试性、强类型的请求和响应对象、发起请求与接收响应时的拦截器支持,以及更好的、基于可观察(Observable)对象的 API 以及流式错误处理机制。
|
||||
`@angular/common/http` 中的 `HttpClient` 类为 Angular 应用程序提供了一个简化的 API 来实现 HTTP 客户端功能。它基于浏览器提供的 `XMLHttpRequest` 接口。
|
||||
`HttpClient` 带来的其它优点包括:可测试性、强类型的请求和响应对象、发起请求与接收响应时的拦截器支持,以及更好的、基于可观察(Observable)对象的 API 以及流式错误处理机制。
|
||||
|
||||
You can run the <live-example></live-example> that accompanies this guide.
|
||||
|
||||
|
@ -206,7 +206,7 @@ The response body doesn't return all the data you may need. Sometimes servers re
|
|||
|
||||
Tell `HttpClient` that you want the full response with the `observe` option:
|
||||
|
||||
要这样做,我们就要通过`observe`选项来告诉`HttpClient`,你想要完整的响应信息,而不是只有响应体:
|
||||
要这样做,我们就要通过 `observe` 选项来告诉 `HttpClient`,你想要完整的响应信息,而不是只有响应体:
|
||||
|
||||
<code-example
|
||||
path="http/src/app/config/config.service.ts"
|
||||
|
@ -240,7 +240,7 @@ As you can see, the response object has a `body` property of the correct type.
|
|||
|
||||
What happens if the request fails on the server, or if a poor network connection prevents it from even reaching the server? `HttpClient` will return an _error_ object instead of a successful response.
|
||||
|
||||
如果这个请求导致了服务器错误怎么办?甚至,在烂网络下请求都没到服务器该怎么办?`HttpClient`就会返回一个错误(error)而不再是成功的响应。
|
||||
如果这个请求导致了服务器错误怎么办?甚至,在烂网络下请求都没到服务器该怎么办?`HttpClient` 就会返回一个错误(error)而不再是成功的响应。
|
||||
|
||||
You _could_ handle in the component by adding a second callback to the `.subscribe()`:
|
||||
|
||||
|
@ -269,15 +269,15 @@ But displaying the raw error object returned by `HttpClient` is far from the bes
|
|||
Detecting that an error occurred is one thing.
|
||||
Interpreting that error and composing a user-friendly response is a bit more involved.
|
||||
|
||||
检测错误的发生是第一步,不过如果知道具体发生了什么错误才会更有用。上面例子中传给回调函数的`err`参数的类型是`HttpErrorResponse`,它包含了这个错误中一些很有用的信息。
|
||||
检测错误的发生是第一步,不过如果知道具体发生了什么错误才会更有用。上面例子中传给回调函数的 `err` 参数的类型是 `HttpErrorResponse`,它包含了这个错误中一些很有用的信息。
|
||||
|
||||
Two types of errors can occur. The server backend might reject the request, returning an HTTP response with a status code such as 404 or 500. These are error _responses_.
|
||||
|
||||
可能发生的错误分为两种。如果后端返回了一个失败的返回码(如404、500等),它会返回一个错误响应体。
|
||||
可能发生的错误分为两种。如果后端返回了一个失败的返回码(如 404、500 等),它会返回一个错误响应体。
|
||||
|
||||
Or something could go wrong on the client-side such as a network error that prevents the request from completing successfully or an exception thrown in an RxJS operator. These errors produce JavaScript `ErrorEvent` objects.
|
||||
|
||||
或者,如果在客户端这边出了错误(比如在RxJS操作符 (operator) 中抛出的异常或某些阻碍完成这个请求的网络错误),就会抛出一个`Error`类型的异常。
|
||||
或者,如果在客户端这边出了错误(比如在 RxJS 操作符 (operator) 中抛出的异常或某些阻碍完成这个请求的网络错误),就会抛出一个 `Error` 类型的异常。
|
||||
|
||||
The `HttpClient` captures both kinds of errors in its `HttpErrorResponse` and you can inspect that response to figure out what really happened.
|
||||
|
||||
|
@ -361,7 +361,7 @@ in a _functional, reactive style_.
|
|||
Many Angular APIs, including `HttpClient`, produce and consume RxJS `Observables`.
|
||||
|
||||
[RxJS](http://reactivex.io/rxjs/) 是一个库,用于把异步调用和基于回调的代码组合成*函数式(functional)的*、*响应式(reactive)的*风格。
|
||||
很多 Angular API,包括 `HttpClient`都会生成和消费 RxJS 的 `Observable`。
|
||||
很多 Angular API,包括 `HttpClient` 都会生成和消费 RxJS 的 `Observable`。
|
||||
|
||||
RxJS itself is out-of-scope for this guide. You will find many learning resources on the web.
|
||||
While you can get by with a minimum of RxJS knowledge, you'll want to grow your RxJS skills over time in order to use `HttpClient` effectively.
|
||||
|
@ -424,7 +424,7 @@ A `download()` method in the `DownloaderComponent` initiates the request by subs
|
|||
|
||||
In addition to fetching data from the server, `HttpClient` supports mutating requests, that is, sending data to the server with other HTTP methods such as PUT, POST, and DELETE.
|
||||
|
||||
除了从服务器获取数据之外,`HttpClient` 还支持修改型的请求,也就是说,通过`PUT`、`POST`、`DELETE` 这样的 HTTP 方法把数据发送到服务器。
|
||||
除了从服务器获取数据之外,`HttpClient` 还支持修改型的请求,也就是说,通过 `PUT`、`POST`、`DELETE` 这样的 HTTP 方法把数据发送到服务器。
|
||||
|
||||
The sample app for this guide includes a simplified version of the "Tour of Heroes" example
|
||||
that fetches heroes and enables users to add, delete, and update them.
|
||||
|
@ -649,7 +649,7 @@ The following `HeroService` example is just like the POST example.
|
|||
For the reasons [explained above](#always-subscribe), the caller (`HeroesComponent.update()` in this case) must `subscribe()` to the observable returned from the `HttpClient.put()`
|
||||
in order to initiate the request.
|
||||
|
||||
因为[前面解释过的](#always-subscribe)原因,调用者(这里是`HeroesComponent.update()`)必须 `subscribe()` 由 `HttpClient.put()` 返回的可观察对象,以发起这个调用。
|
||||
因为[前面解释过的](#always-subscribe)原因,调用者(这里是 `HeroesComponent.update()`)必须 `subscribe()` 由 `HttpClient.put()` 返回的可观察对象,以发起这个调用。
|
||||
|
||||
## Advanced usage
|
||||
|
||||
|
@ -927,7 +927,7 @@ Most interceptors call `next.handle()` so that the request flows through to the
|
|||
An interceptor _could_ skip calling `next.handle()`, short-circuit the chain, and [return its own `Observable`](#caching) with an artificial server response.
|
||||
|
||||
大多数的拦截器都会调用 `next.handle()`,以便这个请求流能走到下一个拦截器,并最终传给后端处理器。
|
||||
拦截器也*可以*不调用 `next.handle()`,使这个链路短路,并返回一个带有人工构造出来的服务器响应的 [自己的`Observable`](#caching)。
|
||||
拦截器也*可以*不调用 `next.handle()`,使这个链路短路,并返回一个带有人工构造出来的服务器响应的 [自己的 `Observable`](#caching)。
|
||||
|
||||
This is a common middleware pattern found in frameworks such as Express.js.
|
||||
|
||||
|
@ -1198,7 +1198,7 @@ An interceptor that alters headers can be used for a number of different operati
|
|||
|
||||
* Caching behavior; for example, `If-Modified-Since`
|
||||
|
||||
控制缓存行为。比如`If-Modified-Since`
|
||||
控制缓存行为。比如 `If-Modified-Since`
|
||||
|
||||
* XSRF protection
|
||||
|
||||
|
@ -1459,18 +1459,18 @@ by returning an observable of simulated events.
|
|||
|
||||
[Cross-Site Request Forgery (XSRF)](https://en.wikipedia.org/wiki/Cross-site_request_forgery) is an attack technique by which the attacker can trick an authenticated user into unknowingly executing actions on your website. `HttpClient` supports a [common mechanism](https://en.wikipedia.org/wiki/Cross-site_request_forgery#Cookie-to-Header_Token) used to prevent XSRF attacks. When performing HTTP requests, an interceptor reads a token from a cookie, by default `XSRF-TOKEN`, and sets it as an HTTP header, `X-XSRF-TOKEN`. Since only code that runs on your domain could read the cookie, the backend can be certain that the HTTP request came from your client application and not an attacker.
|
||||
|
||||
[跨站请求伪造 (XSRF)](https://en.wikipedia.org/wiki/Cross-site_request_forgery)是一个攻击技术,它能让攻击者假冒一个已认证的用户在你的网站上执行未知的操作。`HttpClient`支持一种[通用的机制](https://en.wikipedia.org/wiki/Cross-site_request_forgery#Cookie-to-Header_Token)来防范 XSRF 攻击。当执行 HTTP 请求时,一个拦截器会从cookie中读取 XSRF 令牌(默认名字为`XSRF-TOKEN`),并且把它设置为一个 HTTP 头 `X-XSRF-TOKEN`,由于只有运行在我们自己的域名下的代码才能读取这个 cookie,因此后端可以确认这个 HTTP 请求真的来自我们的客户端应用,而不是攻击者。
|
||||
[跨站请求伪造 (XSRF)](https://en.wikipedia.org/wiki/Cross-site_request_forgery)是一个攻击技术,它能让攻击者假冒一个已认证的用户在你的网站上执行未知的操作。`HttpClient` 支持一种[通用的机制](https://en.wikipedia.org/wiki/Cross-site_request_forgery#Cookie-to-Header_Token)来防范 XSRF 攻击。当执行 HTTP 请求时,一个拦截器会从 cookie 中读取 XSRF 令牌(默认名字为 `XSRF-TOKEN`),并且把它设置为一个 HTTP 头 `X-XSRF-TOKEN`,由于只有运行在我们自己的域名下的代码才能读取这个 cookie,因此后端可以确认这个 HTTP 请求真的来自我们的客户端应用,而不是攻击者。
|
||||
|
||||
By default, an interceptor sends this cookie on all mutating requests (POST, etc.)
|
||||
to relative URLs but not on GET/HEAD requests or
|
||||
on requests with an absolute URL.
|
||||
|
||||
默认情况下,拦截器会在所有的修改型请求中(比如POST等)把这个 cookie 发送给使用相对URL的请求。但不会在 GET/HEAD 请求中发送,也不会发送给使用绝对 URL 的请求。
|
||||
默认情况下,拦截器会在所有的修改型请求中(比如 POST 等)把这个 cookie 发送给使用相对 URL 的请求。但不会在 GET/HEAD 请求中发送,也不会发送给使用绝对 URL 的请求。
|
||||
|
||||
To take advantage of this, your server needs to set a token in a JavaScript readable session cookie called `XSRF-TOKEN` on either the page load or the first GET request. On subsequent requests the server can verify that the cookie matches the `X-XSRF-TOKEN` HTTP header, and therefore be sure that only code running on your domain could have sent the request. The token must be unique for each user and must be verifiable by the server; this prevents the client from making up its own tokens. Set the token to a digest of your site's authentication
|
||||
cookie with a salt for added security.
|
||||
|
||||
要获得这种优点,我们的服务器需要在页面加载或首个 GET 请求中把一个名叫`XSRF-TOKEN`的令牌写入可被 JavaScript 读到的会话 cookie 中。
|
||||
要获得这种优点,我们的服务器需要在页面加载或首个 GET 请求中把一个名叫 `XSRF-TOKEN` 的令牌写入可被 JavaScript 读到的会话 cookie 中。
|
||||
而在后续的请求中,服务器可以验证这个 cookie 是否与 HTTP 头 `X-XSRF-TOKEN` 的值一致,以确保只有运行在我们自己域名下的代码才能发起这个请求。这个令牌必须对每个用户都是唯一的,并且必须能被服务器验证,因此不能由客户端自己生成令牌。把这个令牌设置为你的站点认证信息并且加了盐(salt)的摘要,以提升安全性。
|
||||
|
||||
In order to prevent collisions in environments where multiple Angular apps share the same domain or subdomain, give each application a unique cookie name.
|
||||
|
@ -1484,7 +1484,7 @@ Your backend service must be configured to set the cookie for your page, and to
|
|||
the header is present on all eligible requests.
|
||||
If not, Angular's default protection will be ineffective.
|
||||
|
||||
*注意,`HttpClient`支持的只是 XSRF 防护方案的客户端这一半。* 我们的后端服务必须配置为给页面设置 cookie ,并且要验证请求头,以确保全都是合法的请求。否则,Angular 默认的这种防护措施就会失效。
|
||||
*注意,`HttpClient` 支持的只是 XSRF 防护方案的客户端这一半。* 我们的后端服务必须配置为给页面设置 cookie ,并且要验证请求头,以确保全都是合法的请求。否则,Angular 默认的这种防护措施就会失效。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -1559,7 +1559,7 @@ To begin testing calls to `HttpClient`,
|
|||
import the `HttpClientTestingModule` and the mocking controller, `HttpTestingController`,
|
||||
along with the other symbols your tests require.
|
||||
|
||||
要开始测试那些通过`HttpClient`发起的请求,就要导入`HttpClientTestingModule`模块,并把它加到你的`TestBed` 设置里去,代码如下:
|
||||
要开始测试那些通过 `HttpClient` 发起的请求,就要导入 `HttpClientTestingModule` 模块,并把它加到你的 `TestBed` 设置里去,代码如下:
|
||||
|
||||
<code-example
|
||||
path="http/src/testing/http-client.spec.ts"
|
||||
|
@ -1606,7 +1606,7 @@ Now you can write a test that expects a GET Request to occur and provides a mock
|
|||
|
||||
The last step, verifying that no requests remain outstanding, is common enough for you to move it into an `afterEach()` step:
|
||||
|
||||
最后一步,验证没有发起过预期之外的请求,足够通用,因此我们可以把它移到`afterEach()`中:
|
||||
最后一步,验证没有发起过预期之外的请求,足够通用,因此我们可以把它移到 `afterEach()` 中:
|
||||
|
||||
<code-example
|
||||
path="http/src/testing/http-client.spec.ts"
|
||||
|
@ -1646,7 +1646,7 @@ It takes the same arguments but returns an array of matching requests.
|
|||
Once returned, these requests are removed from future matching and
|
||||
you are responsible for flushing and verifying them.
|
||||
|
||||
如果我们需要在测试中对重复的请求进行响应,可以使用`match()` API 来代替 `expectOne()`,它的参数不变,但会返回一个与这些请求相匹配的数组。一旦返回,这些请求就会从将来要匹配的列表中移除,我们要自己验证和刷新(flush)它。
|
||||
如果我们需要在测试中对重复的请求进行响应,可以使用 `match()` API 来代替 `expectOne()`,它的参数不变,但会返回一个与这些请求相匹配的数组。一旦返回,这些请求就会从将来要匹配的列表中移除,我们要自己验证和刷新(flush)它。
|
||||
|
||||
<code-example
|
||||
path="http/src/testing/http-client.spec.ts"
|
||||
|
|
|
@ -173,7 +173,7 @@ In the example below, an `<h1>` tag displays a simple English language greeting,
|
|||
|
||||
To mark the greeting for translation, add the `i18n` attribute to the `<h1>` tag.
|
||||
|
||||
添加`i18n`属性到该标签上,把它标记为需要翻译的文本。
|
||||
添加 `i18n` 属性到该标签上,把它标记为需要翻译的文本。
|
||||
|
||||
<code-example path="i18n/doc-files/app.component.html" region="i18n-attribute" title="src/app/app.component.html" linenums="false">
|
||||
|
||||
|
@ -207,7 +207,7 @@ app context.
|
|||
You add context by beginning the `i18n` attribute value with the _meaning_ and
|
||||
separating it from the _description_ with the `|` character: `<meaning>|<description>`
|
||||
|
||||
在描述的前面,我们为指定的字符串添加一些上下文含义,用`|`将其与描述文字隔开(`<意图>|<描述>`)。
|
||||
在描述的前面,我们为指定的字符串添加一些上下文含义,用 `|` 将其与描述文字隔开(`<意图>|<描述>`)。
|
||||
|
||||
<code-example path="i18n/doc-files/app.component.html" region="i18n-attribute-meaning" title="src/app/app.component.html" linenums="false">
|
||||
|
||||
|
@ -224,18 +224,18 @@ text messages with different descriptions (not different meanings), then they ar
|
|||
|
||||
如果所有地方出现的文本具有**相同**含义时,它们应该有**相同**的翻译,
|
||||
但是如果在某些地方它具有**不同含义**,那么它应该有不同的翻译。
|
||||
Angular的提取工具在翻译源文件中保留**含义**和**描述**,以支持符合特定上下文的翻译。
|
||||
Angular 的提取工具在翻译源文件中保留**含义**和**描述**,以支持符合特定上下文的翻译。
|
||||
|
||||
{@a custom-id}
|
||||
|
||||
### Set a custom id for persistence and maintenance
|
||||
|
||||
### 设置一个自定义的`id`来提升可搜索性和可维护性
|
||||
### 设置一个自定义的 `id` 来提升可搜索性和可维护性
|
||||
|
||||
The angular i18n extractor tool generates a file with a translation unit entry for each `i18n`
|
||||
attribute in a template. By default, it assigns each translation unit a unique id such as this one:
|
||||
|
||||
Angular 的 `i18n` 提取工具会为模板中每个带有`i18n`属性的元素生成一个*翻译单元(translation unit)*条目,并保存到一个文件中。默认情况下,它为每个翻译单元指定一个唯一的`id`,就像这样:
|
||||
Angular 的 `i18n` 提取工具会为模板中每个带有 `i18n` 属性的元素生成一个*翻译单元(translation unit)*条目,并保存到一个文件中。默认情况下,它为每个翻译单元指定一个唯一的 `id`,就像这样:
|
||||
|
||||
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="generated-id" linenums="false">
|
||||
|
||||
|
@ -244,7 +244,7 @@ Angular 的 `i18n` 提取工具会为模板中每个带有`i18n`属性的元素
|
|||
When you change the translatable text, the extractor tool generates a new id for that translation unit.
|
||||
You must then update the translation file with the new id.
|
||||
|
||||
当我们修改这段可翻译的文字时,提取工具会为那个翻译单元生成一个新的`id`。
|
||||
当我们修改这段可翻译的文字时,提取工具会为那个翻译单元生成一个新的 `id`。
|
||||
我们就要使用这个新的 id 来修改这个翻译文件。
|
||||
|
||||
Alternatively, you can specify a custom id in the `i18n` attribute by using the prefix `@@`.
|
||||
|
@ -257,7 +257,7 @@ The example below defines the custom id `introductionHeader`:
|
|||
When you specify a custom id, the extractor tool and compiler generate a translation unit with that
|
||||
custom id.
|
||||
|
||||
现在,提取工具和编译器就会用*你的自定义id`生成一个翻译单元,而不会再改变它。
|
||||
现在,提取工具和编译器就会用*你的自定义 id` 生成一个翻译单元,而不会再改变它。
|
||||
|
||||
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="custom-id" linenums="false">
|
||||
|
||||
|
@ -278,7 +278,7 @@ by the custom `id`:
|
|||
|
||||
You also can add a meaning, as shown in this example:
|
||||
|
||||
下面这个例子带有*含义*和*描述*,最后是`id`:
|
||||
下面这个例子带有*含义*和*描述*,最后是 `id`:
|
||||
|
||||
<code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-meaning-and-id' title='app/app.component.html' linenums="false">
|
||||
|
||||
|
@ -289,7 +289,7 @@ You also can add a meaning, as shown in this example:
|
|||
Be sure to define custom ids that are unique. If you use the same id for two different text messages,
|
||||
only the first one is extracted, and its translation is used in place of both original text messages.
|
||||
|
||||
为了确保定义出*唯一*的自定义id。如果我们对两个*不同的*文本块使用了同一个id,那么就只有一个会被提取出来,然后其翻译结果会被用于全部文本块。
|
||||
为了确保定义出*唯一*的自定义 id。如果我们对两个*不同的*文本块使用了同一个 id,那么就只有一个会被提取出来,然后其翻译结果会被用于全部文本块。
|
||||
|
||||
In the example below the custom id `myId` is used for two different messages:
|
||||
|
||||
|
@ -338,8 +338,8 @@ However, if you don't want to create a new DOM element merely to facilitate tran
|
|||
you can wrap the text in an `<ng-container>` element.
|
||||
The `<ng-container>` is transformed into an html comment:
|
||||
|
||||
如果要翻译一段纯文本,我们就可以把它用`<span>`标签包裹起来。
|
||||
但如果由于某些原因(比如CSS结构方面的考虑),我们可能不希望仅仅为了翻译而创建一个新的DOM元素,那么也可以把这段文本包裹进一个`<ng-container>`元素中。`<ng-container>`将被转换成一个HTML注释:
|
||||
如果要翻译一段纯文本,我们就可以把它用 `<span>` 标签包裹起来。
|
||||
但如果由于某些原因(比如 CSS 结构方面的考虑),我们可能不希望仅仅为了翻译而创建一个新的 DOM 元素,那么也可以把这段文本包裹进一个 `<ng-container>` 元素中。`<ng-container>` 将被转换成一个 HTML 注释:
|
||||
|
||||
<code-example path="i18n/src/app/app.component.html" region="i18n-ng-container" title="src/app/app.component.html" linenums="false">
|
||||
|
||||
|
@ -355,7 +355,7 @@ You also can translate attributes.
|
|||
For example, assume that your template has an image with a `title` attribute:
|
||||
|
||||
我们还可以翻译属性。
|
||||
比如,假设我们的模板具有一个带`title`属性的图片:
|
||||
比如,假设我们的模板具有一个带 `title` 属性的图片:
|
||||
|
||||
<code-example path="i18n/doc-files/app.component.html" region="i18n-title" title="src/app/app.component.html" linenums="false">
|
||||
|
||||
|
@ -378,7 +378,7 @@ This technique works for any attribute of any element.
|
|||
You also can assign a meaning, description, and id with the `i18n-x="<meaning>|<description>@@<id>"`
|
||||
syntax.
|
||||
|
||||
我们也同样可以使用`i18n-x="<meaning>|<description>@@<id>"`语法来指定一个含义和描述。
|
||||
我们也同样可以使用 `i18n-x="<meaning>|<description>@@<id>"` 语法来指定一个含义和描述。
|
||||
|
||||
{@a plural-ICU}
|
||||
|
||||
|
@ -409,11 +409,11 @@ based on when the update occurred:
|
|||
* The first parameter is the key. It is bound to the component property (`minutes`), which determines
|
||||
the number of minutes.
|
||||
|
||||
第一个参数是key。它绑定到了组件中表示狼的数量的`wolves`属性。
|
||||
第一个参数是 key。它绑定到了组件中表示狼的数量的 `wolves` 属性。
|
||||
|
||||
* The second parameter identifies this as a `plural` translation type.
|
||||
|
||||
第二个参数表示这是一个`plural`(复数)翻译类型。
|
||||
第二个参数表示这是一个 `plural`(复数)翻译类型。
|
||||
|
||||
* The third parameter defines a pluralization pattern consisting of pluralization categories and their matching values.
|
||||
|
||||
|
@ -493,7 +493,7 @@ The following format message in the component template binds to the component's
|
|||
which outputs one of the following string values: "m", "f" or "o".
|
||||
The message maps those values to the appropriate translations:
|
||||
|
||||
组件模板中的下列消息格式绑定到了组件的`gender`属性,这个属性的取值是 "m" 或 "f" 或 "o"。
|
||||
组件模板中的下列消息格式绑定到了组件的 `gender` 属性,这个属性的取值是 "m" 或 "f" 或 "o"。
|
||||
这个消息会把那些值映射到适当的翻译文本:
|
||||
|
||||
<code-example path="i18n/src/app/app.component.html" region="i18n-select" title="src/app/app.component.html" linenums="false">
|
||||
|
@ -523,11 +523,11 @@ You can also nest different ICU expressions together, as shown in this example:
|
|||
Use the `ng xi18n` command provided by the CLI to extract the text messages marked with `i18n` into
|
||||
a translation source file.
|
||||
|
||||
使用`ng-xi18n`提取工具来将带`i18n`标记的文本提取到一个翻译源文件中。
|
||||
使用 `ng-xi18n` 提取工具来将带 `i18n` 标记的文本提取到一个翻译源文件中。
|
||||
|
||||
Open a terminal window at the root of the app project and enter the `ng xi18n` command:
|
||||
|
||||
在应用的项目根目录打开一个终端窗口,并输入`ng-xi18n`命令:
|
||||
在应用的项目根目录打开一个终端窗口,并输入 `ng-xi18n` 命令:
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
|
||||
|
@ -570,7 +570,7 @@ Bundle (XMB)</a>
|
|||
You can specify the translation format explicitly with the `--i18nFormat` flag as illustrated in
|
||||
these example commands:
|
||||
|
||||
我们可以使用`--i18nFormat`来明确指定想用的格式,范例如下:
|
||||
我们可以使用 `--i18nFormat` 来明确指定想用的格式,范例如下:
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
|
||||
|
@ -599,7 +599,7 @@ You can specify the output path used by the CLI to extract your translation sour
|
|||
the parameter `--outputPath`:
|
||||
|
||||
我们还可能需要指定其它选项。
|
||||
比如,如果TypeScript的配置文件`tsconfig.json`位于其它地方而不是根目录,我们就要通过`-p`选项来明确指出它的路径。
|
||||
比如,如果 TypeScript 的配置文件 `tsconfig.json` 位于其它地方而不是根目录,我们就要通过 `-p` 选项来明确指出它的路径。
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
|
||||
|
@ -636,7 +636,7 @@ file. This information is not used by Angular, but external translation tools ma
|
|||
The `ng xi18n` command generates a translation source file named `messages.xlf` in the project `src`
|
||||
folder.
|
||||
|
||||
`ng xi18n`命令在项目根目录生成一个名为`messages.xlf`的翻译源文件。
|
||||
`ng xi18n` 命令在项目根目录生成一个名为 `messages.xlf` 的翻译源文件。
|
||||
|
||||
The next step is to translate this source file into the specific language
|
||||
translation files. The example in this guide creates a French translation file.
|
||||
|
@ -697,7 +697,7 @@ If you were translating to other languages, you would repeat these steps for eac
|
|||
In a large translation project, you would send the `messages.fr.xlf` file to a French translator who
|
||||
would enter the translations using an XLIFF file editor.
|
||||
|
||||
在现实世界中,`messages.fr.xlf`文件会被发给法语翻译,他们使用<a href="https://en.wikipedia.org/wiki/XLIFF#Editors" target="_blank">这些XLIFF文件编辑器</a>中的一种来翻译它。
|
||||
在现实世界中,`messages.fr.xlf` 文件会被发给法语翻译,他们使用<a href="https://en.wikipedia.org/wiki/XLIFF#Editors" target="_blank">这些 XLIFF 文件编辑器</a>中的一种来翻译它。
|
||||
|
||||
This sample file is easy to translate without a special editor or knowledge of French.
|
||||
|
||||
|
@ -753,7 +753,7 @@ must be just below the translation unit for the logo.
|
|||
|
||||
To translate a `plural`, translate its ICU format match values:
|
||||
|
||||
要翻译一个复数,就要翻译它的ICU格式中匹配的值:
|
||||
要翻译一个复数,就要翻译它的 ICU 格式中匹配的值:
|
||||
|
||||
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-plural" title="src/locale/messages.fr.xlf (<trans-unit>)" linenums="false">
|
||||
|
||||
|
@ -784,8 +784,8 @@ In place of the `select` is a placeholder, `<x id="ICU">`, that represents the `
|
|||
Translate the text and move around the placeholder if necessary, but don't remove it. If you remove
|
||||
the placeholder, the ICU expression will not be present in your translated app.
|
||||
|
||||
第一个单元包含`select`之外的文本。
|
||||
这里的`select`是一个占位符`<x id="ICU">`,用来表示`select`中的消息。
|
||||
第一个单元包含 `select` 之外的文本。
|
||||
这里的 `select` 是一个占位符 `<x id="ICU">`,用来表示 `select` 中的消息。
|
||||
翻译这段文本,并把占位符放在那里。
|
||||
|
||||
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-select-1" title="src/locale/messages.fr.xlf (<trans-unit>)" linenums="false">
|
||||
|
@ -795,7 +795,7 @@ the placeholder, the ICU expression will not be present in your translated app.
|
|||
The second translation unit, immediately below the first one, contains the `select` message.
|
||||
Translate that as well.
|
||||
|
||||
第一个翻译单元的紧下方就是第二个翻译单元,包含`select`中的消息。翻译它。
|
||||
第一个翻译单元的紧下方就是第二个翻译单元,包含 `select` 中的消息。翻译它。
|
||||
|
||||
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-select-2" title="src/locale/messages.fr.xlf (<trans-unit>)" linenums="false">
|
||||
|
||||
|
@ -932,13 +932,13 @@ guide:
|
|||
|
||||
### Merge with the JIT compiler
|
||||
|
||||
### 用JiT编译器合并
|
||||
### 用 JiT 编译器合并
|
||||
|
||||
The JIT compiler compiles the app in the browser as the app loads.
|
||||
Translation with the JIT compiler is a dynamic process of:
|
||||
|
||||
JiT(即时)编译器在应用程序加载时,在浏览器中编译应用。
|
||||
在使用JiT编译器的环境中翻译是一个动态的流程,包括:
|
||||
在使用 JiT 编译器的环境中翻译是一个动态的流程,包括:
|
||||
|
||||
1. Importing the appropriate language translation file as a string constant.
|
||||
|
||||
|
@ -946,7 +946,7 @@ JiT(即时)编译器在应用程序加载时,在浏览器中编译应用
|
|||
|
||||
2. Creating corresponding translation providers for the JIT compiler.
|
||||
|
||||
为JiT编译器创建相应的翻译提供商。
|
||||
为 JiT 编译器创建相应的翻译提供商。
|
||||
|
||||
3. Bootstrapping the app with those providers.
|
||||
|
||||
|
@ -955,24 +955,24 @@ JiT(即时)编译器在应用程序加载时,在浏览器中编译应用
|
|||
Three providers tell the JIT compiler how to translate the template texts for a particular language
|
||||
while compiling the app:
|
||||
|
||||
三种提供商帮助JiT编译在编译应用时,将模板文本翻译到某种语言:
|
||||
三种提供商帮助 JiT 编译在编译应用时,将模板文本翻译到某种语言:
|
||||
|
||||
* `TRANSLATIONS` is a string containing the content of the translation file.
|
||||
|
||||
`TRANSLATIONS`是含有翻译文件内容的字符串。
|
||||
`TRANSLATIONS` 是含有翻译文件内容的字符串。
|
||||
|
||||
* `TRANSLATIONS_FORMAT` is the format of the file: `xlf`, `xlf2`, or `xtb`.
|
||||
|
||||
`TRANSLATIONS_FORMAT`是文件的格式: `xlf`、`xlif`或`xtb`。
|
||||
`TRANSLATIONS_FORMAT` 是文件的格式: `xlf`、`xlif` 或 `xtb`。
|
||||
|
||||
* `LOCALE_ID` is the locale of the target language.
|
||||
|
||||
`LOCALE_ID`是目标语言的语言环境。
|
||||
`LOCALE_ID` 是目标语言的语言环境。
|
||||
|
||||
The Angular `bootstrapModule` method has a second `compilerOptions` parameter that can influence the
|
||||
behavior of the compiler. You can use it to provide the translation providers:
|
||||
|
||||
在下面的`src/app/i18n-providers.ts`文件的`getTranslationProviders()`函数中,根据用户的**语言环境**和对应的翻译文件构建这些提供商:
|
||||
在下面的 `src/app/i18n-providers.ts` 文件的 `getTranslationProviders()` 函数中,根据用户的**语言环境**和对应的翻译文件构建这些提供商:
|
||||
|
||||
<code-example path="i18n/doc-files/main.2.ts" title="src/main.ts">
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@ opening an Angular file, reads your `tsconfig.json` file, finds all the
|
|||
templates you have in your application, and then provides language
|
||||
services for any templates that you open.
|
||||
|
||||
Angular 语言服务让我们能在模板内获得自动完成、错误检查、给出提示和内部导航等功能,而不用管这些模板位于外部HTML文件中还是内嵌在注解/装饰器的字符串中。
|
||||
Angular语言服务会自动检测我们要打开的文件(从我们的`tsconfig.json`中读取),找出应用中所需的所有模板,然后为我们打开的这些模板提供语言服务。
|
||||
Angular 语言服务让我们能在模板内获得自动完成、错误检查、给出提示和内部导航等功能,而不用管这些模板位于外部 HTML 文件中还是内嵌在注解/装饰器的字符串中。
|
||||
Angular 语言服务会自动检测我们要打开的文件(从我们的 `tsconfig.json` 中读取),找出应用中所需的所有模板,然后为我们打开的这些模板提供语言服务。
|
||||
|
||||
## Autocompletion
|
||||
|
||||
|
@ -22,7 +22,7 @@ contextual possibilities and hints as you type. This example shows
|
|||
autocomplete in an interpolation. As you type it out,
|
||||
you can hit tab to complete.
|
||||
|
||||
自动完成可以在输入时为我们提供当前情境下的候选内容和提示,从而提高开发速度。下面这个例子展示了插值表达式中的自动完成功能。当我们进行输入的时候,就可以按tab键来自动完成。
|
||||
自动完成可以在输入时为我们提供当前情境下的候选内容和提示,从而提高开发速度。下面这个例子展示了插值表达式中的自动完成功能。当我们进行输入的时候,就可以按 tab 键来自动完成。
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/language-service/language-completion.gif" alt="autocompletion">
|
||||
|
@ -41,7 +41,7 @@ show up in the completion list.
|
|||
The Angular Language Service can also forewarn you of mistakes in your code.
|
||||
In this example, Angular doesn't know what `orders` is or where it comes from.
|
||||
|
||||
Angular 语言服务还能对代码中存在的错误进行预警。在这个例子中,Angular 不知道什么是`orders`或者它来自哪里。
|
||||
Angular 语言服务还能对代码中存在的错误进行预警。在这个例子中,Angular 不知道什么是 `orders` 或者它来自哪里。
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/language-service/language-error.gif" alt="error checking">
|
||||
|
@ -107,7 +107,7 @@ colorization inside the template and autocomplete in addition to the Angular Lan
|
|||
Here's the dev dependency
|
||||
you need to have in `package.json`:
|
||||
|
||||
下面这个开发依赖需要添加到`package.json`中:
|
||||
下面这个开发依赖需要添加到 `package.json` 中:
|
||||
|
||||
```json
|
||||
|
||||
|
@ -120,7 +120,7 @@ devDependencies {
|
|||
Then in the terminal window at the root of your project,
|
||||
install the `devDependencies` with `npm` or `yarn`:
|
||||
|
||||
然后,打开终端窗口,在项目根目录下使用`npm`或`yarn`来安装这些`devDependencies`:
|
||||
然后,打开终端窗口,在项目根目录下使用 `npm` 或 `yarn` 来安装这些 `devDependencies`:
|
||||
|
||||
```sh
|
||||
|
||||
|
@ -156,7 +156,7 @@ In [Sublime Text](https://www.sublimetext.com/), you first need an extension to
|
|||
Install the latest version of typescript in a local `node_modules` directory:
|
||||
|
||||
在[Sublime Text](https://www.sublimetext.com/)中,我们首先需要一个扩展来支持 TypeScript。
|
||||
把最新版本的 TypeScript 安装到本地的`node_modules`目录下:
|
||||
把最新版本的 TypeScript 安装到本地的 `node_modules` 目录下:
|
||||
|
||||
```sh
|
||||
|
||||
|
@ -180,7 +180,7 @@ Starting with TypeScript 2.3, TypeScript has a language service plugin model tha
|
|||
|
||||
Next, in your user preferences (`Cmd+,` or `Ctrl+,`), add:
|
||||
|
||||
接下来,在你的用户首选项中(按`Cmd+,`或`Ctrl+,`)添加:
|
||||
接下来,在你的用户首选项中(按 `Cmd+,` 或 `Ctrl+,`)添加:
|
||||
|
||||
```json
|
||||
|
||||
|
@ -195,7 +195,7 @@ Next, in your user preferences (`Cmd+,` or `Ctrl+,`), add:
|
|||
You can also install Angular Language Service in your project with the
|
||||
following `npm` command:
|
||||
|
||||
我们还可以使用下列`npm`命令来把 Angular 语言服务安装到项目中:
|
||||
我们还可以使用下列 `npm` 命令来把 Angular 语言服务安装到项目中:
|
||||
|
||||
```sh
|
||||
|
||||
|
@ -206,7 +206,7 @@ npm install --save-dev @angular/language-service
|
|||
Additionally, add the following to the `"compilerOptions"` section of
|
||||
your project's `tsconfig.json`.
|
||||
|
||||
另外,还要在项目的`tsconfig.json`中添加下列`"compilerOptions"`区域:
|
||||
另外,还要在项目的 `tsconfig.json` 中添加下列 `"compilerOptions"` 区域:
|
||||
|
||||
```json
|
||||
|
||||
|
@ -220,7 +220,7 @@ Note that this only provides diagnostics and completions in `.ts`
|
|||
files. You need a custom sublime plugin (or modifications to the current plugin)
|
||||
for completions in HTML files.
|
||||
|
||||
注意,这只是提供了`.ts`文件中的诊断与自动完成。我们需要一个自定义的sublime插件(或修改现有插件)来在 HTML 文件中提供自动完成功能。
|
||||
注意,这只是提供了 `.ts` 文件中的诊断与自动完成。我们需要一个自定义的 sublime 插件(或修改现有插件)来在 HTML 文件中提供自动完成功能。
|
||||
|
||||
## How the Language Service works
|
||||
|
||||
|
@ -240,8 +240,8 @@ context, it can then determine what the children can be.
|
|||
|
||||
It's a little more involved if you are in an interpolation. If you have an interpolation of `{{data.---}}` inside a `div` and need the completion list after `data.---`, the compiler can't use the HTML AST to find the answer. The HTML AST can only tell the compiler that there is some text with the characters "`{{data.---}}`". That's when the template parser produces an expression AST, which resides within the template AST. The Angular Language Services then looks at `data.---` within its context and asks the TypeScript Language Service what the members of data are. TypeScript then returns the list of possibilities.
|
||||
|
||||
如果是在插值表达式中,还会牵扯到更多东西。如果我们在`div`元素中有一个插值表达式`{{data.---}}`,并且需要在输入了`data.`之后提供自动完成列表,编译器就没办法使用 HTML AST 来找出答案了。
|
||||
HTML AST只能告诉编译器,有一些具有 "`{{data.---}}`" 特征的文本。也就是说模板解析器会生成表达式的 AST ,并且放在模板的 AST 中。Angular 语言服务然后在这个情境下查找`data.---`,并向 TypeScript 语言服务询问这些数据都有哪些成员。然后 TypeScript 就会返回一个可能的列表。
|
||||
如果是在插值表达式中,还会牵扯到更多东西。如果我们在 `div` 元素中有一个插值表达式 `{{data.---}}`,并且需要在输入了 `data.` 之后提供自动完成列表,编译器就没办法使用 HTML AST 来找出答案了。
|
||||
HTML AST 只能告诉编译器,有一些具有 "`{{data.---}}`" 特征的文本。也就是说模板解析器会生成表达式的 AST ,并且放在模板的 AST 中。Angular 语言服务然后在这个情境下查找 `data.---`,并向 TypeScript 语言服务询问这些数据都有哪些成员。然后 TypeScript 就会返回一个可能的列表。
|
||||
|
||||
For more in-depth information, see the
|
||||
[Angular Language Service API](https://github.com/angular/angular/blob/master/packages/language-service/src/types.ts)
|
||||
|
@ -258,4 +258,4 @@ For more information, see [Chuck Jazdzewski's presentation](https://www.youtube.
|
|||
Service from [ng-conf](https://www.ng-conf.org/) 2017.
|
||||
|
||||
|
||||
要了解更多信息,参见 [ng-conf](https://www.ng-conf.org/) 2017 中 [Chuck Jazdzewski的演讲](https://www.youtube.com/watch?v=ez3R0Gi4z5A&t=368s) 中讲解的 Angular 语言服务。
|
||||
要了解更多信息,参见 [ng-conf](https://www.ng-conf.org/) 2017 中 [Chuck Jazdzewski 的演讲](https://www.youtube.com/watch?v=ez3R0Gi4z5A&t=368s) 中讲解的 Angular 语言服务。
|
||||
|
|
|
@ -4,17 +4,17 @@
|
|||
|
||||
A component has a lifecycle managed by Angular.
|
||||
|
||||
每个组件都有一个被Angular管理的生命周期。
|
||||
每个组件都有一个被 Angular 管理的生命周期。
|
||||
|
||||
Angular creates it, renders it, creates and renders its children,
|
||||
checks it when its data-bound properties change, and destroys it before removing it from the DOM.
|
||||
|
||||
Angular创建它,渲染它,创建并渲染它的子组件,在它被绑定的属性发生变化时检查它,并在它从DOM中被移除前销毁它。
|
||||
Angular 创建它,渲染它,创建并渲染它的子组件,在它被绑定的属性发生变化时检查它,并在它从 DOM 中被移除前销毁它。
|
||||
|
||||
Angular offers **lifecycle hooks**
|
||||
that provide visibility into these key life moments and the ability to act when they occur.
|
||||
|
||||
Angular提供了**生命周期钩子**,把这些关键生命时刻暴露出来,赋予我们在它们发生时采取行动的能力。
|
||||
Angular 提供了**生命周期钩子**,把这些关键生命时刻暴露出来,赋予我们在它们发生时采取行动的能力。
|
||||
|
||||
A directive has the same set of lifecycle hooks.
|
||||
|
||||
|
@ -32,21 +32,21 @@ Developers can tap into key moments in that lifecycle by implementing
|
|||
one or more of the *lifecycle hook* interfaces in the Angular `core` library.
|
||||
|
||||
指令和组件的实例有一个生命周期:新建、更新和销毁。
|
||||
通过实现一个或多个Angular `core`库里定义的*生命周期钩子*接口,开发者可以介入该生命周期中的这些关键时刻。
|
||||
通过实现一个或多个 Angular `core` 库里定义的*生命周期钩子*接口,开发者可以介入该生命周期中的这些关键时刻。
|
||||
|
||||
Each interface has a single hook method whose name is the interface name prefixed with `ng`.
|
||||
For example, the `OnInit` interface has a hook method named `ngOnInit()`
|
||||
that Angular calls shortly after creating the component:
|
||||
|
||||
每个接口都有唯一的一个钩子方法,它们的名字是由接口名再加上`ng`前缀构成的。比如,`OnInit`接口的钩子方法叫做`ngOnInit`,
|
||||
Angular在创建组件后立刻调用它,:
|
||||
每个接口都有唯一的一个钩子方法,它们的名字是由接口名再加上 `ng` 前缀构成的。比如,`OnInit` 接口的钩子方法叫做 `ngOnInit`,
|
||||
Angular 在创建组件后立刻调用它,:
|
||||
|
||||
<code-example path="lifecycle-hooks/src/app/peek-a-boo.component.ts" region="ngOnInit" title="peek-a-boo.component.ts (excerpt)" linenums="false"></code-example>
|
||||
|
||||
No directive or component will implement all of the lifecycle hooks.
|
||||
Angular only calls a directive/component hook method *if it is defined*.
|
||||
|
||||
没有指令或者组件会实现所有这些接口,并且有些钩子只对组件有意义。只有在指令/组件中*定义过的*那些钩子方法才会被Angular调用。
|
||||
没有指令或者组件会实现所有这些接口,并且有些钩子只对组件有意义。只有在指令/组件中*定义过的*那些钩子方法才会被 Angular 调用。
|
||||
|
||||
{@a hooks-purpose-timing}
|
||||
|
||||
|
@ -57,7 +57,7 @@ Angular only calls a directive/component hook method *if it is defined*.
|
|||
*After* creating a component/directive by calling its constructor, Angular
|
||||
calls the lifecycle hook methods in the following sequence at specific moments:
|
||||
|
||||
当Angular使用构造函数新建一个组件或指令后,就会按下面的顺序在特定时刻调用这些生命周期钩子方法:
|
||||
当 Angular 使用构造函数新建一个组件或指令后,就会按下面的顺序在特定时刻调用这些生命周期钩子方法:
|
||||
|
||||
<table width="100%">
|
||||
<col width="20%"></col>
|
||||
|
@ -92,12 +92,12 @@ calls the lifecycle hook methods in the following sequence at specific moments:
|
|||
Respond when Angular (re)sets data-bound input properties.
|
||||
The method receives a `SimpleChanges` object of current and previous property values.
|
||||
|
||||
当Angular(重新)设置数据绑定输入属性时响应。
|
||||
该方法接受当前和上一属性值的`SimpleChanges`对象
|
||||
当 Angular(重新)设置数据绑定输入属性时响应。
|
||||
该方法接受当前和上一属性值的 `SimpleChanges` 对象
|
||||
|
||||
Called before `ngOnInit()` and whenever one or more data-bound input properties change.
|
||||
|
||||
当被绑定的输入属性的值发生变化时调用,首次调用一定会发生在`ngOnInit()`之前。
|
||||
当被绑定的输入属性的值发生变化时调用,首次调用一定会发生在 `ngOnInit()` 之前。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -116,11 +116,11 @@ calls the lifecycle hook methods in the following sequence at specific moments:
|
|||
Initialize the directive/component after Angular first displays the data-bound properties
|
||||
and sets the directive/component's input properties.
|
||||
|
||||
在Angular第一次显示数据绑定和设置指令/组件的输入属性之后,初始化指令/组件。
|
||||
在 Angular 第一次显示数据绑定和设置指令/组件的输入属性之后,初始化指令/组件。
|
||||
|
||||
Called _once_, after the _first_ `ngOnChanges()`.
|
||||
|
||||
在第一轮`ngOnChanges()`完成之后调用,只调用**一次**。
|
||||
在第一轮 `ngOnChanges()` 完成之后调用,只调用**一次**。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -138,11 +138,11 @@ calls the lifecycle hook methods in the following sequence at specific moments:
|
|||
|
||||
Detect and act upon changes that Angular can't or won't detect on its own.
|
||||
|
||||
检测,并在发生Angular无法或不愿意自己检测的变化时作出反应。
|
||||
检测,并在发生 Angular 无法或不愿意自己检测的变化时作出反应。
|
||||
|
||||
Called during every change detection run, immediately after `ngOnChanges()` and `ngOnInit()`.
|
||||
|
||||
在每个Angular变更检测周期中调用,`ngOnChanges()`和`ngOnInit()`之后。
|
||||
在每个 Angular 变更检测周期中调用,`ngOnChanges()` 和 `ngOnInit()` 之后。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -164,7 +164,7 @@ calls the lifecycle hook methods in the following sequence at specific moments:
|
|||
|
||||
Called _once_ after the first `ngDoCheck()`.
|
||||
|
||||
第一次`ngDoCheck()`之后调用,只调用一次。
|
||||
第一次 `ngDoCheck()` 之后调用,只调用一次。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -186,7 +186,7 @@ calls the lifecycle hook methods in the following sequence at specific moments:
|
|||
|
||||
Called after the `ngAfterContentInit()` and every subsequent `ngDoCheck()`.
|
||||
|
||||
`ngAfterContentInit()`和每次`ngDoCheck()`之后调用
|
||||
`ngAfterContentInit()` 和每次 `ngDoCheck()` 之后调用
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -208,7 +208,7 @@ calls the lifecycle hook methods in the following sequence at specific moments:
|
|||
|
||||
Called _once_ after the first `ngAfterContentChecked()`.
|
||||
|
||||
第一次`ngAfterContentChecked()`之后调用,只调用一次。
|
||||
第一次 `ngAfterContentChecked()` 之后调用,只调用一次。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -230,7 +230,7 @@ calls the lifecycle hook methods in the following sequence at specific moments:
|
|||
|
||||
Called after the `ngAfterViewInit` and every subsequent `ngAfterContentChecked()`.
|
||||
|
||||
`ngAfterViewInit()`和每次`ngAfterContentChecked()`之后调用。
|
||||
`ngAfterViewInit()` 和每次 `ngAfterContentChecked()` 之后调用。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -249,12 +249,12 @@ calls the lifecycle hook methods in the following sequence at specific moments:
|
|||
Cleanup just before Angular destroys the directive/component.
|
||||
Unsubscribe Observables and detach event handlers to avoid memory leaks.
|
||||
|
||||
当Angular每次销毁指令/组件之前调用并清扫。
|
||||
当 Angular 每次销毁指令/组件之前调用并清扫。
|
||||
在这儿反订阅可观察对象和分离事件处理器,以防内存泄漏。
|
||||
|
||||
Called _just before_ Angular destroys the directive/component.
|
||||
|
||||
在Angular销毁指令/组件之前调用。
|
||||
在 Angular 销毁指令/组件之前调用。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -272,8 +272,8 @@ The interfaces are optional for JavaScript and Typescript developers from a pure
|
|||
The JavaScript language doesn't have interfaces.
|
||||
Angular can't see TypeScript interfaces at runtime because they disappear from the transpiled JavaScript.
|
||||
|
||||
从纯技术的角度讲,接口对JavaScript和TypeScript的开发者都是可选的。JavaScript语言本身没有接口。
|
||||
Angular在运行时看不到TypeScript接口,因为它们在编译为JavaScript的时候已经消失了。
|
||||
从纯技术的角度讲,接口对 JavaScript 和 TypeScript 的开发者都是可选的。JavaScript 语言本身没有接口。
|
||||
Angular 在运行时看不到 TypeScript 接口,因为它们在编译为 JavaScript 的时候已经消失了。
|
||||
|
||||
Fortunately, they aren't necessary.
|
||||
You don't have to add the lifecycle hook interfaces to directives and components to benefit from the hooks themselves.
|
||||
|
@ -284,13 +284,13 @@ You don't have to add the lifecycle hook interfaces to directives and components
|
|||
Angular instead inspects directive and component classes and calls the hook methods *if they are defined*.
|
||||
Angular finds and calls methods like `ngOnInit()`, with or without the interfaces.
|
||||
|
||||
Angular会去检测我们的指令和组件的类,一旦发现钩子方法被定义了,就调用它们。
|
||||
Angular会找到并调用像`ngOnInit()`这样的钩子方法,有没有接口无所谓。
|
||||
Angular 会去检测我们的指令和组件的类,一旦发现钩子方法被定义了,就调用它们。
|
||||
Angular 会找到并调用像 `ngOnInit()` 这样的钩子方法,有没有接口无所谓。
|
||||
|
||||
Nonetheless, it's good practice to add interfaces to TypeScript directive classes
|
||||
in order to benefit from strong typing and editor tooling.
|
||||
|
||||
虽然如此,我们还是强烈建议你在TypeScript指令类中添加接口,以获得强类型和IDE等编辑器带来的好处。
|
||||
虽然如此,我们还是强烈建议你在 TypeScript 指令类中添加接口,以获得强类型和 IDE 等编辑器带来的好处。
|
||||
|
||||
{@a other-lifecycle-hooks}
|
||||
|
||||
|
@ -300,7 +300,7 @@ in order to benefit from strong typing and editor tooling.
|
|||
|
||||
Other Angular sub-systems may have their own lifecycle hooks apart from these component hooks.
|
||||
|
||||
Angular的其它子系统除了有这些组件钩子外,还可能有它们自己的生命周期钩子。
|
||||
Angular 的其它子系统除了有这些组件钩子外,还可能有它们自己的生命周期钩子。
|
||||
|
||||
3rd party libraries might implement their hooks as well in order to give developers more
|
||||
control over how these libraries are used.
|
||||
|
@ -317,7 +317,7 @@ The <live-example></live-example>
|
|||
demonstrates the lifecycle hooks in action through a series of exercises
|
||||
presented as components under the control of the root `AppComponent`.
|
||||
|
||||
<live-example></live-example>通过在受控于根组件`AppComponent`的一些组件上进行的一系列练习,演示了生命周期钩子的运作方式。
|
||||
<live-example></live-example>通过在受控于根组件 `AppComponent` 的一些组件上进行的一系列练习,演示了生命周期钩子的运作方式。
|
||||
|
||||
They follow a common pattern: a *parent* component serves as a test rig for
|
||||
a *child* component that illustrates one or more of the lifecycle hook methods.
|
||||
|
@ -383,12 +383,12 @@ Here's a brief description of each exercise:
|
|||
A `SpyDirective` can log when the element it spies upon is
|
||||
created or destroyed using the `ngOnInit` and `ngOnDestroy` hooks.
|
||||
|
||||
指令也同样有生命周期钩子。我们新建了一个`SpyDirective`,利用`ngOnInit`和`ngOnDestroy`钩子,在它所监视的每个元素被创建或销毁时输出日志。
|
||||
指令也同样有生命周期钩子。我们新建了一个 `SpyDirective`,利用 `ngOnInit` 和 `ngOnDestroy` 钩子,在它所监视的每个元素被创建或销毁时输出日志。
|
||||
|
||||
This example applies the `SpyDirective` to a `<div>` in an `ngFor` *hero* repeater
|
||||
managed by the parent `SpyComponent`.
|
||||
|
||||
本例把`SpyDirective`应用到父组件里的`ngFor`*英雄*重复器(repeater)的`<div>`里面。
|
||||
本例把 `SpyDirective` 应用到父组件里的 `ngFor`*英雄*重复器(repeater)的 `<div>` 里面。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -408,8 +408,8 @@ Here's a brief description of each exercise:
|
|||
every time one of the component input properties changes.
|
||||
Shows how to interpret the `changes` object.
|
||||
|
||||
这里将会看到:每当组件的输入属性发生变化时,Angular会如何以`changes`对象作为参数去调用`ngOnChanges()`钩子。
|
||||
展示了该如何理解和使用`changes`对象。
|
||||
这里将会看到:每当组件的输入属性发生变化时,Angular 会如何以 `changes` 对象作为参数去调用 `ngOnChanges()` 钩子。
|
||||
展示了该如何理解和使用 `changes` 对象。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -428,8 +428,8 @@ Here's a brief description of each exercise:
|
|||
Implements an `ngDoCheck()` method with custom change detection.
|
||||
See how often Angular calls this hook and watch it post changes to a log.
|
||||
|
||||
实现了一个`ngDoCheck()`方法,通过它可以自定义变更检测逻辑。
|
||||
这里将会看到:Angular会用什么频度调用这个钩子,监视它的变化,并把这些变化输出成一条日志。
|
||||
实现了一个 `ngDoCheck()` 方法,通过它可以自定义变更检测逻辑。
|
||||
这里将会看到:Angular 会用什么频度调用这个钩子,监视它的变化,并把这些变化输出成一条日志。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -448,8 +448,8 @@ Here's a brief description of each exercise:
|
|||
Shows what Angular means by a *view*.
|
||||
Demonstrates the `ngAfterViewInit` and `ngAfterViewChecked` hooks.
|
||||
|
||||
显示Angular中的*视图*所指的是什么。
|
||||
演示了`ngAfterViewInit`和`ngAfterViewChecked`钩子。
|
||||
显示 Angular 中的*视图*所指的是什么。
|
||||
演示了 `ngAfterViewInit` 和 `ngAfterViewChecked` 钩子。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -470,7 +470,7 @@ Here's a brief description of each exercise:
|
|||
Demonstrates the `ngAfterContentInit` and `ngAfterContentChecked` hooks.
|
||||
|
||||
展示如何把外部内容投影进组件中,以及如何区分“投影进来的内容”和“组件的子视图”。
|
||||
演示了`ngAfterContentInit`和`ngAfterContentChecked`钩子。
|
||||
演示了 `ngAfterContentInit` 和 `ngAfterContentChecked` 钩子。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -498,8 +498,8 @@ Here's a brief description of each exercise:
|
|||
Meanwhile, the `SpyDirective` from the previous example is applied
|
||||
to the `CounterComponent` log where it watches log entries being created and destroyed.
|
||||
|
||||
在这个例子中,每当父组件递增它的输入属性`counter`时,`CounterComponent`就会通过`ngOnChanges`记录一条变更。
|
||||
同时,我们还把前一个例子中的`SpyDirective`用在`CounterComponent`上,来提供日志,可以同时观察到日志的创建和销毁过程。
|
||||
在这个例子中,每当父组件递增它的输入属性 `counter` 时,`CounterComponent` 就会通过 `ngOnChanges` 记录一条变更。
|
||||
同时,我们还把前一个例子中的 `SpyDirective` 用在 `CounterComponent` 上,来提供日志,可以同时观察到日志的创建和销毁过程。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -519,13 +519,13 @@ The remainder of this page discusses selected exercises in further detail.
|
|||
|
||||
The `PeekABooComponent` demonstrates all of the hooks in one component.
|
||||
|
||||
`PeekABooComponent`组件演示了组件中所有可能存在的钩子。
|
||||
`PeekABooComponent` 组件演示了组件中所有可能存在的钩子。
|
||||
|
||||
You would rarely, if ever, implement all of the interfaces like this.
|
||||
The peek-a-boo exists to show how Angular calls the hooks in the expected order.
|
||||
|
||||
你可能很少、或者永远不会像这里一样实现所有这些接口。
|
||||
我们之所以在peek-a-boo中这么做,只是为了观看Angular是如何按照期望的顺序调用这些钩子的。
|
||||
我们之所以在 peek-a-boo 中这么做,只是为了观看 Angular 是如何按照期望的顺序调用这些钩子的。
|
||||
|
||||
This snapshot reflects the state of the log after the user clicked the *Create...* button and then the *Destroy...* button.
|
||||
|
||||
|
@ -541,15 +541,15 @@ The sequence of log messages follows the prescribed hook calling order:
|
|||
|
||||
日志信息的日志和所规定的钩子调用顺序是一致的:
|
||||
`OnChanges`、`OnInit`、`DoCheck` (3x)、`AfterContentInit`、`AfterContentChecked` (3x)、
|
||||
`AfterViewInit`、`AfterViewChecked` (3x)和`OnDestroy`
|
||||
`AfterViewInit`、`AfterViewChecked` (3x)和 `OnDestroy`
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
The constructor isn't an Angular hook *per se*.
|
||||
The log confirms that input properties (the `name` property in this case) have no assigned values at construction.
|
||||
|
||||
构造函数本质上不应该算作Angular的钩子。
|
||||
记录确认了在创建期间那些输入属性(这里是`name`属性)没有被赋值。
|
||||
构造函数本质上不应该算作 Angular 的钩子。
|
||||
记录确认了在创建期间那些输入属性(这里是 `name` 属性)没有被赋值。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -557,7 +557,7 @@ Had the user clicked the *Update Hero* button, the log would show another `OnCha
|
|||
`DoCheck`, `AfterContentChecked` and `AfterViewChecked`.
|
||||
Clearly these three hooks fire *often*. Keep the logic in these hooks as lean as possible!
|
||||
|
||||
如果我们点击*Update Hero*按钮,就会看到另一个`OnChanges`和至少两组`DoCheck`、`AfterContentChecked`和`AfterViewChecked`钩子。
|
||||
如果我们点击*Update Hero*按钮,就会看到另一个 `OnChanges` 和至少两组 `DoCheck`、`AfterContentChecked` 和 `AfterViewChecked` 钩子。
|
||||
显然,这三种钩子被触发了*很多次*,所以我们必须让这三种钩子里的逻辑尽可能的精简!
|
||||
|
||||
The next examples focus on hook details.
|
||||
|
@ -572,7 +572,7 @@ The next examples focus on hook details.
|
|||
|
||||
Go undercover with these two spy hooks to discover when an element is initialized or destroyed.
|
||||
|
||||
潜入这两个spy钩子来发现一个元素是什么时候被初始化或者销毁的。
|
||||
潜入这两个 spy 钩子来发现一个元素是什么时候被初始化或者销毁的。
|
||||
|
||||
This is the perfect infiltration job for a directive.
|
||||
The heroes will never know they're being watched.
|
||||
|
@ -587,15 +587,15 @@ The heroes will never know they're being watched.
|
|||
|
||||
1. Angular calls hook methods for *directives* as well as components.<br><br>
|
||||
|
||||
就像对组件一样,Angular也会对*指令*调用这些钩子方法。<br><br>
|
||||
就像对组件一样,Angular 也会对*指令*调用这些钩子方法。<br><br>
|
||||
|
||||
2. A spy directive can provide insight into a DOM object that you cannot change directly.
|
||||
Obviously you can't touch the implementation of a native `<div>`.
|
||||
You can't modify a third party component either.
|
||||
But you can watch both with a directive.
|
||||
|
||||
一个侦探(spy)指令可以让我们在无法直接修改DOM对象实现代码的情况下,透视其内部细节。
|
||||
显然,你不能修改一个原生`<div>`元素的实现代码。
|
||||
一个侦探(spy)指令可以让我们在无法直接修改 DOM 对象实现代码的情况下,透视其内部细节。
|
||||
显然,你不能修改一个原生 `<div>` 元素的实现代码。
|
||||
你同样不能修改第三方组件。
|
||||
但我们用一个指令就能监视它们了。
|
||||
|
||||
|
@ -604,7 +604,7 @@ The heroes will never know they're being watched.
|
|||
The sneaky spy directive is simple, consisting almost entirely of `ngOnInit()` and `ngOnDestroy()` hooks
|
||||
that log messages to the parent via an injected `LoggerService`.
|
||||
|
||||
我们这个鬼鬼祟祟的侦探指令很简单,几乎完全由`ngOnInit()`和`ngOnDestroy()`钩子组成,它通过一个注入进来的`LoggerService`来把消息记录到父组件中去。
|
||||
我们这个鬼鬼祟祟的侦探指令很简单,几乎完全由 `ngOnInit()` 和 `ngOnDestroy()` 钩子组成,它通过一个注入进来的 `LoggerService` 来把消息记录到父组件中去。
|
||||
|
||||
<code-example path="lifecycle-hooks/src/app/spy.directive.ts" region="spy-directive" title="src/app/spy.directive.ts" linenums="false"></code-example>
|
||||
|
||||
|
@ -613,14 +613,14 @@ at the same time as that element.
|
|||
Here it is attached to the repeated hero `<div>`:
|
||||
|
||||
我们可以把这个侦探指令写到任何原生元素或组件元素上,它将与所在的组件同时初始化和销毁。
|
||||
下面是把它附加到用来重复显示英雄数据的这个`<div>`上。
|
||||
下面是把它附加到用来重复显示英雄数据的这个 `<div>` 上。
|
||||
|
||||
<code-example path="lifecycle-hooks/src/app/spy.component.html" region="template" title="src/app/spy.component.html" linenums="false"></code-example>
|
||||
|
||||
Each spy's birth and death marks the birth and death of the attached hero `<div>`
|
||||
with an entry in the *Hook Log* as seen here:
|
||||
|
||||
每个“侦探”的出生和死亡也同时标记出了存放英雄的那个`<div>`的出生和死亡。*钩子记录*中的结构是这样的:
|
||||
每个“侦探”的出生和死亡也同时标记出了存放英雄的那个 `<div>` 的出生和死亡。*钩子记录*中的结构是这样的:
|
||||
|
||||
<figure>
|
||||
<img src='generated/images/guide/lifecycle-hooks/spy-directive.gif' alt="Spy Directive">
|
||||
|
@ -628,19 +628,19 @@ with an entry in the *Hook Log* as seen here:
|
|||
|
||||
Adding a hero results in a new hero `<div>`. The spy's `ngOnInit()` logs that event.
|
||||
|
||||
添加一个英雄就会产生一个新的英雄`<div>`。侦探的`ngOnInit()`记录下了这个事件。
|
||||
添加一个英雄就会产生一个新的英雄 `<div>`。侦探的 `ngOnInit()` 记录下了这个事件。
|
||||
|
||||
The *Reset* button clears the `heroes` list.
|
||||
Angular removes all hero `<div>` elements from the DOM and destroys their spy directives at the same time.
|
||||
The spy's `ngOnDestroy()` method reports its last moments.
|
||||
|
||||
*Reset*按钮清除了这个`heroes`列表。
|
||||
Angular从DOM中移除了所有英雄的div,并且同时销毁了附加在这些div上的侦探指令。
|
||||
侦探的`ngOnDestroy()`方法汇报了它自己的临终时刻。
|
||||
*Reset*按钮清除了这个 `heroes` 列表。
|
||||
Angular 从 DOM 中移除了所有英雄的 div,并且同时销毁了附加在这些 div 上的侦探指令。
|
||||
侦探的 `ngOnDestroy()` 方法汇报了它自己的临终时刻。
|
||||
|
||||
The `ngOnInit()` and `ngOnDestroy()` methods have more vital roles to play in real applications.
|
||||
|
||||
在真实的应用程序中,`ngOnInit()`和`ngOnDestroy()`方法扮演着更重要的角色。
|
||||
在真实的应用程序中,`ngOnInit()` 和 `ngOnDestroy()` 方法扮演着更重要的角色。
|
||||
|
||||
{@a oninit}
|
||||
|
||||
|
@ -650,7 +650,7 @@ The `ngOnInit()` and `ngOnDestroy()` methods have more vital roles to play in re
|
|||
|
||||
Use `ngOnInit()` for two main reasons:
|
||||
|
||||
使用`ngOnInit()`有两个原因:
|
||||
使用 `ngOnInit()` 有两个原因:
|
||||
|
||||
1. To perform complex initializations shortly after construction.
|
||||
|
||||
|
@ -658,7 +658,7 @@ Use `ngOnInit()` for two main reasons:
|
|||
|
||||
1. To set up the component after Angular sets the input properties.
|
||||
|
||||
在Angular设置完输入属性之后,对该组件进行准备。
|
||||
在 Angular 设置完输入属性之后,对该组件进行准备。
|
||||
|
||||
Experienced developers agree that components should be cheap and safe to construct.
|
||||
|
||||
|
@ -670,7 +670,7 @@ Experienced developers agree that components should be cheap and safe to constru
|
|||
[explains why](http://misko.hevery.com/code-reviewers-guide/flaw-constructor-does-real-work/)
|
||||
you should avoid complex constructor logic.
|
||||
|
||||
Misko Hevery,Angular项目的组长,在[这里解释](http://misko.hevery.com/code-reviewers-guide/flaw-constructor-does-real-work/)了你为什么应该避免复杂的构造函数逻辑。
|
||||
Misko Hevery,Angular 项目的组长,在[这里解释](http://misko.hevery.com/code-reviewers-guide/flaw-constructor-does-real-work/)了你为什么应该避免复杂的构造函数逻辑。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -686,7 +686,7 @@ Constructors should do no more than set the initial local variables to simple va
|
|||
An `ngOnInit()` is a good place for a component to fetch its initial data. The
|
||||
[Tour of Heroes Tutorial](tutorial/toh-pt4#oninit) guide shows how.
|
||||
|
||||
`ngOnInit()`是组件获取初始数据的好地方。[指南](tutorial/toh-pt4#oninit)中讲解了如何这样做。
|
||||
`ngOnInit()` 是组件获取初始数据的好地方。[指南](tutorial/toh-pt4#oninit)中讲解了如何这样做。
|
||||
|
||||
Remember also that a directive's data-bound input properties are not set until _after construction_.
|
||||
That's a problem if you need to initialize the directive based on those properties.
|
||||
|
@ -694,7 +694,7 @@ They'll have been set when `ngOnInit()` runs.
|
|||
|
||||
另外还要记住,在指令的_构造函数完成之前_,那些被绑定的输入属性还都没有值。
|
||||
如果我们需要基于这些属性的值来初始化这个指令,这种情况就会出问题。
|
||||
而当`ngOnInit()`执行的时候,这些属性都已经被正确的赋值过了。
|
||||
而当 `ngOnInit()` 执行的时候,这些属性都已经被正确的赋值过了。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
|
@ -702,15 +702,15 @@ They'll have been set when `ngOnInit()` runs.
|
|||
Angular calls `ngOnChanges()` before `ngOnInit()` and many times after that.
|
||||
It only calls `ngOnInit()` once.
|
||||
|
||||
我们访问这些属性的第一次机会,实际上是`ngOnChanges()`方法,Angular会在`ngOnInit()`之前调用它。
|
||||
但是在那之后,Angular还会调用`ngOnChanges()`很多次。而`ngOnInit()`只会被调用一次。
|
||||
我们访问这些属性的第一次机会,实际上是 `ngOnChanges()` 方法,Angular 会在 `ngOnInit()` 之前调用它。
|
||||
但是在那之后,Angular 还会调用 `ngOnChanges()` 很多次。而 `ngOnInit()` 只会被调用一次。
|
||||
|
||||
</div>
|
||||
|
||||
You can count on Angular to call the `ngOnInit()` method _soon_ after creating the component.
|
||||
That's where the heavy initialization logic belongs.
|
||||
|
||||
你可以信任Angular会在创建组件后立刻调用`ngOnInit()`方法。
|
||||
你可以信任 Angular 会在创建组件后立刻调用 `ngOnInit()` 方法。
|
||||
这里是放置复杂初始化逻辑的好地方。
|
||||
|
||||
{@a ondestroy}
|
||||
|
@ -721,7 +721,7 @@ That's where the heavy initialization logic belongs.
|
|||
|
||||
Put cleanup logic in `ngOnDestroy()`, the logic that *must* run before Angular destroys the directive.
|
||||
|
||||
一些清理逻辑*必须*在Angular销毁指令之前运行,把它们放在`ngOnDestroy()`中。
|
||||
一些清理逻辑*必须*在 Angular 销毁指令之前运行,把它们放在 `ngOnDestroy()` 中。
|
||||
|
||||
This is the time to notify another part of the application that the component is going away.
|
||||
|
||||
|
@ -733,7 +733,7 @@ Unregister all callbacks that this directive registered with global or applicati
|
|||
You risk memory leaks if you neglect to do so.
|
||||
|
||||
这里是用来释放那些不会被垃圾收集器自动回收的各类资源的地方。
|
||||
取消那些对可观察对象和DOM事件的订阅。停止定时器。注销该指令曾注册到全局服务或应用级服务中的各种回调函数。
|
||||
取消那些对可观察对象和 DOM 事件的订阅。停止定时器。注销该指令曾注册到全局服务或应用级服务中的各种回调函数。
|
||||
如果不这么做,就会有导致内存泄露的风险。
|
||||
|
||||
{@a onchanges}
|
||||
|
@ -745,8 +745,8 @@ You risk memory leaks if you neglect to do so.
|
|||
Angular calls its `ngOnChanges()` method whenever it detects changes to ***input properties*** of the component (or directive).
|
||||
This example monitors the `OnChanges` hook.
|
||||
|
||||
一旦检测到该组件(或指令)的***输入属性***发生了变化,Angular就会调用它的`ngOnChanges()`方法。
|
||||
本例监控`OnChanges`钩子。
|
||||
一旦检测到该组件(或指令)的***输入属性***发生了变化,Angular 就会调用它的 `ngOnChanges()` 方法。
|
||||
本例监控 `OnChanges` 钩子。
|
||||
|
||||
<code-example path="lifecycle-hooks/src/app/on-changes.component.ts" region="ng-on-changes" title="on-changes.component.ts (excerpt)" linenums="false"></code-example>
|
||||
|
||||
|
@ -754,18 +754,18 @@ The `ngOnChanges()` method takes an object that maps each changed property name
|
|||
[SimpleChange](api/core/SimpleChange) object holding the current and previous property values.
|
||||
This hook iterates over the changed properties and logs them.
|
||||
|
||||
`ngOnChanges()`方法获取了一个对象,它把每个发生变化的属性名都映射到了一个[SimpleChange](api/core/SimpleChange)对象,
|
||||
`ngOnChanges()` 方法获取了一个对象,它把每个发生变化的属性名都映射到了一个[SimpleChange](api/core/SimpleChange)对象,
|
||||
该对象中有属性的当前值和前一个值。我们在这些发生了变化的属性上进行迭代,并记录它们。
|
||||
|
||||
The example component, `OnChangesComponent`, has two input properties: `hero` and `power`.
|
||||
|
||||
这个例子中的`OnChangesComponent`组件有两个输入属性:`hero`和`power`。
|
||||
这个例子中的 `OnChangesComponent` 组件有两个输入属性:`hero` 和 `power`。
|
||||
|
||||
<code-example path="lifecycle-hooks/src/app/on-changes.component.ts" region="inputs" title="src/app/on-changes.component.ts" linenums="false"></code-example>
|
||||
|
||||
The host `OnChangesParentComponent` binds to them like this:
|
||||
|
||||
宿主`OnChangesParentComponent`绑定了它们,就像这样:
|
||||
宿主 `OnChangesParentComponent` 绑定了它们,就像这样:
|
||||
|
||||
<code-example path="lifecycle-hooks/src/app/on-changes-parent.component.html" region="on-changes" title="src/app/on-changes-parent.component.html"></code-example>
|
||||
|
||||
|
@ -782,7 +782,7 @@ But the `ngOnChanges` does not catch changes to `hero.name`
|
|||
That's surprising at first.
|
||||
|
||||
当*power*属性的字符串值变化时,相应的日志就出现了。
|
||||
但是`ngOnChanges`并没有捕捉到`hero.name`的变化。
|
||||
但是 `ngOnChanges` 并没有捕捉到 `hero.name` 的变化。
|
||||
这是第一个意外。
|
||||
|
||||
Angular only calls the hook when the value of the input property changes.
|
||||
|
@ -790,10 +790,10 @@ The value of the `hero` property is the *reference to the hero object*.
|
|||
Angular doesn't care that the hero's own `name` property changed.
|
||||
The hero object *reference* didn't change so, from Angular's perspective, there is no change to report!
|
||||
|
||||
Angular只会在输入属性的值变化时调用这个钩子。
|
||||
而`hero`属性的值是一个*到英雄对象的引用*。
|
||||
Angular不会关注这个英雄对象的`name`属性的变化。
|
||||
这个英雄对象的*引用*没有发生变化,于是从Angular的视角看来,也就没有什么需要报告的变化了。
|
||||
Angular 只会在输入属性的值变化时调用这个钩子。
|
||||
而 `hero` 属性的值是一个*到英雄对象的引用*。
|
||||
Angular 不会关注这个英雄对象的 `name` 属性的变化。
|
||||
这个英雄对象的*引用*没有发生变化,于是从 Angular 的视角看来,也就没有什么需要报告的变化了。
|
||||
|
||||
{@a docheck}
|
||||
|
||||
|
@ -803,19 +803,19 @@ Angular不会关注这个英雄对象的`name`属性的变化。
|
|||
|
||||
Use the `DoCheck` hook to detect and act upon changes that Angular doesn't catch on its own.
|
||||
|
||||
使用`DoCheck`钩子来检测那些Angular自身无法捕获的变更并采取行动。
|
||||
使用 `DoCheck` 钩子来检测那些 Angular 自身无法捕获的变更并采取行动。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
Use this method to detect a change that Angular overlooked.
|
||||
|
||||
用这个方法来检测那些被Angular忽略的更改。
|
||||
用这个方法来检测那些被 Angular 忽略的更改。
|
||||
|
||||
</div>
|
||||
|
||||
The *DoCheck* sample extends the *OnChanges* sample with the following `ngDoCheck()` hook:
|
||||
|
||||
*DoCheck*范例通过下面的`ngDoCheck()`实现扩展了*OnChanges*范例:
|
||||
*DoCheck*范例通过下面的 `ngDoCheck()` 实现扩展了*OnChanges*范例:
|
||||
|
||||
<code-example path="lifecycle-hooks/src/app/do-check.component.ts" region="ng-do-check" title="DoCheckComponent (ngDoCheck)" linenums="false"></code-example>
|
||||
|
||||
|
@ -825,7 +825,7 @@ so you can see how often `DoCheck` is called. The results are illuminating:
|
|||
|
||||
该代码检测一些**相关的值**,捕获当前值并与以前的值进行比较。
|
||||
当英雄或它的超能力发生了非实质性改变时,我们就往日志中写一条特殊的消息。
|
||||
这样你可以看到`DoCheck`被调用的频率。结果非常显眼:
|
||||
这样你可以看到 `DoCheck` 被调用的频率。结果非常显眼:
|
||||
|
||||
<figure>
|
||||
<img src='generated/images/guide/lifecycle-hooks/do-check-anim.gif' alt="DoCheck">
|
||||
|
@ -836,8 +836,8 @@ This hook is called with enormous frequency—after _every_
|
|||
change detection cycle no matter where the change occurred.
|
||||
It's called over twenty times in this example before the user can do anything.
|
||||
|
||||
虽然`ngDoCheck()`钩子可以可以监测到英雄的`name`什么时候发生了变化。但我们必须小心。
|
||||
这个`ngDoCheck`钩子被非常频繁的调用 —— 在_每次_变更检测周期之后,发生了变化的每个地方都会调它。
|
||||
虽然 `ngDoCheck()` 钩子可以可以监测到英雄的 `name` 什么时候发生了变化。但我们必须小心。
|
||||
这个 `ngDoCheck` 钩子被非常频繁的调用 —— 在_每次_变更检测周期之后,发生了变化的每个地方都会调它。
|
||||
在这个例子中,用户还没有做任何操作之前,它就被调用了超过二十次。
|
||||
|
||||
Most of these initial checks are triggered by Angular's first rendering of *unrelated data elsewhere on the page*.
|
||||
|
@ -845,8 +845,8 @@ Mere mousing into another `<input>` triggers a call.
|
|||
Relatively few calls reveal actual changes to pertinent data.
|
||||
Clearly our implementation must be very lightweight or the user experience suffers.
|
||||
|
||||
大部分检查的第一次调用都是在Angular首次渲染该页面中*其它不相关数据*时触发的。
|
||||
仅仅把鼠标移到其它`<input>`中就会触发一次调用。
|
||||
大部分检查的第一次调用都是在 Angular 首次渲染该页面中*其它不相关数据*时触发的。
|
||||
仅仅把鼠标移到其它 `<input>` 中就会触发一次调用。
|
||||
只有相对较少的调用才是由于对相关数据的修改而触发的。
|
||||
显然,我们的实现必须非常轻量级,否则将损害用户体验。
|
||||
|
||||
|
@ -859,17 +859,17 @@ Clearly our implementation must be very lightweight or the user experience suffe
|
|||
The *AfterView* sample explores the `AfterViewInit()` and `AfterViewChecked()` hooks that Angular calls
|
||||
*after* it creates a component's child views.
|
||||
|
||||
*AfterView*例子展示了`AfterViewInit()`和`AfterViewChecked()`钩子,Angular会在每次创建了组件的子视图后调用它们。
|
||||
*AfterView*例子展示了 `AfterViewInit()` 和 `AfterViewChecked()` 钩子,Angular 会在每次创建了组件的子视图后调用它们。
|
||||
|
||||
Here's a child view that displays a hero's name in an `<input>`:
|
||||
|
||||
下面是一个子视图,它用来把英雄的名字显示在一个`<input>`中:
|
||||
下面是一个子视图,它用来把英雄的名字显示在一个 `<input>` 中:
|
||||
|
||||
<code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="child-view" title="ChildComponent" linenums="false"></code-example>
|
||||
|
||||
The `AfterViewComponent` displays this child view *within its template*:
|
||||
|
||||
`AfterViewComponent`把这个子视图显示*在它的模板中*:
|
||||
`AfterViewComponent` 把这个子视图显示*在它的模板中*:
|
||||
|
||||
<code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="template" title="AfterViewComponent (template)" linenums="false"></code-example>
|
||||
|
||||
|
@ -889,26 +889,26 @@ which can only be reached by querying for the child view via the property decora
|
|||
|
||||
The `doSomething()` method updates the screen when the hero name exceeds 10 characters.
|
||||
|
||||
当英雄的名字超过10个字符时,`doSomething()`方法就会更新屏幕。
|
||||
当英雄的名字超过 10 个字符时,`doSomething()` 方法就会更新屏幕。
|
||||
|
||||
<code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="do-something" title="AfterViewComponent (doSomething)" linenums="false"></code-example>
|
||||
|
||||
Why does the `doSomething()` method wait a tick before updating `comment`?
|
||||
|
||||
为什么在更新`comment`属性之前,`doSomething()`方法要等上一拍(tick)?
|
||||
为什么在更新 `comment` 属性之前,`doSomething()` 方法要等上一拍(tick)?
|
||||
|
||||
Angular's unidirectional data flow rule forbids updates to the view *after* it has been composed.
|
||||
Both of these hooks fire _after_ the component's view has been composed.
|
||||
|
||||
Angular的“单向数据流”规则禁止在一个视图已经被组合好*之后*再更新视图。
|
||||
Angular 的“单向数据流”规则禁止在一个视图已经被组合好*之后*再更新视图。
|
||||
而这两个钩子都是在组件的视图已经被组合好之后触发的。
|
||||
|
||||
Angular throws an error if the hook updates the component's data-bound `comment` property immediately (try it!).
|
||||
The `LoggerService.tick_then()` postpones the log update
|
||||
for one turn of the browser's JavaScript cycle and that's just long enough.
|
||||
|
||||
如果我们立即更新组件中被绑定的`comment`属性,Angular就会抛出一个错误(试试!)。
|
||||
`LoggerService.tick_then()`方法延迟更新日志一个回合(浏览器JavaScript周期回合),这样就够了。
|
||||
如果我们立即更新组件中被绑定的 `comment` 属性,Angular 就会抛出一个错误(试试!)。
|
||||
`LoggerService.tick_then()` 方法延迟更新日志一个回合(浏览器 JavaScript 周期回合),这样就够了。
|
||||
|
||||
Here's *AfterView* in action:
|
||||
|
||||
|
@ -921,7 +921,7 @@ Here's *AfterView* in action:
|
|||
Notice that Angular frequently calls `AfterViewChecked()`, often when there are no changes of interest.
|
||||
Write lean hook methods to avoid performance problems.
|
||||
|
||||
注意,Angular会频繁的调用`AfterViewChecked()`,甚至在并没有需要关注的更改时也会触发。
|
||||
注意,Angular 会频繁的调用 `AfterViewChecked()`,甚至在并没有需要关注的更改时也会触发。
|
||||
所以务必把这个钩子方法写得尽可能精简,以免出现性能问题。
|
||||
|
||||
{@a aftercontent}
|
||||
|
@ -933,7 +933,7 @@ Write lean hook methods to avoid performance problems.
|
|||
The *AfterContent* sample explores the `AfterContentInit()` and `AfterContentChecked()` hooks that Angular calls
|
||||
*after* Angular projects external content into the component.
|
||||
|
||||
*AfterContent*例子展示了`AfterContentInit()`和`AfterContentChecked()`钩子,Angular会在外来内容被投影到组件中*之后*调用它们。
|
||||
*AfterContent*例子展示了 `AfterContentInit()` 和 `AfterContentChecked()` 钩子,Angular 会在外来内容被投影到组件中*之后*调用它们。
|
||||
|
||||
{@a content-projection}
|
||||
|
||||
|
@ -944,13 +944,13 @@ The *AfterContent* sample explores the `AfterContentInit()` and `AfterContentChe
|
|||
*Content projection* is a way to import HTML content from outside the component and insert that content
|
||||
into the component's template in a designated spot.
|
||||
|
||||
*内容投影*是从组件外部导入HTML内容,并把它插入在组件模板中指定位置上的一种途径。
|
||||
*内容投影*是从组件外部导入 HTML 内容,并把它插入在组件模板中指定位置上的一种途径。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
AngularJS developers know this technique as *transclusion*.
|
||||
|
||||
AngularJS的开发者大概知道一项叫做*transclusion*的技术,对,这就是它的马甲。
|
||||
AngularJS 的开发者大概知道一项叫做*transclusion*的技术,对,这就是它的马甲。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -959,7 +959,7 @@ This time, instead of including the child view within the template, it imports t
|
|||
the `AfterContentComponent`'s parent. Here's the parent's template:
|
||||
|
||||
对比[前一个](guide/lifecycle-hooks#afterview)例子考虑这个变化。
|
||||
这次,我们不再通过模板来把子视图包含进来,而是改从`AfterContentComponent`的父组件中导入它。下面是父组件的模板:
|
||||
这次,我们不再通过模板来把子视图包含进来,而是改从 `AfterContentComponent` 的父组件中导入它。下面是父组件的模板:
|
||||
|
||||
<code-example path="lifecycle-hooks/src/app/after-content.component.ts" region="parent-template" title="AfterContentParentComponent (template excerpt)" linenums="false"></code-example>
|
||||
|
||||
|
@ -967,12 +967,12 @@ Notice that the `<my-child>` tag is tucked between the `<after-content>` tags.
|
|||
Never put content between a component's element tags *unless you intend to project that content
|
||||
into the component*.
|
||||
|
||||
注意,`<my-child>`标签被包含在`<after-content>`标签中。
|
||||
注意,`<my-child>` 标签被包含在 `<after-content>` 标签中。
|
||||
永远不要在组件标签的内部放任何内容 —— *除非我们想把这些内容投影进这个组件中*。
|
||||
|
||||
Now look at the component's template:
|
||||
|
||||
现在来看下`<after-content>`组件的模板:
|
||||
现在来看下 `<after-content>` 组件的模板:
|
||||
|
||||
<code-example path="lifecycle-hooks/src/app/after-content.component.ts" region="template" title="AfterContentComponent (template)" linenums="false"></code-example>
|
||||
|
||||
|
@ -980,9 +980,9 @@ The `<ng-content>` tag is a *placeholder* for the external content.
|
|||
It tells Angular where to insert that content.
|
||||
In this case, the projected content is the `<my-child>` from the parent.
|
||||
|
||||
`<ng-content>`标签是外来内容的*占位符*。
|
||||
它告诉Angular在哪里插入这些外来内容。
|
||||
在这里,被投影进去的内容就是来自父组件的`<my-child>`标签。
|
||||
`<ng-content>` 标签是外来内容的*占位符*。
|
||||
它告诉 Angular 在哪里插入这些外来内容。
|
||||
在这里,被投影进去的内容就是来自父组件的 `<my-child>` 标签。
|
||||
|
||||
<figure>
|
||||
<img src='generated/images/guide/lifecycle-hooks/projected-child-view.png' alt="Projected Content">
|
||||
|
@ -996,11 +996,11 @@ In this case, the projected content is the `<my-child>` from the parent.
|
|||
|
||||
* HTML between component element tags.
|
||||
|
||||
在组件的元素标签中有HTML
|
||||
在组件的元素标签中有 HTML
|
||||
|
||||
* The presence of `<ng-content>` tags in the component's template.
|
||||
|
||||
组件的模板中出现了`<ng-content>`标签
|
||||
组件的模板中出现了 `<ng-content>` 标签
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -1008,7 +1008,7 @@ In this case, the projected content is the `<my-child>` from the parent.
|
|||
|
||||
### AfterContent hooks
|
||||
|
||||
### AfterContent钩子
|
||||
### AfterContent 钩子
|
||||
|
||||
*AfterContent* hooks are similar to the *AfterView* hooks.
|
||||
The key difference is in the child component.
|
||||
|
@ -1018,12 +1018,12 @@ The key difference is in the child component.
|
|||
* The *AfterView* hooks concern `ViewChildren`, the child components whose element tags
|
||||
appear *within* the component's template.
|
||||
|
||||
*AfterView*钩子所关心的是`ViewChildren`,这些子组件的元素标签会出现在该组件的模板*里面*。
|
||||
*AfterView*钩子所关心的是 `ViewChildren`,这些子组件的元素标签会出现在该组件的模板*里面*。
|
||||
|
||||
* The *AfterContent* hooks concern `ContentChildren`, the child components that Angular
|
||||
projected into the component.
|
||||
|
||||
*AfterContent*钩子所关心的是`ContentChildren`,这些子组件被Angular投影进该组件中。
|
||||
*AfterContent*钩子所关心的是 `ContentChildren`,这些子组件被 Angular 投影进该组件中。
|
||||
|
||||
The following *AfterContent* hooks take action based on changing values in a *content child*,
|
||||
which can only be reached by querying for them via the property decorated with
|
||||
|
@ -1042,7 +1042,7 @@ which can only be reached by querying for them via the property decorated with
|
|||
This component's `doSomething()` method update's the component's data-bound `comment` property immediately.
|
||||
There's no [need to wait](guide/lifecycle-hooks#wait-a-tick).
|
||||
|
||||
该组件的`doSomething()`方法立即更新了组件被绑定的`comment`属性。
|
||||
该组件的 `doSomething()` 方法立即更新了组件被绑定的 `comment` 属性。
|
||||
它[不用等](guide/lifecycle-hooks#wait-a-tick)下一回合。
|
||||
|
||||
Recall that Angular calls both *AfterContent* hooks before calling either of the *AfterView* hooks.
|
||||
|
@ -1050,6 +1050,6 @@ Angular completes composition of the projected content *before* finishing the co
|
|||
There is a small window between the `AfterContent...` and `AfterView...` hooks to modify the host view.
|
||||
|
||||
|
||||
回忆一下,Angular在每次调用*AfterView*钩子之前也会同时调用*AfterContent*。
|
||||
Angular在完成当前组件的视图合成之前,就已经完成了被投影内容的合成。
|
||||
回忆一下,Angular 在每次调用*AfterView*钩子之前也会同时调用*AfterContent*。
|
||||
Angular 在完成当前组件的视图合成之前,就已经完成了被投影内容的合成。
|
||||
所以我们仍然有机会去修改那个视图。
|
||||
|
|
|
@ -108,7 +108,7 @@ typical characteristics, in real world apps, you may see hybrids.
|
|||
|
||||
They might be imported by the root `AppModule` of a small application that lacks routing.
|
||||
|
||||
对于缺少路由的小型应用,它们可能只会被根模块`AppModule`导入一次。
|
||||
对于缺少路由的小型应用,它们可能只会被根模块 `AppModule` 导入一次。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -312,7 +312,7 @@ The following table summarizes the key characteristics of each feature module gr
|
|||
|
||||
Declarations
|
||||
|
||||
声明`declarations`
|
||||
声明 `declarations`
|
||||
|
||||
</th>
|
||||
|
||||
|
@ -320,7 +320,7 @@ The following table summarizes the key characteristics of each feature module gr
|
|||
|
||||
Providers
|
||||
|
||||
提供商`providers`
|
||||
提供商 `providers`
|
||||
|
||||
</th>
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ into three categories:
|
|||
|
||||
The following table summarizes the `@NgModule` metadata properties.
|
||||
|
||||
下面是`@NgModule`元数据中属性的汇总表:
|
||||
下面是 `@NgModule` 元数据中属性的汇总表:
|
||||
|
||||
<table>
|
||||
|
||||
|
@ -222,7 +222,7 @@ The following table summarizes the `@NgModule` metadata properties.
|
|||
A module can list another module among its `exports`, in which case
|
||||
all of that module's public components, directives, and pipes are exported.
|
||||
|
||||
一个模块可以把另一个模块加入自己的`exports`列表中,这时,另一个模块的所有公共组件、指令和管道都会被导出。
|
||||
一个模块可以把另一个模块加入自己的 `exports` 列表中,这时,另一个模块的所有公共组件、指令和管道都会被导出。
|
||||
|
||||
[Re-export](guide/ngmodule-faq#q-reexport) makes module transitivity explicit.
|
||||
If Module 'A' re-exports `CommonModule` and Module 'B' imports Module 'A',
|
||||
|
@ -251,7 +251,7 @@ The following table summarizes the `@NgModule` metadata properties.
|
|||
Angular can launch with multiple bootstrap components,
|
||||
each with its own location in the host web page.
|
||||
|
||||
Angular也可以引导多个引导组件,它们每一个都在宿主页面中有自己的位置。
|
||||
Angular 也可以引导多个引导组件,它们每一个都在宿主页面中有自己的位置。
|
||||
|
||||
A bootstrap component is automatically added to `entryComponents`.
|
||||
|
||||
|
|
|
@ -16,11 +16,11 @@ A basic understanding of the following concepts:
|
|||
|
||||
NgModules help organize an application into cohesive blocks of functionality.
|
||||
|
||||
NgModules可以帮我们把应用组织成一些紧密相关的代码块。
|
||||
NgModules 可以帮我们把应用组织成一些紧密相关的代码块。
|
||||
|
||||
This page answers the questions many developers ask about NgModule design and implementation.
|
||||
|
||||
这里回答的是开发者常问起的关于Angular模块的设计与实现问题。
|
||||
这里回答的是开发者常问起的关于 Angular 模块的设计与实现问题。
|
||||
|
||||
## What classes should I add to the `declarations` array?
|
||||
|
||||
|
@ -48,17 +48,17 @@ Declarables are the class types—components, directives, and pipes—th
|
|||
you can add to a module's `declarations` list.
|
||||
They're the only classes that you can add to `declarations`.
|
||||
|
||||
*可声明的*就是组件、指令和管道等可以被加到模块的`declarations`列表中的类。它们也是*所有*能被加到`declarations`中的类。
|
||||
*可声明的*就是组件、指令和管道等可以被加到模块的 `declarations` 列表中的类。它们也是*所有*能被加到 `declarations` 中的类。
|
||||
|
||||
<hr/>
|
||||
|
||||
## What classes should I _not_ add to `declarations`?
|
||||
|
||||
## 哪些类*不*应该加到`declarations`中?
|
||||
## 哪些类*不*应该加到 `declarations` 中?
|
||||
|
||||
Add only [declarable](guide/bootstrapping#the-declarations-array) classes to an NgModule's `declarations` list.
|
||||
|
||||
只有[可声明的](guide/ngmodule-faq#q-declarable)类才能加到模块的`declarations`列表中。
|
||||
只有[可声明的](guide/ngmodule-faq#q-declarable)类才能加到模块的 `declarations` 列表中。
|
||||
|
||||
Do *not* declare the following:
|
||||
|
||||
|
@ -71,7 +71,7 @@ Do *not* declare the following:
|
|||
* An array of directives imported from another module.
|
||||
For example, don't declare `FORMS_DIRECTIVES` from `@angular/forms` because the `FormsModule` already declares it.
|
||||
|
||||
从其它模块中导入的指令。例如,不要声明来自`@angular/forms`的FORMS_DIRECTIVES,因为 `FormsModule` 已经声明过它们了。
|
||||
从其它模块中导入的指令。例如,不要声明来自 `@angular/forms` 的 FORMS_DIRECTIVES,因为 `FormsModule` 已经声明过它们了。
|
||||
|
||||
* Module classes.
|
||||
|
||||
|
@ -84,7 +84,7 @@ For example, don't declare `FORMS_DIRECTIVES` from `@angular/forms` because the
|
|||
* Non-Angular classes and objects, such as
|
||||
strings, numbers, functions, entity models, configurations, business logic, and helper classes.
|
||||
|
||||
非Angular的类和对象,比如:字符串、数字、函数、实体模型、配置、业务逻辑和辅助类。
|
||||
非 Angular 的类和对象,比如:字符串、数字、函数、实体模型、配置、业务逻辑和辅助类。
|
||||
|
||||
<hr/>
|
||||
|
||||
|
@ -95,8 +95,8 @@ strings, numbers, functions, entity models, configurations, business logic, and
|
|||
`AppComponent` is often listed in both `declarations` and `bootstrap`.
|
||||
You might see the same component listed in `declarations`, `exports`, and `entryComponents`.
|
||||
|
||||
我们经常看到`AppComponent`被同时列在`declarations`和`bootstrap`中。
|
||||
我们还可能看到`HeroComponent`被同时列在`declarations`、`exports`和`entryComponent`中。
|
||||
我们经常看到 `AppComponent` 被同时列在 `declarations` 和 `bootstrap` 中。
|
||||
我们还可能看到 `HeroComponent` 被同时列在 `declarations`、`exports` 和 `entryComponent` 中。
|
||||
|
||||
While that seems redundant, these properties have different functions.
|
||||
Membership in one list doesn't imply membership in another list.
|
||||
|
@ -105,20 +105,20 @@ Membership in one list doesn't imply membership in another list.
|
|||
|
||||
* `AppComponent` could be declared in this module but not bootstrapped.
|
||||
|
||||
`AppComponent`可能被声明在此模块中,但可能不是引导组件。
|
||||
`AppComponent` 可能被声明在此模块中,但可能不是引导组件。
|
||||
|
||||
* `AppComponent` could be bootstrapped in this module but declared in a different feature module.
|
||||
|
||||
`AppComponent`可能在此模块中引导,但可能是由另一个特性模块声明的。
|
||||
`AppComponent` 可能在此模块中引导,但可能是由另一个特性模块声明的。
|
||||
|
||||
* A component could be imported from another app module (so you can't declare it) and re-exported by this module.
|
||||
|
||||
`HeroComponent`可能是从另一个应用模块中导入的(所以我们没法声明它)并且被当前模块重新导出。
|
||||
`HeroComponent` 可能是从另一个应用模块中导入的(所以我们没法声明它)并且被当前模块重新导出。
|
||||
|
||||
* A component could be exported for inclusion in an external component's template
|
||||
as well as dynamically loaded in a pop-up dialog.
|
||||
|
||||
`HeroComponent`可能被导入,以便用在外部组件的模板中,但也可能同时被一个弹出式对话框加载。
|
||||
`HeroComponent` 可能被导入,以便用在外部组件的模板中,但也可能同时被一个弹出式对话框加载。
|
||||
|
||||
<hr/>
|
||||
|
||||
|
@ -155,13 +155,13 @@ This always means importing `CommonModule` from `@angular/common` for access to
|
|||
the Angular directives such as `NgIf` and `NgFor`.
|
||||
You can import it directly or from another NgModule that [re-exports](guide/ngmodule-faq#q-reexport) it.
|
||||
|
||||
这意味着要从`@angular/common`中导入`CommonModule`才能访问Angular的内置指令,比如`NgIf`和`NgFor`。
|
||||
这意味着要从 `@angular/common` 中导入 `CommonModule` 才能访问 Angular 的内置指令,比如 `NgIf` 和 `NgFor`。
|
||||
你可以直接导入它或者从[重新导出](guide/ngmodule-faq#q-reexport)过该模块的其它模块中导入它。
|
||||
|
||||
Import `FormsModule` from `@angular/forms`
|
||||
if your components have `[(ngModel)]` two-way binding expressions.
|
||||
|
||||
如果你的组件有`[(ngModel)]`双向绑定表达式,就要从`@angular/forms`中导入`FormsModule`。
|
||||
如果你的组件有 `[(ngModel)]` 双向绑定表达式,就要从 `@angular/forms` 中导入 `FormsModule`。
|
||||
|
||||
Import _shared_ and _feature_ modules when this module's components incorporate their
|
||||
components, directives, and pipes.
|
||||
|
@ -170,7 +170,7 @@ components, directives, and pipes.
|
|||
|
||||
Import only [BrowserModule](guide/ngmodule-faq#q-browser-vs-common-module) in the root `AppModule`.
|
||||
|
||||
只能在根模块`AppModule`中[导入_BrowserModule_](guide/ngmodule-faq#q-browser-vs-common-module)。
|
||||
只能在根模块 `AppModule` 中[导入_BrowserModule_](guide/ngmodule-faq#q-browser-vs-common-module)。
|
||||
|
||||
<hr/>
|
||||
|
||||
|
@ -183,29 +183,29 @@ Import only [BrowserModule](guide/ngmodule-faq#q-browser-vs-common-module) in th
|
|||
The root application module, `AppModule`, of almost every browser application
|
||||
should import `BrowserModule` from `@angular/platform-browser`.
|
||||
|
||||
几乎所有要在浏览器中使用的应用的**根模块**(`AppModule`)都应该从`@angular/platform-browser`中导入`BrowserModule`。
|
||||
几乎所有要在浏览器中使用的应用的**根模块**(`AppModule`)都应该从 `@angular/platform-browser` 中导入 `BrowserModule`。
|
||||
|
||||
`BrowserModule` provides services that are essential to launch and run a browser app.
|
||||
|
||||
`BrowserModule`提供了启动和运行浏览器应用的那些基本的服务提供商。
|
||||
`BrowserModule` 提供了启动和运行浏览器应用的那些基本的服务提供商。
|
||||
|
||||
`BrowserModule` also re-exports `CommonModule` from `@angular/common`,
|
||||
which means that components in the `AppModule` module also have access to
|
||||
the Angular directives every app needs, such as `NgIf` and `NgFor`.
|
||||
|
||||
`BrowserModule`还从`@angular/common`中重新导出了`CommonModule`,这意味着`AppModule`中的组件也同样可以访问那些每个应用都需要的Angular指令,如`NgIf`和`NgFor`。
|
||||
`BrowserModule` 还从 `@angular/common` 中重新导出了 `CommonModule`,这意味着 `AppModule` 中的组件也同样可以访问那些每个应用都需要的 Angular 指令,如 `NgIf` 和 `NgFor`。
|
||||
|
||||
Do not import `BrowserModule` in any other module.
|
||||
*Feature modules* and *lazy-loaded modules* should import `CommonModule` instead.
|
||||
They need the common directives. They don't need to re-install the app-wide providers.
|
||||
|
||||
在其它任何模块中都*不要导入*`BrowserModule`。
|
||||
*特性模块*和*惰性加载模块*应该改成导入`CommonModule`。
|
||||
*特性模块*和*惰性加载模块*应该改成导入 `CommonModule`。
|
||||
它们需要通用的指令。它们不需要重新初始化全应用级的提供商。
|
||||
|
||||
Importing `CommonModule` also frees feature modules for use on _any_ target platform, not just browsers.
|
||||
|
||||
特性模块中导入`CommonModule`可以让它能用在任何目标平台上,不仅是浏览器。那些跨平台库的作者应该喜欢这种方式的。
|
||||
特性模块中导入 `CommonModule` 可以让它能用在任何目标平台上,不仅是浏览器。那些跨平台库的作者应该喜欢这种方式的。
|
||||
|
||||
<hr/>
|
||||
|
||||
|
@ -218,20 +218,20 @@ Importing `CommonModule` also frees feature modules for use on _any_ target plat
|
|||
That's not a problem. When three modules all import Module 'A',
|
||||
Angular evaluates Module 'A' once, the first time it encounters it, and doesn't do so again.
|
||||
|
||||
没有任何问题。当三个模块全都导入模块'A'时,Angular只会首次遇到时加载一次模块'A',之后就不会这么做了。
|
||||
没有任何问题。当三个模块全都导入模块'A'时,Angular 只会首次遇到时加载一次模块'A',之后就不会这么做了。
|
||||
|
||||
That's true at whatever level `A` appears in a hierarchy of imported NgModules.
|
||||
When Module 'B' imports Module 'A', Module 'C' imports 'B', and Module 'D' imports `[C, B, A]`,
|
||||
then 'D' triggers the evaluation of 'C', which triggers the evaluation of 'B', which evaluates 'A'.
|
||||
When Angular gets to the 'B' and 'A' in 'D', they're already cached and ready to go.
|
||||
|
||||
无论`A`出现在所导入模块的哪个层级,都会如此。
|
||||
如果模块'B'导入模块'A'、模块'C'导入模块'B',模块'D'导入`[C, B, A]`,那么'D'会触发模块'C'的加载,'C'会触发'B'的加载,而'B'会加载'A'。
|
||||
当Angular在'D'中想要获取'B'和'A'时,这两个模块已经被缓存过了,可以立即使用。
|
||||
无论 `A` 出现在所导入模块的哪个层级,都会如此。
|
||||
如果模块'B'导入模块'A'、模块'C'导入模块'B',模块'D'导入 `[C, B, A]`,那么'D'会触发模块'C'的加载,'C'会触发'B'的加载,而'B'会加载'A'。
|
||||
当 Angular 在'D'中想要获取'B'和'A'时,这两个模块已经被缓存过了,可以立即使用。
|
||||
|
||||
Angular doesn't like NgModules with circular references, so don't let Module 'A' import Module 'B', which imports Module 'A'.
|
||||
|
||||
Angular不允许模块之间出现循环依赖,所以不要让模块'A'导入模块'B',而模块'B'又导入模块'A'。
|
||||
Angular 不允许模块之间出现循环依赖,所以不要让模块'A'导入模块'B',而模块'B'又导入模块'A'。
|
||||
|
||||
<hr/>
|
||||
|
||||
|
@ -291,8 +291,8 @@ For example, there's no point in re-exporting `HttpClientModule` because it does
|
|||
Its only purpose is to add http service providers to the application as a whole.
|
||||
|
||||
纯服务模块没有公开(导出)的声明。
|
||||
例如,没必要重新导出`HttpClientModule`,因为它不导出任何东西。
|
||||
它唯一的用途是一起把http的那些服务提供商添加到应用中。
|
||||
例如,没必要重新导出 `HttpClientModule`,因为它不导出任何东西。
|
||||
它唯一的用途是一起把 http 的那些服务提供商添加到应用中。
|
||||
|
||||
<hr/>
|
||||
|
||||
|
@ -313,7 +313,7 @@ An NgModule can re-export entire NgModules, which effectively re-exports all of
|
|||
Angular's own `BrowserModule` exports a couple of NgModules like this:
|
||||
|
||||
模块可以重新导出其它模块,这会导致重新导出它们导出的所有类。
|
||||
Angular自己的`BrowserModule`就重新导出了一组模块,例如:
|
||||
Angular 自己的 `BrowserModule` 就重新导出了一组模块,例如:
|
||||
|
||||
```typescript
|
||||
|
||||
|
@ -332,8 +332,8 @@ Its only purpose is to add http service providers to the application as a whole.
|
|||
|
||||
不要费心去导出纯服务类。
|
||||
纯服务类的模块不会导出任何可供其它模块使用的[可声明类](guide/ngmodule-faq#q-declarable)。
|
||||
例如,不用重新导出`HttpClientModule`,因为它没有导出任何东西。
|
||||
它唯一的用途是把那些http服务提供商一起添加到应用中。
|
||||
例如,不用重新导出 `HttpClientModule`,因为它没有导出任何东西。
|
||||
它唯一的用途是把那些 http 服务提供商一起添加到应用中。
|
||||
|
||||
<hr/>
|
||||
|
||||
|
@ -343,30 +343,30 @@ Its only purpose is to add http service providers to the application as a whole.
|
|||
|
||||
The `forRoot()` static method is a convention that makes it easy for developers to configure the module's providers.
|
||||
|
||||
静态方法`forRoot()`是一个约定,它可以让开发人员更轻松的配置模块的提供商。
|
||||
静态方法 `forRoot()` 是一个约定,它可以让开发人员更轻松的配置模块的提供商。
|
||||
|
||||
The `RouterModule.forRoot()` method is a good example.
|
||||
Apps pass a `Routes` object to `RouterModule.forRoot()` in order to configure the app-wide `Router` service with routes.
|
||||
`RouterModule.forRoot()` returns a [ModuleWithProviders](api/core/ModuleWithProviders).
|
||||
You add that result to the `imports` list of the root `AppModule`.
|
||||
|
||||
`RouterModule.forRoot()`就是一个很好的例子。
|
||||
应用把一个`Routes`对象传给`RouterModule.forRoot()`,为的就是使用路由配置全应用级的`Router`服务。
|
||||
`RouterModule.forRoot()`返回一个[ModuleWithProviders](api/core/ModuleWithProviders)对象。
|
||||
我们把这个结果添加到根模块`AppModule`的`imports`列表中。
|
||||
`RouterModule.forRoot()` 就是一个很好的例子。
|
||||
应用把一个 `Routes` 对象传给 `RouterModule.forRoot()`,为的就是使用路由配置全应用级的 `Router` 服务。
|
||||
`RouterModule.forRoot()` 返回一个[ModuleWithProviders](api/core/ModuleWithProviders)对象。
|
||||
我们把这个结果添加到根模块 `AppModule` 的 `imports` 列表中。
|
||||
|
||||
Only call and import a `.forRoot()` result in the root application module, `AppModule`.
|
||||
Importing it in any other module, particularly in a lazy-loaded module,
|
||||
is contrary to the intent and will likely produce a runtime error.
|
||||
For more information, see [Singleton Services](guide/singleton-services).
|
||||
|
||||
只能在应用的根模块`AppModule`中调用并导入`.forRoot()`的结果。
|
||||
只能在应用的根模块 `AppModule` 中调用并导入 `.forRoot()` 的结果。
|
||||
在其它模块中导入它,特别是惰性加载模块中,是违反设计目标的并会导致一个运行时错误。
|
||||
要了解更多,参见[单例服务](guide/singleton-services)。
|
||||
|
||||
`RouterModule` also offers a `forChild` static method for configuring the routes of lazy-loaded modules.
|
||||
|
||||
`RouterModule`也提供了静态方法`forChild`,用于配置惰性加载模块的路由。
|
||||
`RouterModule` 也提供了静态方法 `forChild`,用于配置惰性加载模块的路由。
|
||||
|
||||
`forRoot()` and `forChild()` are conventional names for methods that
|
||||
configure services in root and feature modules respectively.
|
||||
|
@ -376,7 +376,7 @@ configure services in root and feature modules respectively.
|
|||
Angular doesn't recognize these names but Angular developers do.
|
||||
Follow this convention when you write similar modules with configurable service providers.
|
||||
|
||||
Angular并不识别这些名字,但是Angular的开发人员可以。
|
||||
Angular 并不识别这些名字,但是 Angular 的开发人员可以。
|
||||
当你写类似的需要可配置的服务提供商时,请遵循这个约定。
|
||||
|
||||
<!--KW--I don't understand how Angular doesn't understand these methods...-->
|
||||
|
@ -390,14 +390,14 @@ Angular并不识别这些名字,但是Angular的开发人员可以。
|
|||
Providers listed in the `@NgModule.providers` of a bootstrapped module have application scope.
|
||||
Adding a service provider to `@NgModule.providers` effectively publishes the service to the entire application.
|
||||
|
||||
列在引导模块的`@NgModule.providers`中的服务提供商具有**全应用级作用域**。
|
||||
往`NgModule.providers`中添加服务提供商将导致该服务被发布到整个应用中。
|
||||
列在引导模块的 `@NgModule.providers` 中的服务提供商具有**全应用级作用域**。
|
||||
往 `NgModule.providers` 中添加服务提供商将导致该服务被发布到整个应用中。
|
||||
|
||||
When you import an NgModule,
|
||||
Angular adds the module's service providers (the contents of its `providers` list)
|
||||
to the application root injector.
|
||||
|
||||
当我们导入一个模块时,Angular就会把该模块的服务提供商(也就是它的`providers`列表中的内容)加入该应用的*根注入器*中。
|
||||
当我们导入一个模块时,Angular 就会把该模块的服务提供商(也就是它的 `providers` 列表中的内容)加入该应用的*根注入器*中。
|
||||
|
||||
This makes the provider visible to every class in the application that knows the provider's lookup token, or knows its name.
|
||||
|
||||
|
@ -409,10 +409,10 @@ Merging NgModule providers into the application injector
|
|||
makes it easy for a module library to enrich the entire application with new services.
|
||||
By adding the `HttpClientModule` once, every application component can make HTTP requests.
|
||||
|
||||
Angular就是如此设计的。
|
||||
通过模块导入来实现可扩展性是Angular模块系统的主要设计目标。
|
||||
Angular 就是如此设计的。
|
||||
通过模块导入来实现可扩展性是 Angular 模块系统的主要设计目标。
|
||||
把模块的提供商并入应用程序的注入器可以让库模块使用新的服务来强化应用程序变得更容易。
|
||||
只要添加一次`HttpClientModule`,那么应用中的每个组件就都可以发起Http请求了。
|
||||
只要添加一次 `HttpClientModule`,那么应用中的每个组件就都可以发起 Http 请求了。
|
||||
|
||||
However, this might feel like an unwelcome surprise if you expect the module's services
|
||||
to be visible only to the components declared by that feature module.
|
||||
|
@ -421,7 +421,7 @@ any class that knows the `HeroService` _type_ can inject that service,
|
|||
not just the classes declared in the `HeroModule`.
|
||||
|
||||
不过,如果你期望模块的服务只对那个特性模块内部声明的组件可见,那么这可能会带来一些不受欢迎的意外。
|
||||
如果`HeroModule`提供了一个`HeroService`,并且根模块`AppModule`导入了`HeroModule`,那么任何知道`HeroService`*类型*的类都可能注入该服务,而不仅是在`HeroModule`中声明的那些类。
|
||||
如果 `HeroModule` 提供了一个 `HeroService`,并且根模块 `AppModule` 导入了 `HeroModule`,那么任何知道 `HeroService`*类型*的类都可能注入该服务,而不仅是在 `HeroModule` 中声明的那些类。
|
||||
|
||||
<hr/>
|
||||
|
||||
|
@ -440,8 +440,8 @@ When the Angular router lazy-loads a module, it creates a new execution context.
|
|||
That [context has its own injector](guide/ngmodule-faq#q-why-child-injector "Why Angular creates a child injector"),
|
||||
which is a direct child of the application injector.
|
||||
|
||||
当Angular路由器惰性加载一个模块时,它创建了一个新的运行环境。
|
||||
那个环境[拥有自己的注入器](guide/ngmodule-faq#q-why-child-injector "为什么Angular会创建子注入器"),它是应用注入器的直属子级。
|
||||
当 Angular 路由器惰性加载一个模块时,它创建了一个新的运行环境。
|
||||
那个环境[拥有自己的注入器](guide/ngmodule-faq#q-why-child-injector "为什么 Angular 会创建子注入器"),它是应用注入器的直属子级。
|
||||
|
||||
The router adds the lazy module's providers and the providers of its imported NgModules to this child injector.
|
||||
|
||||
|
@ -452,7 +452,7 @@ When the router creates a component within the lazy-loaded context,
|
|||
Angular prefers service instances created from these providers to the service instances of the application root injector.
|
||||
|
||||
这些提供商不会被拥有相同令牌的应用级别提供商的变化所影响。
|
||||
当路由器在惰性加载环境中创建组件时,Angular优先使用惰性加载模块中的服务实例,而不是来自应用的根注入器的。
|
||||
当路由器在惰性加载环境中创建组件时,Angular 优先使用惰性加载模块中的服务实例,而不是来自应用的根注入器的。
|
||||
|
||||
<hr/>
|
||||
|
||||
|
@ -468,7 +468,7 @@ the second module's provider "wins". That's because both providers are added to
|
|||
When Angular looks to inject a service for that token,
|
||||
it creates and delivers the instance created by the second provider.
|
||||
|
||||
当Angular尝试根据令牌注入服务时,它使用第二个提供商来创建并交付服务实例。
|
||||
当 Angular 尝试根据令牌注入服务时,它使用第二个提供商来创建并交付服务实例。
|
||||
|
||||
_Every_ class that injects this service gets the instance created by the second provider.
|
||||
Even classes declared within the first module get the instance created by the second provider.
|
||||
|
@ -479,12 +479,12 @@ Even classes declared within the first module get the instance created by the se
|
|||
If NgModule A provides a service for token 'X' and imports an NgModule B
|
||||
that also provides a service for token 'X', then NgModule A's service definition "wins".
|
||||
|
||||
如果模块A提供了一个使用令牌'X'的服务,并且导入的模块B也用令牌'X'提供了一个服务,那么模块A中定义的服务“获胜”了。
|
||||
如果模块 A 提供了一个使用令牌'X'的服务,并且导入的模块 B 也用令牌'X'提供了一个服务,那么模块 A 中定义的服务“获胜”了。
|
||||
|
||||
The service provided by the root `AppModule` takes precedence over services provided by imported NgModules.
|
||||
The `AppModule` always wins.
|
||||
|
||||
由根`AppModule`提供的服务相对于所导入模块中提供的服务有优先权。换句话说:`AppModule`总会获胜。
|
||||
由根 `AppModule` 提供的服务相对于所导入模块中提供的服务有优先权。换句话说:`AppModule` 总会获胜。
|
||||
|
||||
<hr/>
|
||||
|
||||
|
@ -496,7 +496,7 @@ When a module is loaded at application launch,
|
|||
its `@NgModule.providers` have *application-wide scope*;
|
||||
that is, they are available for injection throughout the application.
|
||||
|
||||
如果一个模块在应用程序启动时就加载,它的`@NgModule.providers`具有***全应用级作用域***。
|
||||
如果一个模块在应用程序启动时就加载,它的 `@NgModule.providers` 具有***全应用级作用域***。
|
||||
它们也可用于整个应用的注入中。
|
||||
|
||||
Imported providers are easily replaced by providers from another imported NgModule.
|
||||
|
@ -516,24 +516,24 @@ If another module elsewhere in the application also customizes `HttpBackend`
|
|||
or merely imports the `HttpClientModule`, it could override this module's `HttpBackend` provider,
|
||||
losing the special header. The server will reject http requests from this module.
|
||||
|
||||
假设模块需要一个定制过的`HttpBackend`,它为所有的Http请求添加一个特别的请求头。
|
||||
如果应用中其它地方的另一个模块也定制了`HttpBackend`或仅仅导入了`HttpClientModule`,它就会改写当前模块的`HttpBackend`提供商,丢掉了这个特别的请求头。
|
||||
假设模块需要一个定制过的 `HttpBackend`,它为所有的 Http 请求添加一个特别的请求头。
|
||||
如果应用中其它地方的另一个模块也定制了 `HttpBackend` 或仅仅导入了 `HttpClientModule`,它就会改写当前模块的 `HttpBackend` 提供商,丢掉了这个特别的请求头。
|
||||
这样服务器就会拒绝来自该模块的请求。
|
||||
|
||||
To avoid this problem, import the `HttpClientModule` only in the `AppModule`, the application _root module_.
|
||||
|
||||
要消除这个问题,就只能在应用的根模块`AppModule`中导入`HttpClientModule`。
|
||||
要消除这个问题,就只能在应用的根模块 `AppModule` 中导入 `HttpClientModule`。
|
||||
|
||||
If you must guard against this kind of "provider corruption", *don't rely on a launch-time module's `providers`.*
|
||||
|
||||
如果你必须防范这种“提供商腐化”现象,那就*不要依赖于“启动时加载”模块的`providers`*。
|
||||
如果你必须防范这种“提供商腐化”现象,那就*不要依赖于“启动时加载”模块的 `providers`*。
|
||||
|
||||
Load the module lazily if you can.
|
||||
Angular gives a [lazy-loaded module](guide/ngmodule-faq#q-lazy-loaded-module-provider-visibility) its own child injector.
|
||||
The module's providers are visible only within the component tree created with this injector.
|
||||
|
||||
只要可能,就让模块惰性加载。
|
||||
Angular给了[惰性加载模块](guide/ngmodule-faq#q-lazy-loaded-module-provider-visibility)自己的子注入器。
|
||||
Angular 给了[惰性加载模块](guide/ngmodule-faq#q-lazy-loaded-module-provider-visibility)自己的子注入器。
|
||||
该模块中的提供商只对由该注入器创建的组件树可见。
|
||||
|
||||
If you must load the module eagerly, when the application starts,
|
||||
|
@ -543,7 +543,7 @@ If you must load the module eagerly, when the application starts,
|
|||
|
||||
Continuing with the same example, suppose the components of a module truly require a private, custom `HttpBackend`.
|
||||
|
||||
继续看这个例子,假设某个模块的组件真的需要一个私有的、自定义的`HttpBackend`。
|
||||
继续看这个例子,假设某个模块的组件真的需要一个私有的、自定义的 `HttpBackend`。
|
||||
|
||||
Create a "top component" that acts as the root for all of the module's components.
|
||||
Add the custom `HttpBackend` provider to the top component's `providers` list rather than the module's `providers`.
|
||||
|
@ -551,16 +551,16 @@ Recall that Angular creates a child injector for each component instance and pop
|
|||
with the component's own providers.
|
||||
|
||||
那就创建一个“顶级组件”来扮演该模块中所有组件的根。
|
||||
把这个自定义的`HttpBackend`提供商添加到这个顶级组件的`providers`列表中,而不是该模块的`providers`中。
|
||||
回忆一下,Angular会为每个组件实例创建一个子注入器,并使用组件自己的`providers`来配置这个注入器。
|
||||
把这个自定义的 `HttpBackend` 提供商添加到这个顶级组件的 `providers` 列表中,而不是该模块的 `providers` 中。
|
||||
回忆一下,Angular 会为每个组件实例创建一个子注入器,并使用组件自己的 `providers` 来配置这个注入器。
|
||||
|
||||
When a child of this component asks for the `HttpBackend` service,
|
||||
Angular provides the local `HttpBackend` service,
|
||||
not the version provided in the application root injector.
|
||||
Child components make proper HTTP requests no matter what other modules do to `HttpBackend`.
|
||||
|
||||
当该组件的子组件*想要*一个`HttpBackend`服务时,Angular会提供一个局部的`HttpBackend`服务,而不是应用的根注入器创建的那个。
|
||||
子组件将正确发起http请求,而不管其它模块对`HttpBackend`做了什么。
|
||||
当该组件的子组件*想要*一个 `HttpBackend` 服务时,Angular 会提供一个局部的 `HttpBackend` 服务,而不是应用的根注入器创建的那个。
|
||||
子组件将正确发起 http 请求,而不管其它模块对 `HttpBackend` 做了什么。
|
||||
|
||||
Be sure to create module components as children of this module's top component.
|
||||
|
||||
|
@ -570,7 +570,7 @@ You can embed the child components in the top component's template.
|
|||
Alternatively, make the top component a routing host by giving it a `<router-outlet>`.
|
||||
Define child routes and let the router load module components into that outlet.
|
||||
|
||||
你可以把这些子组件都嵌在顶级组件的模板中。或者,给顶级组件一个`<router-outlet>`,让它作为路由的宿主。
|
||||
你可以把这些子组件都嵌在顶级组件的模板中。或者,给顶级组件一个 `<router-outlet>`,让它作为路由的宿主。
|
||||
定义子路由,并让路由器把模块中的组件加载进该路由出口(outlet)中。
|
||||
|
||||
<hr/>
|
||||
|
@ -579,21 +579,21 @@ Define child routes and let the router load module components into that outlet.
|
|||
|
||||
## Should I add application-wide providers to the root `AppModule` or the root `AppComponent`?
|
||||
|
||||
## 我应该把全应用级提供商添加到根模块`AppModule`中还是根组件`AppComponent`中?
|
||||
## 我应该把全应用级提供商添加到根模块 `AppModule` 中还是根组件 `AppComponent` 中?
|
||||
|
||||
Register application-wide providers in the root `AppModule`, not in the `AppComponent`.
|
||||
|
||||
在根模块`AppModule`中注册全应用级提供商,而不是`AppComponent`中。
|
||||
在根模块 `AppModule` 中注册全应用级提供商,而不是 `AppComponent` 中。
|
||||
|
||||
Lazy-loaded modules and their components can inject `AppModule` services;
|
||||
they can't inject `AppComponent` services.
|
||||
|
||||
惰性加载模块及其组件可以注入`AppModule`中的服务,却不能注入`AppComponent`中的。
|
||||
惰性加载模块及其组件可以注入 `AppModule` 中的服务,却不能注入 `AppComponent` 中的。
|
||||
|
||||
Register a service in `AppComponent` providers _only_ if the service must be hidden
|
||||
from components outside the `AppComponent` tree. This is a rare use case.
|
||||
|
||||
*只有*当该服务必须对`AppComponent`组件树之外的组件不可见时,才应该把服务注册进`AppComponent`的`providers`中。
|
||||
*只有*当该服务必须对 `AppComponent` 组件树之外的组件不可见时,才应该把服务注册进 `AppComponent` 的 `providers` 中。
|
||||
这是一个非常罕见的异常用法。
|
||||
|
||||
More generally, [prefer registering providers in NgModules](guide/ngmodule-faq#q-component-or-module) to registering in components.
|
||||
|
@ -608,20 +608,20 @@ Angular registers all startup module providers with the application root injecto
|
|||
The services that root injector providers create have application scope, which
|
||||
means they are available to the entire application.
|
||||
|
||||
Angular把所有启动期模块的提供商都注册进了应用的根注入器中。
|
||||
Angular 把所有启动期模块的提供商都注册进了应用的根注入器中。
|
||||
这些服务是由根注入器中的提供商创建的,并且在整个应用中都可用。
|
||||
它们具有*应用级作用域*。
|
||||
|
||||
Certain services, such as the `Router`, only work when you register them in the application root injector.
|
||||
|
||||
某些服务(比如`Router`)只有当注册进应用的根注入器时才能正常工作。
|
||||
某些服务(比如 `Router`)只有当注册进应用的根注入器时才能正常工作。
|
||||
|
||||
By contrast, Angular registers `AppComponent` providers with the `AppComponent`'s own injector.
|
||||
`AppComponent` services are available only to that component and its component tree.
|
||||
They have component scope.
|
||||
|
||||
相反,Angular使用`AppComponent`自己的注入器注册了`AppComponent`的提供商。
|
||||
`AppComponent`服务只在该组件及其子组件树中才能使用。
|
||||
相反,Angular 使用 `AppComponent` 自己的注入器注册了 `AppComponent` 的提供商。
|
||||
`AppComponent` 服务只在该组件及其子组件树中才能使用。
|
||||
它们具有*组件级作用域*。
|
||||
|
||||
The `AppComponent`'s injector is a child of the root injector, one down in the injector hierarchy.
|
||||
|
@ -630,7 +630,7 @@ But in routed applications, routing operates at the root level
|
|||
where `AppComponent` services don't exist.
|
||||
This means that lazy-loaded modules can't reach them.
|
||||
|
||||
`AppComponent`的注入器是根注入器的*子级*,注入器层次中的下一级。
|
||||
`AppComponent` 的注入器是根注入器的*子级*,注入器层次中的下一级。
|
||||
这对于没有路由器的应用来说*几乎是*整个应用了。
|
||||
但对那些带路由的应用,路由操作位于顶层,那里不存在 `AppComponent` 服务。这意味着惰性加载模块不能使用它们。
|
||||
|
||||
|
@ -659,14 +659,14 @@ the service with the component.
|
|||
Then each new instance of the component gets its own cached service instance.
|
||||
The changes that editor makes in its service don't touch the instances elsewhere in the application.
|
||||
|
||||
例如,如果英雄编辑组件需要自己私有的缓存英雄服务实例,那么我们应该把`HeroService`注册进`HeroEditorComponent`中。
|
||||
这样,每个新的`HeroEditorComponent`的实例都会得到一份自己的缓存服务实例。
|
||||
例如,如果英雄编辑组件需要自己私有的缓存英雄服务实例,那么我们应该把 `HeroService` 注册进 `HeroEditorComponent` 中。
|
||||
这样,每个新的 `HeroEditorComponent` 的实例都会得到一份自己的缓存服务实例。
|
||||
编辑器的改动只会作用于它自己的服务,而不会影响到应用中其它地方的英雄实例。
|
||||
|
||||
[Always register _application-wide_ services with the root `AppModule`](guide/ngmodule-faq#q-root-component-or-module),
|
||||
not the root `AppComponent`.
|
||||
|
||||
[总是在根模块`AppModule`中注册*全应用级*服务](guide/ngmodule-faq#q-root-component-or-module),而不要在根组件`AppComponent`中。
|
||||
[总是在根模块 `AppModule` 中注册*全应用级*服务](guide/ngmodule-faq#q-root-component-or-module),而不要在根组件 `AppComponent` 中。
|
||||
|
||||
<hr/>
|
||||
|
||||
|
@ -693,12 +693,12 @@ and delivers the app-wide singleton service. No problem.
|
|||
|
||||
Now consider a lazy loaded module that also provides a service called `UserService`.
|
||||
|
||||
现在,该考虑`HeroModule`了,*它是惰性加载的!*。
|
||||
现在,该考虑 `HeroModule` 了,*它是惰性加载的!*。
|
||||
|
||||
When the router lazy loads a module, it creates a child injector and registers the `UserService`
|
||||
provider with that child injector. The child injector is _not_ the root injector.
|
||||
|
||||
当路由器准备惰性加载`HeroModule`的时候,它会创建一个子注入器,并且把`UserService`的提供商注册到那个子注入器中。子注入器和根注入器是*不同*的。
|
||||
当路由器准备惰性加载 `HeroModule` 的时候,它会创建一个子注入器,并且把 `UserService` 的提供商注册到那个子注入器中。子注入器和根注入器是*不同*的。
|
||||
|
||||
When Angular creates a lazy component for that module and injects `UserService`,
|
||||
it finds a `UserService` provider in the lazy module's _child injector_
|
||||
|
@ -706,9 +706,9 @@ and creates a _new_ instance of the `UserService`.
|
|||
This is an entirely different `UserService` instance
|
||||
than the app-wide singleton version that Angular injected in one of the eagerly loaded components.
|
||||
|
||||
当Angular创建一个惰性加载的`HeroComponent`时,它必须注入一个`UserService`。
|
||||
这次,它会从惰性加载模块的*子注入器*中查找`UserService`的提供商,并用它创建一个`UserService`的新实例。
|
||||
这个`UserService`实例与Angular在主动加载的组件中注入的那个全应用级单例对象截然不同。
|
||||
当 Angular 创建一个惰性加载的 `HeroComponent` 时,它必须注入一个 `UserService`。
|
||||
这次,它会从惰性加载模块的*子注入器*中查找 `UserService` 的提供商,并用它创建一个 `UserService` 的新实例。
|
||||
这个 `UserService` 实例与 Angular 在主动加载的组件中注入的那个全应用级单例对象截然不同。
|
||||
|
||||
This scenario causes your app to create a new instance every time, instead of using the singleton.
|
||||
|
||||
|
@ -733,7 +733,7 @@ I'd like to see the error so I can include it.-->
|
|||
Angular adds `@NgModule.providers` to the application root injector, unless the NgModule is lazy-loaded.
|
||||
For a lazy-loaded NgModule, Angular creates a _child injector_ and adds the module's providers to the child injector.
|
||||
|
||||
Angular会把`@NgModule.providers`中的提供商添加到应用的根注入器中……
|
||||
Angular 会把 `@NgModule.providers` 中的提供商添加到应用的根注入器中……
|
||||
除非该模块是惰性加载的,这种情况下,它会创建一*子注入器*,并且把该模块的提供商添加到这个子注入器中。
|
||||
|
||||
This means that an NgModule behaves differently depending on whether it's loaded during application start
|
||||
|
@ -743,13 +743,13 @@ or lazy-loaded later. Neglecting that difference can lead to [adverse consequenc
|
|||
|
||||
Why doesn't Angular add lazy-loaded providers to the app root injector as it does for eagerly loaded NgModules?
|
||||
|
||||
为什么Angular不能像主动加载模块那样把惰性加载模块的提供商也添加到应用程序的根注入器中呢?为什么会出现这种不一致?
|
||||
为什么 Angular 不能像主动加载模块那样把惰性加载模块的提供商也添加到应用程序的根注入器中呢?为什么会出现这种不一致?
|
||||
|
||||
The answer is grounded in a fundamental characteristic of the Angular dependency-injection system.
|
||||
An injector can add providers _until it's first used_.
|
||||
Once an injector starts creating and delivering services, its provider list is frozen; no new providers are allowed.
|
||||
|
||||
归根结底,这来自于Angular依赖注入系统的一个基本特征:
|
||||
归根结底,这来自于 Angular 依赖注入系统的一个基本特征:
|
||||
在注入器还没有被第一次使用之前,可以不断为其添加提供商。
|
||||
一旦注入器已经创建和开始交付服务,它的提供商列表就被冻结了,不再接受新的提供商。
|
||||
|
||||
|
@ -757,7 +757,7 @@ When an applications starts, Angular first configures the root injector with the
|
|||
_before_ creating its first component and injecting any of the provided services.
|
||||
Once the application begins, the app root injector is closed to new providers.
|
||||
|
||||
当应用启动时,Angular会首先使用所有主动加载模块中的提供商来配置根注入器,这发生在它创建第一个组件以及注入任何服务之前。
|
||||
当应用启动时,Angular 会首先使用所有主动加载模块中的提供商来配置根注入器,这发生在它创建第一个组件以及注入任何服务之前。
|
||||
一旦应用开始工作,应用的根注入器就不再接受新的提供商了。
|
||||
|
||||
Time passes and application logic triggers lazy loading of an NgModule.
|
||||
|
@ -766,9 +766,9 @@ It can't add them to the app root injector because that injector is closed to ne
|
|||
So Angular creates a new child injector for the lazy-loaded module context.
|
||||
|
||||
之后,应用逻辑开始惰性加载某个模块。
|
||||
Angular必须把这个惰性加载模块中的提供商添加到*某个*注入器中。
|
||||
Angular 必须把这个惰性加载模块中的提供商添加到*某个*注入器中。
|
||||
但是它无法将它们添加到应用的根注入器中,因为根注入器已经不再接受新的提供商了。
|
||||
于是,Angular在惰性加载模块的上下文中创建了一个新的子注入器。
|
||||
于是,Angular 在惰性加载模块的上下文中创建了一个新的子注入器。
|
||||
|
||||
<hr/>
|
||||
|
||||
|
@ -782,7 +782,7 @@ Some NgModules and their services should be loaded only once by the root `AppMod
|
|||
Importing the module a second time by lazy loading a module could [produce errant behavior](guide/ngmodule-faq#q-why-bad)
|
||||
that may be difficult to detect and diagnose.
|
||||
|
||||
某些模块及其服务只能被根模块`AppModule`加载一次。
|
||||
某些模块及其服务只能被根模块 `AppModule` 加载一次。
|
||||
在惰性加载模块中再次导入这个模块会[导致错误的行为](guide/ngmodule-faq#q-why-bad),这个错误可能非常难于检测和诊断。
|
||||
|
||||
To prevent this issue, write a constructor that attempts to inject the module or service
|
||||
|
@ -794,7 +794,7 @@ You can throw an error or take other remedial action.
|
|||
Certain NgModules, such as `BrowserModule`, implement such a guard.
|
||||
Here is a custom constructor for an NgModule called `CoreModule`.
|
||||
|
||||
某些Angular模块(例如`BrowserModule`)就实现了一个像 Angular 模块那一章的`CoreModule`构造函数那样的守卫。
|
||||
某些 Angular 模块(例如 `BrowserModule`)就实现了一个像 Angular 模块那一章的 `CoreModule` 构造函数那样的守卫。
|
||||
|
||||
<code-example path="ngmodule-faq/src/app/core/core.module.ts" region="ctor" title="src/app/core/core.module.ts (Constructor)" linenums="false">
|
||||
|
||||
|
@ -810,7 +810,7 @@ Here is a custom constructor for an NgModule called `CoreModule`.
|
|||
|
||||
An entry component is any component that Angular loads _imperatively_ by type.
|
||||
|
||||
Angular根据其类型*不可避免地*加载的组件是*入口组件*,
|
||||
Angular 根据其类型*不可避免地*加载的组件是*入口组件*,
|
||||
|
||||
A component loaded _declaratively_ via its selector is _not_ an entry component.
|
||||
|
||||
|
@ -821,15 +821,15 @@ using the component's selector to locate the element in the template.
|
|||
Angular then creates the HTML representation of the component and inserts it into the DOM at the selected element. These aren't entry components.
|
||||
|
||||
大多数应用组件都是声明式加载的。
|
||||
Angular使用该组件的选择器在模板中定位元素,然后创建表现该组件的HTML,并把它插入DOM中所选元素的内部。它们不是入口组件。
|
||||
Angular 使用该组件的选择器在模板中定位元素,然后创建表现该组件的 HTML,并把它插入 DOM 中所选元素的内部。它们不是入口组件。
|
||||
|
||||
The bootstrapped root `AppComponent` is an _entry component_.
|
||||
True, its selector matches an element tag in `index.html`.
|
||||
But `index.html` isn't a component template and the `AppComponent`
|
||||
selector doesn't match an element in any component template.
|
||||
|
||||
而用于引导的根`AppComponent`则是一个*入口组件*。
|
||||
虽然它的选择器匹配了`index.html`中的一个元素,但是`index.html`并不是组件模板,而且`AppComponent`选择器也不会在任何组件模板中出现。
|
||||
而用于引导的根 `AppComponent` 则是一个*入口组件*。
|
||||
虽然它的选择器匹配了 `index.html` 中的一个元素,但是 `index.html` 并不是组件模板,而且 `AppComponent` 选择器也不会在任何组件模板中出现。
|
||||
|
||||
Components in route definitions are also _entry components_.
|
||||
A route definition refers to a component by its _type_.
|
||||
|
@ -838,7 +838,7 @@ loads the component dynamically into a `RouterOutlet`.
|
|||
|
||||
在路由定义中用到的组件也同样是*入口组件*。
|
||||
路由定义根据*类型*来引用组件。
|
||||
路由器会忽略路由组件的选择器(即使它有选择器),并且把该组件动态加载到`RouterOutlet`中。
|
||||
路由器会忽略路由组件的选择器(即使它有选择器),并且把该组件动态加载到 `RouterOutlet` 中。
|
||||
|
||||
For more information, see [Entry Components](guide/entry-components).
|
||||
|
||||
|
@ -855,18 +855,18 @@ that Angular loads into the DOM during the bootstrap process (application launch
|
|||
Other entry components are loaded dynamically by other means, such as with the router.
|
||||
|
||||
引导组件是[入口组件](guide/ngmodule-faq#q-entry-component-defined)的一种。
|
||||
它是被Angular的引导(应用启动)过程加载到DOM中的入口组件。
|
||||
它是被 Angular 的引导(应用启动)过程加载到 DOM 中的入口组件。
|
||||
其它入口组件则是被其它方式动态加载的,比如被路由器加载。
|
||||
|
||||
The `@NgModule.bootstrap` property tells the compiler that this is an entry component _and_
|
||||
it should generate code to bootstrap the application with this component.
|
||||
|
||||
`@NgModule.bootstrap`属性告诉编译器这是一个入口组件,同时它应该生成一些代码来用该组件引导此应用。
|
||||
`@NgModule.bootstrap` 属性告诉编译器这是一个入口组件,同时它应该生成一些代码来用该组件引导此应用。
|
||||
|
||||
There's no need to list a component in both the `bootstrap` and `entryComponents` lists,
|
||||
although doing so is harmless.
|
||||
|
||||
不需要把组件同时列在`bootstrap`和`entryComponent`列表中 —— 虽然这样做也没坏处。
|
||||
不需要把组件同时列在 `bootstrap` 和 `entryComponent` 列表中 —— 虽然这样做也没坏处。
|
||||
|
||||
For more information, see [Entry Components](guide/entry-components).
|
||||
|
||||
|
@ -876,26 +876,26 @@ For more information, see [Entry Components](guide/entry-components).
|
|||
|
||||
## When do I add components to _entryComponents_?
|
||||
|
||||
## 什么时候我应该把组件加到`entryComponents`中?
|
||||
## 什么时候我应该把组件加到 `entryComponents` 中?
|
||||
|
||||
Most application developers won't need to add components to the `entryComponents`.
|
||||
|
||||
大多数应用开发者都不需要把组件添加到`entryComponents`中。
|
||||
大多数应用开发者都不需要把组件添加到 `entryComponents` 中。
|
||||
|
||||
Angular adds certain components to _entry components_ automatically.
|
||||
Components listed in `@NgModule.bootstrap` are added automatically.
|
||||
Components referenced in router configuration are added automatically.
|
||||
These two mechanisms account for almost all entry components.
|
||||
|
||||
Angular会自动把恰当的组件添加到*入口组件*中。
|
||||
列在`@NgModule.bootstrap`中的组件会自动加入。
|
||||
Angular 会自动把恰当的组件添加到*入口组件*中。
|
||||
列在 `@NgModule.bootstrap` 中的组件会自动加入。
|
||||
由路由配置引用到的组件会被自动加入。
|
||||
用这两种机制添加的组件在入口组件中占了绝大多数。
|
||||
|
||||
If your app happens to bootstrap or dynamically load a component _by type_ in some other manner,
|
||||
you must add it to `entryComponents` explicitly.
|
||||
|
||||
如果你的应用要用其它手段来*根据类型*引导或动态加载组件,那就得把它显式添加到`entryComponents`中。
|
||||
如果你的应用要用其它手段来*根据类型*引导或动态加载组件,那就得把它显式添加到 `entryComponents` 中。
|
||||
|
||||
Although it's harmless to add components to this list,
|
||||
it's best to add only the components that are truly _entry components_.
|
||||
|
@ -913,7 +913,7 @@ For more information, see [Entry Components](guide/entry-components).
|
|||
|
||||
## Why does Angular need _entryComponents_?
|
||||
|
||||
## 为什么Angular需要*入口组件*?
|
||||
## 为什么 Angular 需要*入口组件*?
|
||||
|
||||
The reason is _tree shaking_. For production apps you want to load the smallest, fastest code possible. The code should contain only the classes that you actually need.
|
||||
It should exclude a component that's never used, whether or not that component is declared.
|
||||
|
@ -930,7 +930,7 @@ If you don't reference them, the tree shaker drops these components from the fin
|
|||
|
||||
If the [Angular compiler](guide/ngmodule-faq#q-angular-compiler) generated code for every declared component, it would defeat the purpose of the tree shaker.
|
||||
|
||||
如果[Angular编译器](guide/ngmodule-faq#q-angular-compiler)为每个声明的组件都生成了代码,那么摇树优化器的作用就没有了。
|
||||
如果[Angular 编译器](guide/ngmodule-faq#q-angular-compiler)为每个声明的组件都生成了代码,那么摇树优化器的作用就没有了。
|
||||
|
||||
Instead, the compiler adopts a recursive strategy that generates code only for the components you use.
|
||||
|
||||
|
@ -967,38 +967,38 @@ Some suggestions and guidelines appear to have wide appeal.
|
|||
everywhere in your app. This module should consist entirely of `declarations`,
|
||||
most of them exported.
|
||||
|
||||
为那些可能会在应用中到处使用的组件、指令和管道创建`SharedModule`。
|
||||
这种模块应该只包含`declarations`,并且应该导出几乎所有`declarations`里面的声明。
|
||||
为那些可能会在应用中到处使用的组件、指令和管道创建 `SharedModule`。
|
||||
这种模块应该只包含 `declarations`,并且应该导出几乎所有 `declarations` 里面的声明。
|
||||
|
||||
The `SharedModule` may re-export other widget modules, such as `CommonModule`,
|
||||
`FormsModule`, and NgModules with the UI controls that you use most widely.
|
||||
|
||||
`SharedModule`可以重新导出其它小部件模块,比如`CommonModule`、`FormsModule`和提供你广泛使用的UI控件的那些模块。
|
||||
`SharedModule` 可以重新导出其它小部件模块,比如 `CommonModule`、`FormsModule` 和提供你广泛使用的 UI 控件的那些模块。
|
||||
|
||||
The `SharedModule` should not have `providers` for reasons [explained previously](guide/ngmodule-faq#q-why-bad).
|
||||
Nor should any of its imported or re-exported modules have `providers`.
|
||||
|
||||
`SharedModule`***不应该***带有`providers`,原因[在前面解释过了](guide/ngmodule-faq#q-why-bad)。
|
||||
它的导入或重新导出的模块中也不应该有`providers`。
|
||||
`SharedModule`***不应该***带有 `providers`,原因[在前面解释过了](guide/ngmodule-faq#q-why-bad)。
|
||||
它的导入或重新导出的模块中也不应该有 `providers`。
|
||||
如果你要违背这条指导原则,请务必想清楚你在做什么,并要有充分的理由。
|
||||
|
||||
Import the `SharedModule` in your _feature_ modules,
|
||||
both those loaded when the app starts and those you lazy load later.
|
||||
|
||||
在任何特性模块中(无论是你在应用启动时主动加载的模块还是之后惰性加载的模块),你都可以随意导入这个`SharedModule`。
|
||||
在任何特性模块中(无论是你在应用启动时主动加载的模块还是之后惰性加载的模块),你都可以随意导入这个 `SharedModule`。
|
||||
|
||||
### `CoreModule`
|
||||
|
||||
`CoreModule` is a conventional name for an `NgModule` with `providers` for
|
||||
the singleton services you load when the application starts.
|
||||
|
||||
为你要在应用启动时加载的那些服务创建一个带`providers`的`CoreModule`。
|
||||
为你要在应用启动时加载的那些服务创建一个带 `providers` 的 `CoreModule`。
|
||||
|
||||
Import `CoreModule` in the root `AppModule` only.
|
||||
Never import `CoreModule` in any other module.
|
||||
|
||||
只能在根模块`AppModule`中导入`CoreModule`。
|
||||
永远不要在除根模块`AppModule`之外的任何模块中导入`CoreModule`。
|
||||
只能在根模块 `AppModule` 中导入 `CoreModule`。
|
||||
永远不要在除根模块 `AppModule` 之外的任何模块中导入 `CoreModule`。
|
||||
|
||||
Consider making `CoreModule` a pure services module
|
||||
with no `declarations`.
|
||||
|
@ -1032,20 +1032,20 @@ In modern JavaScript, every file is a module
|
|||
(see the [Modules](http://exploringjs.com/es6/ch_modules.html) page of the Exploring ES6 website).
|
||||
Within each file you write an `export` statement to make parts of the module public.
|
||||
|
||||
在现代JavaScript中,每个文件都是模块(参见[模块](http://exploringjs.com/es6/ch_modules.html))。
|
||||
在每个文件中,我们写一个`export`语句将模块的一部分公开。
|
||||
在现代 JavaScript 中,每个文件都是模块(参见[模块](http://exploringjs.com/es6/ch_modules.html))。
|
||||
在每个文件中,我们写一个 `export` 语句将模块的一部分公开。
|
||||
|
||||
An Angular NgModule is a class with the `@NgModule` decorator—JavaScript modules
|
||||
don't have to have the `@NgModule` decorator. Angular's `NgModule` has `imports` and `exports` and they serve a similar purpose.
|
||||
|
||||
Angular 模块是一个带有`@NgModule`装饰器的类,而 JavaScript 模块则没有。
|
||||
Angular的`NgModule`有自己的`imports`和`exports`来达到类似的目的。
|
||||
Angular 模块是一个带有 `@NgModule` 装饰器的类,而 JavaScript 模块则没有。
|
||||
Angular 的 `NgModule` 有自己的 `imports` 和 `exports` 来达到类似的目的。
|
||||
|
||||
You _import_ other NgModules so you can use their exported classes in component templates.
|
||||
You _export_ this NgModule's classes so they can be imported and used by components of _other_ NgModules.
|
||||
|
||||
我们可以*导入*其它Angular模块,以便在当前模块的组件模板中使用它们导出的类。
|
||||
我们可以*导出*当前Angular模块中的类,以便其它模块可以导入它们,并用在自己的组件模板中。
|
||||
我们可以*导入*其它 Angular 模块,以便在当前模块的组件模板中使用它们导出的类。
|
||||
我们可以*导出*当前 Angular 模块中的类,以便其它模块可以导入它们,并用在自己的组件模板中。
|
||||
|
||||
For more information, see [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
|
||||
|
||||
|
@ -1062,20 +1062,20 @@ For more information, see [JavaScript Modules vs. NgModules](guide/ngmodule-vs-j
|
|||
The [Angular compiler](guide/ngmodule-faq#q-angular-compiler) looks inside component templates
|
||||
for other components, directives, and pipes. When it finds one, that's a template reference.
|
||||
|
||||
[Angular编译器](guide/ngmodule-faq#q-angular-compiler)在组件模板内查找其它组件、指令和管道。一旦找到了,那就是一个“模板引用”。
|
||||
[Angular 编译器](guide/ngmodule-faq#q-angular-compiler)在组件模板内查找其它组件、指令和管道。一旦找到了,那就是一个“模板引用”。
|
||||
|
||||
The Angular compiler finds a component or directive in a template when it can match the *selector* of that component or directive to some HTML in that template.
|
||||
|
||||
Angular编译器通过在一个模板的HTML中匹配组件或指令的**选择器(selector)**,来查找组件或指令。
|
||||
Angular 编译器通过在一个模板的 HTML 中匹配组件或指令的**选择器(selector)**,来查找组件或指令。
|
||||
|
||||
The compiler finds a pipe if the pipe's *name* appears within the pipe syntax of the template HTML.
|
||||
|
||||
编译器通过分析模板HTML中的管道语法中是否出现了特定的管道名来查找对应的管道。
|
||||
编译器通过分析模板 HTML 中的管道语法中是否出现了特定的管道名来查找对应的管道。
|
||||
|
||||
Angular only matches selectors and pipe names for classes that are declared by this module
|
||||
or exported by a module that this module imports.
|
||||
|
||||
Angular只查询两种组件、指令或管道:1)那些在当前模块中声明过的,以及2)那些被当前模块导入的模块所导出的。
|
||||
Angular 只查询两种组件、指令或管道:1)那些在当前模块中声明过的,以及 2)那些被当前模块导入的模块所导出的。
|
||||
|
||||
<hr/>
|
||||
|
||||
|
@ -1083,39 +1083,39 @@ Angular只查询两种组件、指令或管道:1)那些在当前模块中声
|
|||
|
||||
## What is the Angular compiler?
|
||||
|
||||
## 什么是Angular编译器?
|
||||
## 什么是 Angular 编译器?
|
||||
|
||||
The Angular compiler converts the application code you write into highly performant JavaScript code.
|
||||
The `@NgModule` metadata plays an important role in guiding the compilation process.
|
||||
|
||||
*Angular编译器*会把我们所写的应用代码转换成高性能的JavaScript代码。
|
||||
在编译过程中,`@NgModule`的元数据扮演了很重要的角色。
|
||||
*Angular 编译器*会把我们所写的应用代码转换成高性能的 JavaScript 代码。
|
||||
在编译过程中,`@NgModule` 的元数据扮演了很重要的角色。
|
||||
|
||||
The code you write isn't immediately executable. For example, components have templates that contain custom elements, attribute directives, Angular binding declarations,
|
||||
and some peculiar syntax that clearly isn't native HTML.
|
||||
|
||||
我们写的代码是无法直接执行的。
|
||||
比如**组件**。
|
||||
组件有一个模板,其中包含了自定义元素、属性型指令、Angular绑定声明和一些显然不属于原生HTML的古怪语法。
|
||||
组件有一个模板,其中包含了自定义元素、属性型指令、Angular 绑定声明和一些显然不属于原生 HTML 的古怪语法。
|
||||
|
||||
The Angular compiler reads the template markup,
|
||||
combines it with the corresponding component class code, and emits _component factories_.
|
||||
|
||||
*Angular编译器*读取模板的HTML,把它和相应的组件类代码组合在一起,并产出*组件工厂*。
|
||||
*Angular 编译器*读取模板的 HTML,把它和相应的组件类代码组合在一起,并产出*组件工厂*。
|
||||
|
||||
A component factory creates a pure, 100% JavaScript representation
|
||||
of the component that incorporates everything described in its `@Component` metadata:
|
||||
the HTML, the binding instructions, the attached styles.
|
||||
|
||||
组件工厂为组件创建纯粹的、100% JavaScript的表示形式,它包含了`@Component`元数据中描述的一切:HTML、绑定指令、附属的样式等……
|
||||
组件工厂为组件创建纯粹的、100% JavaScript 的表示形式,它包含了 `@Component` 元数据中描述的一切:HTML、绑定指令、附属的样式等……
|
||||
|
||||
Because directives and pipes appear in component templates,
|
||||
the Angular compiler incorporates them into compiled component code too.
|
||||
|
||||
由于**指令**和**管道**都出现在组件模板中,*Angular编译器**也同样会把它们组合到编译成的组件代码中。
|
||||
由于**指令**和**管道**都出现在组件模板中,*Angular 编译器**也同样会把它们组合到编译成的组件代码中。
|
||||
|
||||
`@NgModule` metadata tells the Angular compiler what components to compile for this module and
|
||||
how to link this module with other modules.
|
||||
|
||||
|
||||
`@NgModule`元数据告诉*Angular编译器*要为当前模块编译哪些组件,以及如何把当前模块和其它模块链接起来。
|
||||
`@NgModule` 元数据告诉*Angular 编译器*要为当前模块编译哪些组件,以及如何把当前模块和其它模块链接起来。
|
||||
|
|
|
@ -89,7 +89,7 @@ NgModule 类与 JavaScript 模块有下列关键性的不同:
|
|||
* An NgModule bounds [declarable classes](guide/ngmodule-faq#q-declarable) only.
|
||||
Declarables are the only classes that matter to the [Angular compiler](guide/ngmodule-faq#q-angular-compiler).
|
||||
|
||||
Angular模块只绑定了[_可声明的类_](guide/ngmodule-faq#q-declarable),这些可声明的类只是供[Angular编译器](guide/ngmodule-faq#q-angular-compiler)用的。
|
||||
Angular 模块只绑定了[_可声明的类_](guide/ngmodule-faq#q-declarable),这些可声明的类只是供[Angular 编译器](guide/ngmodule-faq#q-angular-compiler)用的。
|
||||
|
||||
* Instead of defining all member classes in one giant file as in a JavaScript module,
|
||||
you list the module's classes in the `@NgModule.declarations` list.
|
||||
|
@ -99,7 +99,7 @@ you list the module's classes in the `@NgModule.declarations` list.
|
|||
* An NgModule can only export the [declarable classes](guide/ngmodule-faq#q-declarable)
|
||||
it owns or imports from other modules. It doesn't declare or export any other kind of class.
|
||||
|
||||
Angular模块只能导出[_可声明的类_](guide/ngmodule-faq#q-declarable)。这可能是它自己拥有的也可能是从其它模块中导入的。它不会声明或导出任何其它类型的类。
|
||||
Angular 模块只能导出[_可声明的类_](guide/ngmodule-faq#q-declarable)。这可能是它自己拥有的也可能是从其它模块中导入的。它不会声明或导出任何其它类型的类。
|
||||
|
||||
* Unlike JavaScript modules, an NgModule can extend the _entire_ application with services
|
||||
by adding providers to the `@NgModule.providers` list.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# NgModules
|
||||
|
||||
# Angular模块 (NgModule)
|
||||
# Angular 模块 (NgModule)
|
||||
|
||||
#### Prerequisites
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
The [**Angular CLI**](https://cli.angular.io/), Angular applications, and Angular itself depend upon features and functionality provided by libraries that are available as [**npm**](https://docs.npmjs.com/) packages.
|
||||
|
||||
[**Angular CLI**](https://cli.angular.io/)、Angular应用程序以及Angular本身都依赖于很多第三方包(包括Angular自己)提供的特性和功能。这些都是 [**npm**](https://docs.npmjs.com/) 包。
|
||||
[**Angular CLI**](https://cli.angular.io/)、Angular 应用程序以及 Angular 本身都依赖于很多第三方包(包括 Angular 自己)提供的特性和功能。这些都是 [**npm**](https://docs.npmjs.com/) 包。
|
||||
|
||||
You can download and install these npm packages with the [**npm client**](https://docs.npmjs.com/cli/install), which runs as a node.js application.
|
||||
|
||||
|
@ -20,7 +20,7 @@ The Angular CLI uses `yarn` by default to install npm packages when you create a
|
|||
|
||||
Node.js and npm are essential to Angular development.
|
||||
|
||||
Node.js和npm是做Angular开发的基础。
|
||||
Node.js 和 npm 是做 Angular 开发的基础。
|
||||
|
||||
[Get them now](https://docs.npmjs.com/getting-started/installing-node "Installing Node.js and updating npm")
|
||||
if they're not already installed on your machine.
|
||||
|
@ -31,14 +31,14 @@ if they're not already installed on your machine.
|
|||
by running the commands `node -v` and `npm -v` in a terminal/console window.
|
||||
Older versions produce errors.
|
||||
|
||||
在终端/控制器窗口运行命令`node -v`和`npm -v`,来**确认你运行的 node 是`v4.x.x`或更高,npm 为`3.x.x`或更高。**
|
||||
在终端/控制器窗口运行命令 `node -v` 和 `npm -v`,来**确认你运行的 node 是 `v4.x.x` 或更高,npm 为 `3.x.x` 或更高。**
|
||||
老版本会产生错误。
|
||||
|
||||
Consider using [nvm](https://github.com/creationix/nvm) for managing multiple
|
||||
versions of node and npm. You may need [nvm](https://github.com/creationix/nvm) if
|
||||
you already have projects running on your machine that use other versions of node and npm.
|
||||
|
||||
我们建议使用[nvm](https://github.com/creationix/nvm)来管理node和npm的多个版本。如果你机器上已经有某些项目运行了node和npm的其它版本,你就会需要[nvm](https://github.com/creationix/nvm)了。
|
||||
我们建议使用[nvm](https://github.com/creationix/nvm)来管理 node 和 npm 的多个版本。如果你机器上已经有某些项目运行了 node 和 npm 的其它版本,你就会需要[nvm](https://github.com/creationix/nvm)了。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -84,15 +84,15 @@ The *devDependencies* are only necessary to *develop* the application.
|
|||
|
||||
The `dependencies` section of `package.json` contains:
|
||||
|
||||
应用程序的`package.json`文件中,`dependencies`下包括:
|
||||
应用程序的 `package.json` 文件中,`dependencies` 下包括:
|
||||
|
||||
* **Angular packages**: Angular core and optional modules; their package names begin `@angular/`.
|
||||
|
||||
**Angular 包**:Angular 的核心和可选模块,它们的包名以`@angular/`开头。
|
||||
**Angular 包**:Angular 的核心和可选模块,它们的包名以 `@angular/` 开头。
|
||||
|
||||
* **Support packages**: 3rd party libraries that must be present for Angular apps to run.
|
||||
|
||||
**支持包**:那些Angular 应用运行时必需的第三方库。
|
||||
**支持包**:那些 Angular 应用运行时必需的第三方库。
|
||||
|
||||
* **Polyfill packages**: Polyfills plug gaps in a browser's JavaScript implementation.
|
||||
|
||||
|
@ -116,7 +116,7 @@ The [`HttpClientModule`](guide/http) is also here, in the '@angular/common/http'
|
|||
**@angular/core**: Critical runtime parts of the framework needed by every application.
|
||||
Includes all metadata decorators, `Component`, `Directive`, dependency injection, and the component lifecycle hooks.
|
||||
|
||||
**@angular/core**:本框架的每个应用都需要的关键运行部件。包括元数据装饰器,如`Component`和`Directive`、依赖注入以及组件生命周期钩子。
|
||||
**@angular/core**:本框架的每个应用都需要的关键运行部件。包括元数据装饰器,如 `Component` 和 `Directive`、依赖注入以及组件生命周期钩子。
|
||||
|
||||
**@angular/compiler**: Angular's *Template Compiler*.
|
||||
It understands templates and can convert them to code that makes the application run and render.
|
||||
|
@ -139,8 +139,8 @@ the pieces that help render into the DOM.
|
|||
This package also includes the `bootstrapStatic()` method
|
||||
for bootstrapping applications for production builds that pre-compile with [AOT](guide/aot-compiler).
|
||||
|
||||
**@angular/platform-browser**:与DOM和浏览器相关的每样东西,特别是帮助往DOM中渲染的那部分。
|
||||
这个包还包含bootstrapStatic方法,用来引导那些在产品构建时要用 [AOT](guide/aot-compiler) 进行编译的应用程序。
|
||||
**@angular/platform-browser**:与 DOM 和浏览器相关的每样东西,特别是帮助往 DOM 中渲染的那部分。
|
||||
这个包还包含 bootstrapStatic 方法,用来引导那些在产品构建时要用 [AOT](guide/aot-compiler) 进行编译的应用程序。
|
||||
|
||||
**@angular/platform-browser-dynamic**: Includes [Providers](api/core/Provider)
|
||||
and methods to compile and run the app on the client
|
||||
|
@ -184,7 +184,7 @@ which polyfills missing features for several popular browser.
|
|||
**[rxjs](https://github.com/benlesh/RxJS)**: Many Angular APIs return _observables_. RxJS is an implementation of the proposed [Observables specification](https://github.com/zenparsing/es-observable) currently before the
|
||||
[TC39](http://www.ecma-international.org/memento/TC39.htm) committee that determines standards for the JavaScript language.
|
||||
|
||||
**[rxjs](https://github.com/benlesh/RxJS)**:很多 Angular API 都会返回**可观察对象(Observable)**。RxJS 是个对[Observables规范](https://github.com/zenparsing/es-observable)的当前实现。[TC39](http://www.ecma-international.org/memento/TC39.htm)委员会将来会决定它是否成为 JavaScript 语言标准的一部分。
|
||||
**[rxjs](https://github.com/benlesh/RxJS)**:很多 Angular API 都会返回**可观察对象(Observable)**。RxJS 是个对[Observables 规范](https://github.com/zenparsing/es-observable)的当前实现。[TC39](http://www.ecma-international.org/memento/TC39.htm)委员会将来会决定它是否成为 JavaScript 语言标准的一部分。
|
||||
|
||||
**[zone.js](https://github.com/angular/zone.js)**: Angular relies on zone.js to run Angular's change detection processes when native JavaScript operations raise events. Zone.js is an implementation of a [specification](https://gist.github.com/mhevery/63fdcdf7c65886051d55) currently before the
|
||||
[TC39](http://www.ecma-international.org/memento/TC39.htm) committee that determines standards for the JavaScript language.
|
||||
|
|
|
@ -6,7 +6,7 @@ Every application starts out with what seems like a simple task: get data, trans
|
|||
Getting data could be as simple as creating a local variable or as complex as streaming data over a WebSocket.
|
||||
|
||||
每个应用开始的时候差不多都是一些简单任务:获取数据、转换它们,然后把它们显示给用户。
|
||||
获取数据可能简单到创建一个局部变量就行,也可能复杂到从WebSocket中获取数据流。
|
||||
获取数据可能简单到创建一个局部变量就行,也可能复杂到从 WebSocket 中获取数据流。
|
||||
|
||||
Once data arrive, you could push their raw `toString` values directly to the view,
|
||||
but that rarely makes for a good user experience.
|
||||
|
@ -14,7 +14,7 @@ For example, in most use cases, users prefer to see a date in a simple format li
|
|||
<samp>April 15, 1988</samp> rather than the raw string format
|
||||
<samp>Fri Apr 15 1988 00:00:00 GMT-0700 (Pacific Daylight Time)</samp>.
|
||||
|
||||
一旦取到数据,我们可以把它们原始值的`toString`结果直接推入视图中。
|
||||
一旦取到数据,我们可以把它们原始值的 `toString` 结果直接推入视图中。
|
||||
但这种做法很少能具备良好的用户体验。
|
||||
比如,几乎每个人都更喜欢简单的日期格式,例如<samp>1988-04-15</samp>,而不是服务端传过来的原始字符串格式 —— <samp>Fri Apr 15 1988 00:00:00 GMT-0700 (Pacific Daylight Time)</samp>。
|
||||
|
||||
|
@ -24,11 +24,11 @@ You can almost think of them as styles.
|
|||
In fact, you might like to apply them in your HTML templates as you do styles.
|
||||
|
||||
显然,有些值最好显示成用户友好的格式。我们很快就会发现,在很多不同的应用中,都在重复做出某些相同的变换。
|
||||
我们几乎会把它们看做某种CSS样式,事实上,我们也确实更喜欢在HTML模板中应用它们 —— 就像CSS样式一样。
|
||||
我们几乎会把它们看做某种 CSS 样式,事实上,我们也确实更喜欢在 HTML 模板中应用它们 —— 就像 CSS 样式一样。
|
||||
|
||||
Introducing Angular pipes, a way to write display-value transformations that you can declare in your HTML.
|
||||
|
||||
通过引入Angular管道,我们可以把这种简单的“显示-值”转换器声明在HTML中。
|
||||
通过引入 Angular 管道,我们可以把这种简单的“显示-值”转换器声明在 HTML 中。
|
||||
|
||||
You can run the <live-example></live-example> in Stackblitz and download the code from there.
|
||||
|
||||
|
@ -43,7 +43,7 @@ In this page, you'll use pipes to transform a component's birthday property into
|
|||
a human-friendly date.
|
||||
|
||||
管道把数据作为输入,然后转换它,给出期望的输出。
|
||||
我们将把组件的`birthday`属性转换成对人类更友好的日期格式,来说明这一点:
|
||||
我们将把组件的 `birthday` 属性转换成对人类更友好的日期格式,来说明这一点:
|
||||
|
||||
<code-example path="pipes/src/app/hero-birthday1.component.ts" title="src/app/hero-birthday1.component.ts" linenums="false">
|
||||
|
||||
|
@ -61,8 +61,8 @@ Inside the interpolation expression, you flow the component's `birthday` value t
|
|||
[pipe operator](guide/template-syntax#pipe) ( | ) to the [Date pipe](api/common/DatePipe)
|
||||
function on the right. All pipes work this way.
|
||||
|
||||
在这个插值表达式中,我们让组件的`birthday`值通过[管道操作符](guide/template-syntax#pipe)( | )流动到
|
||||
右侧的[Date管道](api/common/DatePipe)函数中。所有管道都会用这种方式工作。
|
||||
在这个插值表达式中,我们让组件的 `birthday` 值通过[管道操作符](guide/template-syntax#pipe)( | )流动到
|
||||
右侧的[Date 管道](api/common/DatePipe)函数中。所有管道都会用这种方式工作。
|
||||
|
||||
## Built-in pipes
|
||||
|
||||
|
@ -72,7 +72,7 @@ Angular comes with a stock of pipes such as
|
|||
`DatePipe`, `UpperCasePipe`, `LowerCasePipe`, `CurrencyPipe`, and `PercentPipe`.
|
||||
They are all available for use in any template.
|
||||
|
||||
Angular内置了一些管道,比如`DatePipe`、`UpperCasePipe`、`LowerCasePipe`、`CurrencyPipe`和`PercentPipe`。
|
||||
Angular 内置了一些管道,比如 `DatePipe`、`UpperCasePipe`、`LowerCasePipe`、`CurrencyPipe` 和 `PercentPipe`。
|
||||
它们全都可以直接用在任何模板中。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
@ -80,11 +80,11 @@ Angular内置了一些管道,比如`DatePipe`、`UpperCasePipe`、`LowerCasePi
|
|||
Read more about these and many other built-in pipes in the [pipes topics](api?type=pipe) of the
|
||||
[API Reference](api); filter for entries that include the word "pipe".
|
||||
|
||||
要学习更多内置管道的知识,参见[API参考手册](api?type=pipe),并用“pipe”为关键词对结果进行过滤。
|
||||
要学习更多内置管道的知识,参见[API 参考手册](api?type=pipe),并用“pipe”为关键词对结果进行过滤。
|
||||
|
||||
Angular doesn't have a `FilterPipe` or an `OrderByPipe` for reasons explained in the [Appendix](guide/pipes#no-filter-pipe) of this page.
|
||||
|
||||
Angular没有`FilterPipe`或`OrderByPipe`管道,原因在[后面的附录中](guide/pipes#no-filter-pipe)有解释。
|
||||
Angular 没有 `FilterPipe` 或 `OrderByPipe` 管道,原因在[后面的附录中](guide/pipes#no-filter-pipe)有解释。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -97,14 +97,14 @@ To add parameters to a pipe, follow the pipe name with a colon ( : ) and then th
|
|||
(such as `currency:'EUR'`). If the pipe accepts multiple parameters, separate the values with colons (such as `slice:1:5`)
|
||||
|
||||
管道可能接受任何数量的可选参数来对它的输出进行微调。
|
||||
我们可以在管道名后面添加一个冒号( : )再跟一个参数值,来为管道添加参数(比如`currency:'EUR'`)。
|
||||
如果我们的管道可以接受多个参数,那么就用冒号来分隔这些参数值(比如`slice:1:5`)。
|
||||
我们可以在管道名后面添加一个冒号( : )再跟一个参数值,来为管道添加参数(比如 `currency:'EUR'`)。
|
||||
如果我们的管道可以接受多个参数,那么就用冒号来分隔这些参数值(比如 `slice:1:5`)。
|
||||
|
||||
Modify the birthday template to give the date pipe a format parameter.
|
||||
After formatting the hero's April 15th birthday, it renders as **<samp>04/15/88</samp>**:
|
||||
|
||||
我们将通过修改生日模板来给这个日期管道提供一个格式化参数。
|
||||
当格式化完该英雄的4月15日生日之后,它应该被渲染成**<samp>04/15/88</samp>**。
|
||||
当格式化完该英雄的 4 月 15 日生日之后,它应该被渲染成**<samp>04/15/88</samp>**。
|
||||
|
||||
<code-example path="pipes/src/app/app.component.html" region="format-birthday" title="src/app/app.component.html" linenums="false">
|
||||
|
||||
|
@ -122,7 +122,7 @@ In other words, you can control the format through a binding the same way you co
|
|||
Write a second component that *binds* the pipe's format parameter
|
||||
to the component's `format` property. Here's the template for that component:
|
||||
|
||||
我们来写第二个组件,它把管道的格式参数*绑定*到该组件的`format`属性。这里是新组件的模板:
|
||||
我们来写第二个组件,它把管道的格式参数*绑定*到该组件的 `format` 属性。这里是新组件的模板:
|
||||
|
||||
<code-example path="pipes/src/app/hero-birthday2.component.ts" region="template" title="src/app/hero-birthday2.component.ts (template)" linenums="false">
|
||||
|
||||
|
@ -132,8 +132,8 @@ You also added a button to the template and bound its click event to the compone
|
|||
That method toggles the component's `format` property between a short form
|
||||
(`'shortDate'`) and a longer form (`'fullDate'`).
|
||||
|
||||
我们还能在模板中添加一个按钮,并把它的点击事件绑定到组件的`toggleFormat()`方法。
|
||||
此方法会在短日期格式(`'shortDate'`)和长日期格式(`'fullDate'`)之间切换组件的`format`属性。
|
||||
我们还能在模板中添加一个按钮,并把它的点击事件绑定到组件的 `toggleFormat()` 方法。
|
||||
此方法会在短日期格式(`'shortDate'`)和长日期格式(`'fullDate'`)之间切换组件的 `format` 属性。
|
||||
|
||||
<code-example path="pipes/src/app/hero-birthday2.component.ts" region="class" title="src/app/hero-birthday2.component.ts (class)" linenums="false">
|
||||
|
||||
|
@ -154,7 +154,7 @@ As you click the button, the displayed date alternates between
|
|||
Read more about the `DatePipe` format options in the [Date Pipe](api/common/DatePipe)
|
||||
API Reference page.
|
||||
|
||||
要了解更多`DatePipes`的格式选项,请参阅[API文档](api/common/DatePipe)。
|
||||
要了解更多 `DatePipes` 的格式选项,请参阅[API 文档](api/common/DatePipe)。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -168,7 +168,7 @@ the birthday is chained to the `DatePipe` and on to the `UpperCasePipe`.
|
|||
The birthday displays as **<samp>APR 15, 1988</samp>**.
|
||||
|
||||
我们可以把管道链在一起,以组合出一些潜在的有用功能。
|
||||
下面这个例子中,我们把`birthday`链到`DatePipe`管道,然后又链到`UpperCasePipe`,这样我们就可以把生日显示成大写形式了。
|
||||
下面这个例子中,我们把 `birthday` 链到 `DatePipe` 管道,然后又链到 `UpperCasePipe`,这样我们就可以把生日显示成大写形式了。
|
||||
比如下面的代码就会把生日显示成**<samp>APR 15, 1988</samp>**:
|
||||
|
||||
<code-example path="pipes/src/app/app.component.html" region="chained-birthday" title="src/app/app.component.html" linenums="false">
|
||||
|
@ -178,7 +178,7 @@ The birthday displays as **<samp>APR 15, 1988</samp>**.
|
|||
This example—which displays **<samp>FRIDAY, APRIL 15, 1988</samp>**—chains
|
||||
the same pipes as above, but passes in a parameter to `date` as well.
|
||||
|
||||
下面这个显示**<samp>FRIDAY, APRIL 15, 1988</samp>**的例子用同样的方式链接了这两个管道,而且同时还给`date`管道传进去一个参数。
|
||||
下面这个显示**<samp>FRIDAY, APRIL 15, 1988</samp>**的例子用同样的方式链接了这两个管道,而且同时还给 `date` 管道传进去一个参数。
|
||||
|
||||
<code-example path="pipes/src/app/app.component.html" region="chained-parameter-birthday" title="src/app/app.component.html" linenums="false">
|
||||
|
||||
|
@ -192,7 +192,7 @@ You can write your own custom pipes.
|
|||
Here's a custom pipe named `ExponentialStrengthPipe` that can boost a hero's powers:
|
||||
|
||||
我们还可以写自己的自定义管道。
|
||||
下面就是一个名叫`ExponentialStrengthPipe`的管道,它可以放大英雄的能力:
|
||||
下面就是一个名叫 `ExponentialStrengthPipe` 的管道,它可以放大英雄的能力:
|
||||
|
||||
<code-example path="pipes/src/app/exponential-strength.pipe.ts" title="src/app/exponential-strength.pipe.ts" linenums="false">
|
||||
|
||||
|
@ -209,24 +209,24 @@ This pipe definition reveals the following key points:
|
|||
* The pipe class implements the `PipeTransform` interface's `transform` method that
|
||||
accepts an input value followed by optional parameters and returns the transformed value.
|
||||
|
||||
这个管道类实现了`PipeTransform`接口的`transform`方法,该方法接受一个输入值和一些可选参数,并返回转换后的值。
|
||||
这个管道类实现了 `PipeTransform` 接口的 `transform` 方法,该方法接受一个输入值和一些可选参数,并返回转换后的值。
|
||||
|
||||
* There will be one additional argument to the `transform` method for each parameter passed to the pipe.
|
||||
Your pipe has one such parameter: the `exponent`.
|
||||
|
||||
当每个输入值被传给`transform`方法时,还会带上另一个参数,比如我们这个管道中的`exponent`(放大指数)。
|
||||
当每个输入值被传给 `transform` 方法时,还会带上另一个参数,比如我们这个管道中的 `exponent`(放大指数)。
|
||||
|
||||
* To tell Angular that this is a pipe, you apply the
|
||||
`@Pipe` decorator, which you import from the core Angular library.
|
||||
|
||||
我们通过`@Pipe`装饰器告诉Angular:这是一个管道。该装饰器是从Angular的`core`库中引入的。
|
||||
我们通过 `@Pipe` 装饰器告诉 Angular:这是一个管道。该装饰器是从 Angular 的 `core` 库中引入的。
|
||||
|
||||
* The `@Pipe` decorator allows you to define the
|
||||
pipe name that you'll use within template expressions. It must be a valid JavaScript identifier.
|
||||
Your pipe's name is `exponentialStrength`.
|
||||
|
||||
这个`@Pipe`装饰器允许我们定义管道的名字,这个名字会被用在模板表达式中。它必须是一个有效的JavaScript标识符。
|
||||
比如,我们这个管道的名字是`exponentialStrength`。
|
||||
这个 `@Pipe` 装饰器允许我们定义管道的名字,这个名字会被用在模板表达式中。它必须是一个有效的 JavaScript 标识符。
|
||||
比如,我们这个管道的名字是 `exponentialStrength`。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
|
@ -238,9 +238,9 @@ The `transform` method is essential to a pipe.
|
|||
The `PipeTransform` *interface* defines that method and guides both tooling and the compiler.
|
||||
Technically, it's optional; Angular looks for and executes the `transform` method regardless.
|
||||
|
||||
`transform`方法是管道的基本要素。
|
||||
`transform` 方法是管道的基本要素。
|
||||
`PipeTransform`*接口*中定义了它,并用它指导各种工具和编译器。
|
||||
理论上说,它是可选的。Angular不会管它,而是直接查找并执行`transform`方法。
|
||||
理论上说,它是可选的。Angular 不会管它,而是直接查找并执行 `transform` 方法。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -266,20 +266,20 @@ Note the following:
|
|||
|
||||
* You must include your pipe in the `declarations` array of the `AppModule`.
|
||||
|
||||
我们必须在`AppModule`的`declarations`数组中包含这个管道。
|
||||
我们必须在 `AppModule` 的 `declarations` 数组中包含这个管道。
|
||||
|
||||
<div class="callout is-helpful">
|
||||
|
||||
<header>Remember the declarations array</header>
|
||||
|
||||
<header>别忘了`declarations`数组</header>
|
||||
<header>别忘了 `declarations` 数组</header>
|
||||
|
||||
You must register custom pipes.
|
||||
If you don't, Angular reports an error.
|
||||
Angular CLI's generator registers the pipe automatically.
|
||||
|
||||
我们必须手动注册自定义管道。如果忘了,Angular就会报告一个错误。
|
||||
在前一个例子中我们没有把`DatePipe`列进去,这是因为Angular所有的内置管道都已经预注册过了。
|
||||
我们必须手动注册自定义管道。如果忘了,Angular 就会报告一个错误。
|
||||
在前一个例子中我们没有把 `DatePipe` 列进去,这是因为 Angular 所有的内置管道都已经预注册过了。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -297,7 +297,7 @@ Upgrade the example to a "Power Boost Calculator" that combines
|
|||
your pipe and two-way data binding with `ngModel`.
|
||||
|
||||
仅仅升级模板来测试这个自定义管道其实没多大意思。
|
||||
我们干脆把这个例子升级为“能力倍增计算器”,它可以把该管道和使用`ngModel`的双向数据绑定组合起来。
|
||||
我们干脆把这个例子升级为“能力倍增计算器”,它可以把该管道和使用 `ngModel` 的双向数据绑定组合起来。
|
||||
|
||||
<code-example path="pipes/src/app/power-boost-calculator.component.ts" title="src/app/power-boost-calculator.component.ts">
|
||||
|
||||
|
@ -317,8 +317,8 @@ Angular looks for changes to data-bound values through a *change detection* proc
|
|||
every keystroke, mouse move, timer tick, and server response. This could be expensive.
|
||||
Angular strives to lower the cost whenever possible and appropriate.
|
||||
|
||||
Angular通过*变更检测*过程来查找绑定值的更改,并在每一次JavaScript事件之后运行:每次按键、鼠标移动、定时器以及服务器的响应。
|
||||
这可能会让变更检测显得很昂贵,但是Angular会尽可能降低变更检测的成本。
|
||||
Angular 通过*变更检测*过程来查找绑定值的更改,并在每一次 JavaScript 事件之后运行:每次按键、鼠标移动、定时器以及服务器的响应。
|
||||
这可能会让变更检测显得很昂贵,但是 Angular 会尽可能降低变更检测的成本。
|
||||
|
||||
Angular picks a simpler, faster change detection algorithm when you use a pipe.
|
||||
|
||||
|
@ -331,7 +331,7 @@ Angular picks a simpler, faster change detection algorithm when you use a pipe.
|
|||
In the next example, the component uses the default, aggressive change detection strategy to monitor and update
|
||||
its display of every hero in the `heroes` array. Here's the template:
|
||||
|
||||
我们下一个例子中的组件使用默认的、激进(昂贵)的变更检测策略来检测和更新`heroes`数组中的每个英雄。下面是它的模板:
|
||||
我们下一个例子中的组件使用默认的、激进(昂贵)的变更检测策略来检测和更新 `heroes` 数组中的每个英雄。下面是它的模板:
|
||||
|
||||
<code-example path="pipes/src/app/flying-heroes.component.html" region="template-1" title="src/app/flying-heroes.component.html (v1)" linenums="false">
|
||||
|
||||
|
@ -349,9 +349,9 @@ You can add heroes and Angular updates the display when you do.
|
|||
If you click the `reset` button, Angular replaces `heroes` with a new array of the original heroes and updates the display.
|
||||
If you added the ability to remove or change a hero, Angular would detect those changes and update the display as well.
|
||||
|
||||
我们可以添加新的英雄,加完之后,Angular就会更新显示。
|
||||
`reset`按钮会把`heroes`替换成一个由原来的英雄组成的新数组,重置完之后,Angular就会更新显示。
|
||||
如果我们提供了删除或修改英雄的能力,Angular也会检测到那些更改,并更新显示。
|
||||
我们可以添加新的英雄,加完之后,Angular 就会更新显示。
|
||||
`reset` 按钮会把 `heroes` 替换成一个由原来的英雄组成的新数组,重置完之后,Angular 就会更新显示。
|
||||
如果我们提供了删除或修改英雄的能力,Angular 也会检测到那些更改,并更新显示。
|
||||
|
||||
<h3 class="no-toc"><i>FlyingHeroesPipe</i></h3>
|
||||
|
||||
|
@ -359,7 +359,7 @@ If you added the ability to remove or change a hero, Angular would detect those
|
|||
|
||||
Add a `FlyingHeroesPipe` to the `*ngFor` repeater that filters the list of heroes to just those heroes who can fly.
|
||||
|
||||
我们来往`*ngFor`重复器中添加一个`FlyingHeroesPipe`管道,这个管道能过滤出所有会飞的英雄。
|
||||
我们来往 `*ngFor` 重复器中添加一个 `FlyingHeroesPipe` 管道,这个管道能过滤出所有会飞的英雄。
|
||||
|
||||
<code-example path="pipes/src/app/flying-heroes.component.html" region="template-flying-heroes" title="src/app/flying-heroes.component.html (flyers)" linenums="false">
|
||||
|
||||
|
@ -367,7 +367,7 @@ Add a `FlyingHeroesPipe` to the `*ngFor` repeater that filters the list of heroe
|
|||
|
||||
Here's the `FlyingHeroesPipe` implementation, which follows the pattern for custom pipes described earlier.
|
||||
|
||||
下面是`FlyingHeroesPipe`的实现,它遵循了我们以前见过的那些写自定义管道的模式。
|
||||
下面是 `FlyingHeroesPipe` 的实现,它遵循了我们以前见过的那些写自定义管道的模式。
|
||||
|
||||
<code-example path="pipes/src/app/flying-heroes.pipe.ts" region="pure" title="src/app/flying-heroes.pipe.ts" linenums="false">
|
||||
|
||||
|
@ -381,7 +381,7 @@ when you add flying heroes, none of them are displayed under "Heroes who fly."
|
|||
Although you're not getting the behavior you want, Angular isn't broken.
|
||||
It's just using a different change-detection algorithm that ignores changes to the list or any of its items.
|
||||
|
||||
虽然我们没有得到期望的行为,但Angular也没有出错。
|
||||
虽然我们没有得到期望的行为,但 Angular 也没有出错。
|
||||
这里只是用了另一种变更检测算法 —— 它会忽略对列表及其子项所做的任何更改。
|
||||
|
||||
Notice how a hero is added:
|
||||
|
@ -395,15 +395,15 @@ Notice how a hero is added:
|
|||
You add the hero into the `heroes` array. The reference to the array hasn't changed.
|
||||
It's the same array. That's all Angular cares about. From its perspective, *same array, no change, no display update*.
|
||||
|
||||
当我们往`heroes`数组中添加一个新的英雄时,这个数组的引用并没有改变。它还是那个数组。而引用却是Angular所关心的一切。
|
||||
从Angular的角度来看,*这是同一个数组,没有变化,也就不需要更新显示*。
|
||||
当我们往 `heroes` 数组中添加一个新的英雄时,这个数组的引用并没有改变。它还是那个数组。而引用却是 Angular 所关心的一切。
|
||||
从 Angular 的角度来看,*这是同一个数组,没有变化,也就不需要更新显示*。
|
||||
|
||||
To fix that, create an array with the new hero appended and assign that to `heroes`.
|
||||
This time Angular detects that the array reference has changed.
|
||||
It executes the pipe and updates the display with the new array, which includes the new flying hero.
|
||||
|
||||
我们可以修复它。让我们创建一个新数组,把这个英雄追加进去,并把它赋给`heroes`。
|
||||
这次,Angular检测到数组的引用变化了。它执行了这个管道,并使用这个新数组更新显示,这次它就包括新的飞行英雄了。
|
||||
我们可以修复它。让我们创建一个新数组,把这个英雄追加进去,并把它赋给 `heroes`。
|
||||
这次,Angular 检测到数组的引用变化了。它执行了这个管道,并使用这个新数组更新显示,这次它就包括新的飞行英雄了。
|
||||
|
||||
If you *mutate* the array, no pipe is invoked and the display isn't updated;
|
||||
if you *replace* the array, the pipe executes and the display is updated.
|
||||
|
@ -423,7 +423,7 @@ When do you replace the array? When the data change.
|
|||
That's an easy rule to follow in *this* example
|
||||
where the only way to change the data is by adding a hero.
|
||||
|
||||
直接替换这个数组是通知Angular更新显示的一种高效方式。
|
||||
直接替换这个数组是通知 Angular 更新显示的一种高效方式。
|
||||
我们该什么时候替换这个数组呢?当数据变化的时候。
|
||||
在这个*玩具级*例子中,这是一个简单的规则,因为这里修改数据的唯一途径就是添加新英雄。
|
||||
|
||||
|
@ -437,7 +437,7 @@ The component should be unaware of pipes.
|
|||
|
||||
更多情况下,我们不知道什么时候数据变化了,尤其是在那些有很多种途径改动数据的程序中 —— 可能在程序中很远的地方。
|
||||
组件就是一个通常无法知道那些改动的例子。此外,它会导致削足适履 —— 扭曲我们的组件设计来适应管道。
|
||||
我们要尽可能保持组件类独立于HTML。组件不应该关心管道的存在。
|
||||
我们要尽可能保持组件类独立于 HTML。组件不应该关心管道的存在。
|
||||
|
||||
For filtering flying heroes, consider an *impure pipe*.
|
||||
|
||||
|
@ -454,7 +454,7 @@ impure like this:
|
|||
|
||||
有两类管道:**纯**的与**非纯**的。
|
||||
默认情况下,管道都是纯的。我们以前见到的每个管道都是纯的。
|
||||
通过把它的`pure`标志设置为`false`,我们可以制作一个非纯管道。我们可以像这样让`FlyingHeroesPipe`变成非纯的:
|
||||
通过把它的 `pure` 标志设置为 `false`,我们可以制作一个非纯管道。我们可以像这样让 `FlyingHeroesPipe` 变成非纯的:
|
||||
|
||||
<code-example path="pipes/src/app/flying-heroes.pipe.ts" region="pipe-decorator" title="src/app/flying-heroes.pipe.ts" linenums="false">
|
||||
|
||||
|
@ -472,15 +472,15 @@ Angular executes a *pure pipe* only when it detects a *pure change* to the input
|
|||
A pure change is either a change to a primitive input value (`String`, `Number`, `Boolean`, `Symbol`)
|
||||
or a changed object reference (`Date`, `Array`, `Function`, `Object`).
|
||||
|
||||
Angular只有在它检测到输入值发生了*纯变更*时才会执行*纯管道*。
|
||||
Angular 只有在它检测到输入值发生了*纯变更*时才会执行*纯管道*。
|
||||
***纯变更***是指对原始类型值(`String`、`Number`、`Boolean`、`Symbol`)的更改,
|
||||
或者对对象引用(`Date`、`Array`、`Function`、`Object`)的更改。
|
||||
|
||||
Angular ignores changes within (composite) objects.
|
||||
It won't call a pure pipe if you change an input month, add to an input array, or update an input object property.
|
||||
|
||||
Angular会忽略(复合)对象*内部*的更改。
|
||||
如果我们更改了输入日期(`Date`)中的月份、往一个输入数组(`Array`)中添加新值或者更新了一个输入对象(`Object`)的属性,Angular都不会调用纯管道。
|
||||
Angular 会忽略(复合)对象*内部*的更改。
|
||||
如果我们更改了输入日期(`Date`)中的月份、往一个输入数组(`Array`)中添加新值或者更新了一个输入对象(`Object`)的属性,Angular 都不会调用纯管道。
|
||||
|
||||
This may seem restrictive but it's also fast.
|
||||
An object reference check is fast—much faster than a deep check for
|
||||
|
@ -488,7 +488,7 @@ differences—so Angular can quickly determine if it can skip both the
|
|||
pipe execution and a view update.
|
||||
|
||||
这可能看起来是一种限制,但它保证了速度。
|
||||
对象引用的检查是非常快的(比递归的深检查要快得多),所以Angular可以快速的决定是否应该跳过管道执行和视图更新。
|
||||
对象引用的检查是非常快的(比递归的深检查要快得多),所以 Angular 可以快速的决定是否应该跳过管道执行和视图更新。
|
||||
|
||||
For this reason, a pure pipe is preferable when you can live with the change detection strategy.
|
||||
When you can't, you *can* use the impure pipe.
|
||||
|
@ -514,7 +514,7 @@ a point that's discussed later in this page.
|
|||
Angular executes an *impure pipe* during every component change detection cycle.
|
||||
An impure pipe is called often, as often as every keystroke or mouse-move.
|
||||
|
||||
Angular会在每个组件的变更检测周期中执行*非纯管道*。
|
||||
Angular 会在每个组件的变更检测周期中执行*非纯管道*。
|
||||
非纯管道可能会被调用很多次,和每个按键或每次鼠标移动一样频繁。
|
||||
|
||||
With that concern in mind, implement an impure pipe with great care.
|
||||
|
@ -532,7 +532,7 @@ An expensive, long-running pipe could destroy the user experience.
|
|||
A flip of the switch turns the `FlyingHeroesPipe` into a `FlyingHeroesImpurePipe`.
|
||||
The complete implementation is as follows:
|
||||
|
||||
我们把`FlyingHeroesPipe`换成了`FlyingHeroesImpurePipe`。
|
||||
我们把 `FlyingHeroesPipe` 换成了 `FlyingHeroesImpurePipe`。
|
||||
下面是完整的实现:
|
||||
|
||||
<code-tabs>
|
||||
|
@ -550,12 +550,12 @@ The complete implementation is as follows:
|
|||
You inherit from `FlyingHeroesPipe` to prove the point that nothing changed internally.
|
||||
The only difference is the `pure` flag in the pipe metadata.
|
||||
|
||||
我们把它从`FlyingHeroesPipe`中继承下来,以证明无需改动内部代码。
|
||||
唯一的区别是管道元数据中的`pure`标志。
|
||||
我们把它从 `FlyingHeroesPipe` 中继承下来,以证明无需改动内部代码。
|
||||
唯一的区别是管道元数据中的 `pure` 标志。
|
||||
|
||||
This is a good candidate for an impure pipe because the `transform` function is trivial and fast.
|
||||
|
||||
这是一个很好地非纯管道候选者,因为它的`transform`函数又小又快。
|
||||
这是一个很好地非纯管道候选者,因为它的 `transform` 函数又小又快。
|
||||
|
||||
<code-example path="pipes/src/app/flying-heroes.pipe.ts" linenums="false" title="src/app/flying-heroes.pipe.ts (filter)" region="filter">
|
||||
|
||||
|
@ -563,7 +563,7 @@ This is a good candidate for an impure pipe because the `transform` function is
|
|||
|
||||
You can derive a `FlyingHeroesImpureComponent` from `FlyingHeroesComponent`.
|
||||
|
||||
我们可以从`FlyingHeroesComponent`派生出一个`FlyingHeroesImpureComponent`。
|
||||
我们可以从 `FlyingHeroesComponent` 派生出一个 `FlyingHeroesImpureComponent`。
|
||||
|
||||
<code-example path="pipes/src/app/flying-heroes-impure.component.html" linenums="false" title="src/app/flying-heroes-impure.component.html (excerpt)" region="template-flying-heroes">
|
||||
|
||||
|
@ -586,20 +586,20 @@ The Angular `AsyncPipe` is an interesting example of an impure pipe.
|
|||
The `AsyncPipe` accepts a `Promise` or `Observable` as input
|
||||
and subscribes to the input automatically, eventually returning the emitted values.
|
||||
|
||||
Angular的`AsyncPipe`是一个有趣的非纯管道的例子。
|
||||
`AsyncPipe`接受一个`Promise`或`Observable`作为输入,并且自动订阅这个输入,最终返回它们给出的值。
|
||||
Angular 的 `AsyncPipe` 是一个有趣的非纯管道的例子。
|
||||
`AsyncPipe` 接受一个 `Promise` 或 `Observable` 作为输入,并且自动订阅这个输入,最终返回它们给出的值。
|
||||
|
||||
The `AsyncPipe` is also stateful.
|
||||
The pipe maintains a subscription to the input `Observable` and
|
||||
keeps delivering values from that `Observable` as they arrive.
|
||||
|
||||
`AsyncPipe`管道是有状态的。
|
||||
该管道维护着一个所输入的`Observable`的订阅,并且持续从那个`Observable`中发出新到的值。
|
||||
`AsyncPipe` 管道是有状态的。
|
||||
该管道维护着一个所输入的 `Observable` 的订阅,并且持续从那个 `Observable` 中发出新到的值。
|
||||
|
||||
This next example binds an `Observable` of message strings
|
||||
(`message$`) to a view with the `async` pipe.
|
||||
|
||||
在下面例子中,我们使用该`async`管道把一个消息字符串(`message$`)的`Observable`绑定到视图中。
|
||||
在下面例子中,我们使用该 `async` 管道把一个消息字符串(`message$`)的 `Observable` 绑定到视图中。
|
||||
|
||||
<code-example path="pipes/src/app/hero-async-message.component.ts" title="src/app/hero-async-message.component.ts">
|
||||
|
||||
|
@ -611,7 +611,7 @@ extract the resolved values and expose them for binding,
|
|||
and have to unsubscribe when it's destroyed
|
||||
(a potent source of memory leaks).
|
||||
|
||||
这个Async管道节省了组件的样板代码。
|
||||
这个 Async 管道节省了组件的样板代码。
|
||||
组件不用订阅这个异步数据源,而且不用在被销毁时取消订阅(如果订阅了而忘了反订阅容易导致隐晦的内存泄露)。
|
||||
|
||||
<h3 class="no-toc">An impure caching pipe</h3>
|
||||
|
@ -620,7 +620,7 @@ and have to unsubscribe when it's destroyed
|
|||
|
||||
Write one more impure pipe, a pipe that makes an HTTP request.
|
||||
|
||||
我们来写更多的非纯管道:一个向服务器发起HTTP请求的管道。
|
||||
我们来写更多的非纯管道:一个向服务器发起 HTTP 请求的管道。
|
||||
|
||||
Remember that impure pipes are called every few milliseconds.
|
||||
If you're not careful, this pipe will punish the server with requests.
|
||||
|
@ -632,7 +632,7 @@ In the following code, the pipe only calls the server when the request URL chang
|
|||
The code uses the [Angular http](guide/http) client to retrieve data:
|
||||
|
||||
我们确实得小心点。
|
||||
这个管道只有当所请求的URL发生变化时才会向服务器发起请求。它会缓存服务器的响应。
|
||||
这个管道只有当所请求的 URL 发生变化时才会向服务器发起请求。它会缓存服务器的响应。
|
||||
代码如下,它使用[Angular http](guide/http)客户端来接收数据
|
||||
|
||||
<code-example path="pipes/src/app/fetch-json.pipe.ts" title="src/app/fetch-json.pipe.ts">
|
||||
|
@ -642,7 +642,7 @@ The code uses the [Angular http](guide/http) client to retrieve data:
|
|||
Now demonstrate it in a harness component whose template defines two bindings to this pipe,
|
||||
both requesting the heroes from the `heroes.json` file.
|
||||
|
||||
接下来我们用一个测试台组件演示一下它,该组件的模板中定义了两个使用到此管道的绑定,他们都从`heroes.json`文件中取得英雄数据。
|
||||
接下来我们用一个测试台组件演示一下它,该组件的模板中定义了两个使用到此管道的绑定,他们都从 `heroes.json` 文件中取得英雄数据。
|
||||
|
||||
<code-example path="pipes/src/app/hero-list.component.ts" title="src/app/hero-list.component.ts">
|
||||
|
||||
|
@ -666,7 +666,7 @@ A breakpoint on the pipe's request for data shows the following:
|
|||
|
||||
* Each pipe instance caches its own URL and data.
|
||||
|
||||
每个管道实例都缓存了它自己的URL和数据。
|
||||
每个管道实例都缓存了它自己的 URL 和数据。
|
||||
|
||||
* Each pipe instance only calls the server once.
|
||||
|
||||
|
@ -677,14 +677,14 @@ A breakpoint on the pipe's request for data shows the following:
|
|||
In the previous code sample, the second `fetch` pipe binding demonstrates more pipe chaining.
|
||||
It displays the same hero data in JSON format by chaining through to the built-in `JsonPipe`.
|
||||
|
||||
第二个绑定除了用到`FetchPipe`之外还链接了更多管道。
|
||||
我们把获取数据的结果同时显示在第一个绑定和第二个绑定中。第二个绑定中,我们通过链接到一个内置管道`JsonPipe`把它转成了JSON格式。
|
||||
第二个绑定除了用到 `FetchPipe` 之外还链接了更多管道。
|
||||
我们把获取数据的结果同时显示在第一个绑定和第二个绑定中。第二个绑定中,我们通过链接到一个内置管道 `JsonPipe` 把它转成了 JSON 格式。
|
||||
|
||||
<div class="callout is-helpful">
|
||||
|
||||
<header>Debugging with the json pipe</header>
|
||||
|
||||
<header>借助json管道进行调试</header>
|
||||
<header>借助 json 管道进行调试</header>
|
||||
|
||||
The [JsonPipe](api/common/JsonPipe)
|
||||
provides an easy way to diagnosis a mysteriously failing data binding or
|
||||
|
@ -714,10 +714,10 @@ So are the `ExponentialStrengthPipe` and `FlyingHeroesPipe`.
|
|||
A few steps back, you reviewed the `FlyingHeroesImpurePipe`—an impure pipe with a pure function.
|
||||
|
||||
我们在本章前面见过的管道都是用纯函数实现的。
|
||||
内置的`DatePipe`就是一个用纯函数实现的纯管道。
|
||||
`ExponentialStrengthPipe`是如此,
|
||||
`FlyingHeroesComponent`也是如此。
|
||||
不久前我们刚看过的`FlyingHeroesImpurePipe`,是一个*用纯函数实现的非纯管道*。
|
||||
内置的 `DatePipe` 就是一个用纯函数实现的纯管道。
|
||||
`ExponentialStrengthPipe` 是如此,
|
||||
`FlyingHeroesComponent` 也是如此。
|
||||
不久前我们刚看过的 `FlyingHeroesImpurePipe`,是一个*用纯函数实现的非纯管道*。
|
||||
|
||||
But always implement a *pure pipe* with a *pure function*.
|
||||
Otherwise, you'll see many console errors regarding expressions that changed after they were checked.
|
||||
|
@ -738,7 +738,7 @@ of your views.
|
|||
Explore Angular's inventory of built-in pipes in the [API Reference](api?type=pipe).
|
||||
Try writing a custom pipe and perhaps contributing it to the community.
|
||||
|
||||
要浏览Angular的所有内置管道,请到[API参考手册](api?type=pipe)。
|
||||
要浏览 Angular 的所有内置管道,请到[API 参考手册](api?type=pipe)。
|
||||
学着写写自定义管道,并贡献给开发社区。
|
||||
|
||||
{@a no-filter-pipe}
|
||||
|
@ -751,8 +751,8 @@ Angular doesn't provide pipes for filtering or sorting lists.
|
|||
Developers familiar with AngularJS know these as `filter` and `orderBy`.
|
||||
There are no equivalents in Angular.
|
||||
|
||||
Angular没有随身发布过滤或列表排序的管道。
|
||||
熟悉AngularJS的开发人员应该知道`filter`和`orderBy`过滤器,但在Angular中它们没有等价物。
|
||||
Angular 没有随身发布过滤或列表排序的管道。
|
||||
熟悉 AngularJS 的开发人员应该知道 `filter` 和 `orderBy` 过滤器,但在 Angular 中它们没有等价物。
|
||||
|
||||
This isn't an oversight. Angular doesn't offer such pipes because
|
||||
they perform poorly and prevent aggressive minification.
|
||||
|
@ -760,9 +760,9 @@ Both `filter` and `orderBy` require parameters that reference object properties.
|
|||
Earlier in this page, you learned that such pipes must be [impure](guide/pipes#pure-and-impure-pipes) and that
|
||||
Angular calls impure pipes in almost every change-detection cycle.
|
||||
|
||||
这并不是疏忽。Angular不想提供这些管道,因为 (a) 它们性能堪忧,以及 (b) 它们会阻止比较激进的代码最小化(minification)。
|
||||
无论是`filter`还是`orderBy`都需要它的参数引用对象型属性。
|
||||
我们前面学过,这样的管道必然是[*非纯管道*](guide/pipes#pure-and-impure-pipes),并且Angular会在几乎每一次变更检测周期中调用非纯管道。
|
||||
这并不是疏忽。Angular 不想提供这些管道,因为 (a) 它们性能堪忧,以及 (b) 它们会阻止比较激进的代码最小化(minification)。
|
||||
无论是 `filter` 还是 `orderBy` 都需要它的参数引用对象型属性。
|
||||
我们前面学过,这样的管道必然是[*非纯管道*](guide/pipes#pure-and-impure-pipes),并且 Angular 会在几乎每一次变更检测周期中调用非纯管道。
|
||||
|
||||
Filtering and especially sorting are expensive operations.
|
||||
The user experience can degrade severely for even moderate-sized lists when Angular calls these pipe methods many times per second.
|
||||
|
@ -771,14 +771,14 @@ That charge is fair in the indirect sense that AngularJS prepared this performan
|
|||
by offering `filter` and `orderBy` in the first place.
|
||||
|
||||
过滤、 特别是排序是昂贵的操作。
|
||||
当Angular每秒调用很多次这类管道函数时,即使是中等规模的列表都可能严重降低用户体验。
|
||||
在AngularJS程序中,`filter`和`orderBy`经常被误用,结果连累到Angular自身,人们抱怨说它太慢。
|
||||
从某种意义上,这也不冤:谁叫AngularJS把`filter`和`orderBy`作为首发队员呢?是它自己准备了这个性能陷阱。
|
||||
当 Angular 每秒调用很多次这类管道函数时,即使是中等规模的列表都可能严重降低用户体验。
|
||||
在 AngularJS 程序中,`filter` 和 `orderBy` 经常被误用,结果连累到 Angular 自身,人们抱怨说它太慢。
|
||||
从某种意义上,这也不冤:谁叫 AngularJS 把 `filter` 和 `orderBy` 作为首发队员呢?是它自己准备了这个性能陷阱。
|
||||
|
||||
The minification hazard is also compelling, if less obvious. Imagine a sorting pipe applied to a list of heroes.
|
||||
The list might be sorted by hero `name` and `planet` of origin properties in the following way:
|
||||
|
||||
虽然不是很明显,但代码最小化方面也存在风险。想象一个用于英雄列表的排序管道。我们可能根据英雄原始属性中的`name`和`planet`进行排序,就像这样:
|
||||
虽然不是很明显,但代码最小化方面也存在风险。想象一个用于英雄列表的排序管道。我们可能根据英雄原始属性中的 `name` 和 `planet` 进行排序,就像这样:
|
||||
|
||||
<code-example language="html">
|
||||
|
||||
|
@ -792,17 +792,17 @@ You identify the sort fields by text strings, expecting the pipe to reference a
|
|||
Unfortunately, aggressive minification manipulates the `Hero` property names so that `Hero.name` and `Hero.planet`
|
||||
become something like `Hero.a` and `Hero.b`. Clearly `hero['name']` doesn't work.
|
||||
|
||||
我们使用文本字符串来标记出排序字段,期望管道通过索引形式(如`hero['name']`)引用属性的值。
|
||||
不幸的是,激进的代码最小化策略会*改变*`Hero`类的属性名,所以`Hero.name`和`Hero.planet`可能会被变成`Hero.a`和`Hero.b`。
|
||||
显然,`hero['name']`是无法正常工作的。
|
||||
我们使用文本字符串来标记出排序字段,期望管道通过索引形式(如 `hero['name']`)引用属性的值。
|
||||
不幸的是,激进的代码最小化策略会*改变*`Hero` 类的属性名,所以 `Hero.name` 和 `Hero.planet` 可能会被变成 `Hero.a` 和 `Hero.b`。
|
||||
显然,`hero['name']` 是无法正常工作的。
|
||||
|
||||
While some may not care to minify this aggressively,
|
||||
the Angular product shouldn't prevent anyone from minifying aggressively.
|
||||
Therefore, the Angular team decided that everything Angular provides will minify safely.
|
||||
|
||||
我们中的一些人可能不想做那么激进的最小化。但那不过是*我们的*选择而已。
|
||||
Angular作为一个产品不应该拒绝那些想做激进的最小化的人。
|
||||
所以,Angular开发组决定随Angular一起发布的每样东西,都应该能被安全的最小化。
|
||||
Angular 作为一个产品不应该拒绝那些想做激进的最小化的人。
|
||||
所以,Angular 开发组决定随 Angular 一起发布的每样东西,都应该能被安全的最小化。
|
||||
|
||||
The Angular team and many experienced Angular developers strongly recommend moving
|
||||
filtering and sorting logic into the component itself.
|
||||
|
@ -811,8 +811,8 @@ over when and how often to execute the supporting logic.
|
|||
Any capabilities that you would have put in a pipe and shared across the app can be
|
||||
written in a filtering/sorting service and injected into the component.
|
||||
|
||||
Angular开发组和一些有经验的Angular开发者强烈建议你:把你的过滤和排序逻辑挪进组件本身。
|
||||
组件可以对外暴露一个`filteredHeroes`或`sortedHeroes`属性,这样它就获得控制权,以决定要用什么频度去执行其它辅助逻辑。
|
||||
Angular 开发组和一些有经验的 Angular 开发者强烈建议你:把你的过滤和排序逻辑挪进组件本身。
|
||||
组件可以对外暴露一个 `filteredHeroes` 或 `sortedHeroes` 属性,这样它就获得控制权,以决定要用什么频度去执行其它辅助逻辑。
|
||||
你原本准备实现为管道,并在整个应用中共享的那些功能,都能被改写为一个过滤/排序的服务,并注入到组件中。
|
||||
|
||||
If these performance and minification considerations don't apply to you, you can always create your own such pipes
|
||||
|
|
|
@ -18,12 +18,12 @@ application in TypeScript, using the Angular CLI
|
|||
while adhering to the [Style Guide](guide/styleguide) recommendations that
|
||||
benefit _every_ Angular project.
|
||||
|
||||
在这一章CLI快速起步中,我们的目标是构建并运行一个超级简单的Angular应用。我们会使用Angular-CLI来让每个Angular应用从[风格指南](guide/styleguide)中获益。
|
||||
在这一章 CLI 快速起步中,我们的目标是构建并运行一个超级简单的 Angular 应用。我们会使用 Angular-CLI 来让每个 Angular 应用从[风格指南](guide/styleguide)中获益。
|
||||
|
||||
By the end of the chapter, you'll have a basic understanding of development with the CLI
|
||||
and a foundation for both these documentation samples and for real world applications.
|
||||
|
||||
在本章的末尾,我们会通过CLI对开发过程有一个最基本的理解,并将其作为其它文档范例以及真实应用的基础。
|
||||
在本章的末尾,我们会通过 CLI 对开发过程有一个最基本的理解,并将其作为其它文档范例以及真实应用的基础。
|
||||
|
||||
And you can also <a href="generated/zips/cli-quickstart/cli-quickstart.zip" target="_blank">download the example.</a>
|
||||
|
||||
|
@ -31,7 +31,7 @@ And you can also <a href="generated/zips/cli-quickstart/cli-quickstart.zip" targ
|
|||
|
||||
<h2 id='devenv'>Step 1. Set up the Development Environment</h2>
|
||||
|
||||
<h2 id='devenv'>步骤1. 设置开发环境</h2>
|
||||
<h2 id='devenv'>步骤 1. 设置开发环境</h2>
|
||||
|
||||
You need to set up your development environment before you can do anything.
|
||||
|
||||
|
@ -40,7 +40,7 @@ You need to set up your development environment before you can do anything.
|
|||
Install **[Node.js® and npm](https://nodejs.org/en/download/)**
|
||||
if they are not already on your machine.
|
||||
|
||||
如果你的电脑里没有Node.js®和npm,请安装**[它们](https://nodejs.org/en/download/)**。
|
||||
如果你的电脑里没有 Node.js®和 npm,请安装**[它们](https://nodejs.org/en/download/)**。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
|
@ -66,7 +66,7 @@ Then **install the [Angular CLI](https://github.com/angular/angular-cli)** globa
|
|||
|
||||
<h2 id='create-proj'>Step 2. Create a new project</h2>
|
||||
|
||||
<h2 id='create-proj'>步骤2. 创建新项目</h2>
|
||||
<h2 id='create-proj'>步骤 2. 创建新项目</h2>
|
||||
|
||||
Open a terminal window.
|
||||
|
||||
|
@ -88,13 +88,13 @@ Patience, please.
|
|||
It takes time to set up a new project; most of it is spent installing npm packages.
|
||||
|
||||
请耐心等待。
|
||||
创建新项目需要花费很多时间,大多数时候都是在安装那些npm包。
|
||||
创建新项目需要花费很多时间,大多数时候都是在安装那些 npm 包。
|
||||
|
||||
</div>
|
||||
|
||||
<h2 id='serve'>Step 3: Serve the application</h2>
|
||||
|
||||
<h2 id='serve'>步骤3. 启动开发服务器</h2>
|
||||
<h2 id='serve'>步骤 3. 启动开发服务器</h2>
|
||||
|
||||
Go to the project directory and launch the server.
|
||||
|
||||
|
@ -110,12 +110,12 @@ Go to the project directory and launch the server.
|
|||
The `ng serve` command launches the server, watches your files,
|
||||
and rebuilds the app as you make changes to those files.
|
||||
|
||||
`ng serve`命令会启动开发服务器,监听文件变化,并在修改这些文件时重新构建此应用。
|
||||
`ng serve` 命令会启动开发服务器,监听文件变化,并在修改这些文件时重新构建此应用。
|
||||
|
||||
Using the `--open` (or just `-o`) option will automatically open your browser
|
||||
on `http://localhost:4200/`.
|
||||
|
||||
使用`--open`(或`-o`)参数可以自动打开浏览器并访问`http://localhost:4200/`。
|
||||
使用 `--open`(或 `-o`)参数可以自动打开浏览器并访问 `http://localhost:4200/`。
|
||||
|
||||
Your app greets you with a message:
|
||||
|
||||
|
@ -127,19 +127,19 @@ Your app greets you with a message:
|
|||
|
||||
<h2 id='first-component'>Step 4: Edit your first Angular component</h2>
|
||||
|
||||
<h2 id='first-component'>步骤4. 编辑我们的第一个Angular组件</h2>
|
||||
<h2 id='first-component'>步骤 4. 编辑我们的第一个 Angular 组件</h2>
|
||||
|
||||
The CLI created the first Angular component for you.
|
||||
This is the _root component_ and it is named `app-root`.
|
||||
You can find it in `./src/app/app.component.ts`.
|
||||
|
||||
这个CLI为我们创建了第一个Angular组件。
|
||||
它就是名叫`app-root`的*根组件*。
|
||||
你可以在`./src/app/app.component.ts`目录下找到它。
|
||||
这个 CLI 为我们创建了第一个 Angular 组件。
|
||||
它就是名叫 `app-root` 的*根组件*。
|
||||
你可以在 `./src/app/app.component.ts` 目录下找到它。
|
||||
|
||||
Open the component file and change the `title` property from _Welcome to app!!_ to _Welcome to My First Angular App!!_:
|
||||
|
||||
打开这个组件文件,并且把`title`属性从 _Welcome to app!!_ 改为 _Welcome to My First Angular App!!_ :
|
||||
打开这个组件文件,并且把 `title` 属性从 _Welcome to app!!_ 改为 _Welcome to My First Angular App!!_ :
|
||||
|
||||
<code-example path="cli-quickstart/src/app/app.component.ts" region="title" title="src/app/app.component.ts" linenums="false"></code-example>
|
||||
|
||||
|
@ -172,7 +172,7 @@ That's about all you'd expect to do in a "Hello, World" app.
|
|||
You're ready to take the [Tour of Heroes Tutorial](tutorial) and build
|
||||
a small application that demonstrates the great things you can build with Angular.
|
||||
|
||||
现在,你可以开始[英雄指南](tutorial)教程,通过构建一个小型应用来学习如何用Angular构建各种大型应用了。
|
||||
现在,你可以开始[英雄指南](tutorial)教程,通过构建一个小型应用来学习如何用 Angular 构建各种大型应用了。
|
||||
|
||||
Or you can stick around a bit longer to learn about the files in your brand new project.
|
||||
|
||||
|
@ -184,7 +184,7 @@ Or you can stick around a bit longer to learn about the files in your brand new
|
|||
|
||||
An Angular CLI project is the foundation for both quick experiments and enterprise solutions.
|
||||
|
||||
Angular CLI项目是做快速试验和开发企业解决方案的基础。
|
||||
Angular CLI 项目是做快速试验和开发企业解决方案的基础。
|
||||
|
||||
The first file you should check out is `README.md`.
|
||||
It has some basic information on how to use CLI commands.
|
||||
|
@ -192,8 +192,8 @@ Whenever you want to know more about how Angular CLI works make sure to visit
|
|||
[the Angular CLI repository](https://github.com/angular/angular-cli) and
|
||||
[Wiki](https://github.com/angular/angular-cli/wiki).
|
||||
|
||||
你首先要看的文件是`README.md`。
|
||||
它提供了一些如何使用CLI命令的基础信息。
|
||||
你首先要看的文件是 `README.md`。
|
||||
它提供了一些如何使用 CLI 命令的基础信息。
|
||||
如果你想了解 Angular CLI 的工作原理,请访问 [Angular CLI 的仓库](https://github.com/angular/angular-cli)及其
|
||||
[Wiki](https://github.com/angular/angular-cli/wiki)。
|
||||
|
||||
|
@ -203,14 +203,14 @@ Some of the generated files might be unfamiliar to you.
|
|||
|
||||
### The `src` folder
|
||||
|
||||
### `src`文件夹
|
||||
### `src` 文件夹
|
||||
|
||||
Your app lives in the `src` folder.
|
||||
All Angular components, templates, styles, images, and anything else your app needs go here.
|
||||
Any files outside of this folder are meant to support building your app.
|
||||
|
||||
你的应用代码位于`src`文件夹中。
|
||||
所有的Angular组件、模板、样式、图片以及你的应用所需的任何东西都在那里。
|
||||
你的应用代码位于 `src` 文件夹中。
|
||||
所有的 Angular 组件、模板、样式、图片以及你的应用所需的任何东西都在那里。
|
||||
这个文件夹之外的文件都是为构建应用提供支持用的。
|
||||
|
||||
<div class='filetree'>
|
||||
|
@ -317,7 +317,7 @@ Any files outside of this folder are meant to support building your app.
|
|||
It is the **root** component of what will become a tree of nested components
|
||||
as the application evolves.
|
||||
|
||||
使用HTML模板、CSS样式和单元测试定义`AppComponent`组件。
|
||||
使用 HTML 模板、CSS 样式和单元测试定义 `AppComponent` 组件。
|
||||
它是**根**组件,随着应用的成长它会成为一棵组件树的根节点。
|
||||
|
||||
</td>
|
||||
|
@ -338,8 +338,8 @@ Any files outside of this folder are meant to support building your app.
|
|||
Right now it declares only the `AppComponent`.
|
||||
Soon there will be more components to declare.
|
||||
|
||||
定义`AppModule`,[根模块](guide/bootstrapping "AppModule: 根模块")为 Angular 描述如何组装应用。
|
||||
目前,它只声明了`AppComponent`。
|
||||
定义 `AppModule`,[根模块](guide/bootstrapping "AppModule: 根模块")为 Angular 描述如何组装应用。
|
||||
目前,它只声明了 `AppComponent`。
|
||||
不久,它将声明更多组件。
|
||||
|
||||
</td>
|
||||
|
@ -385,9 +385,9 @@ Any files outside of this folder are meant to support building your app.
|
|||
|
||||
这个文件夹中包括为各个目标环境准备的文件,它们导出了一些应用中要用到的配置变量。
|
||||
这些文件会在构建应用时被替换。
|
||||
比如你可能在产品环境中使用不同的API端点地址,或使用不同的统计Token参数。
|
||||
比如你可能在产品环境中使用不同的 API 端点地址,或使用不同的统计 Token 参数。
|
||||
甚至使用一些模拟服务。
|
||||
所有这些,CLI都替你考虑到了。
|
||||
所有这些,CLI 都替你考虑到了。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -428,9 +428,9 @@ Any files outside of this folder are meant to support building your app.
|
|||
The CLI automatically adds all `js` and `css` files when building your app so you
|
||||
never need to add any `<script>` or `<link>` tags here manually.
|
||||
|
||||
这是别人访问你的网站是看到的主页面的HTML文件。
|
||||
这是别人访问你的网站是看到的主页面的 HTML 文件。
|
||||
大多数情况下你都不用编辑它。
|
||||
在构建应用时,CLI会自动把所有`js`和`css`文件添加进去,所以你不必在这里手动添加任何 `<script>` 或 `<link>` 标签。
|
||||
在构建应用时,CLI 会自动把所有 `js` 和 `css` 文件添加进去,所以你不必在这里手动添加任何 `<script>` 或 `<link>` 标签。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -453,8 +453,8 @@ Any files outside of this folder are meant to support building your app.
|
|||
without changing any code by appending the`--aot` flag to the `ng build` and `ng serve` commands.
|
||||
|
||||
这是应用的主要入口点。
|
||||
使用[JIT compiler](guide/glossary#jit)编译器编译本应用,并启动应用的根模块`AppModule`,使其运行在浏览器中。
|
||||
你还可以使用[AOT compiler](guide/glossary#ahead-of-time-aot-compilation)编译器,而不用修改任何代码 —— 只要给`ng build` 或 `ng serve` 传入 `--aot` 参数就可以了。
|
||||
使用[JIT compiler](guide/glossary#jit)编译器编译本应用,并启动应用的根模块 `AppModule`,使其运行在浏览器中。
|
||||
你还可以使用[AOT compiler](guide/glossary#ahead-of-time-aot-compilation)编译器,而不用修改任何代码 —— 只要给 `ng build` 或 `ng serve` 传入 `--aot` 参数就可以了。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -475,9 +475,9 @@ Any files outside of this folder are meant to support building your app.
|
|||
You should be pretty safe with `core-js` and `zone.js`, but be sure to check out
|
||||
the [Browser Support guide](guide/browser-support) for more information.
|
||||
|
||||
不同的浏览器对Web标准的支持程度也不同。
|
||||
不同的浏览器对 Web 标准的支持程度也不同。
|
||||
腻子脚本(polyfill)能帮我们把这些不同点进行标准化。
|
||||
你只要使用`core-js` 和 `zone.js`通常就够了,不过你也可以查看[浏览器支持指南](guide/browser-support)以了解更多信息。
|
||||
你只要使用 `core-js` 和 `zone.js` 通常就够了,不过你也可以查看[浏览器支持指南](guide/browser-support)以了解更多信息。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -538,7 +538,7 @@ Any files outside of this folder are meant to support building your app.
|
|||
TypeScript compiler configuration for the Angular app (`tsconfig.app.json`)
|
||||
and for the unit tests (`tsconfig.spec.json`).
|
||||
|
||||
TypeScript编译器的配置文件。`tsconfig.app.json`是为Angular应用准备的,而`tsconfig.spec.json`是为单元测试准备的。
|
||||
TypeScript 编译器的配置文件。`tsconfig.app.json` 是为 Angular 应用准备的,而 `tsconfig.spec.json` 是为单元测试准备的。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -554,8 +554,8 @@ The `src/` folder is just one of the items inside the project's root folder.
|
|||
Other files help you build, test, maintain, document, and deploy the app.
|
||||
These files go in the root folder next to `src/`.
|
||||
|
||||
`src/`文件夹是项目的根文件夹之一。
|
||||
其它文件是用来帮助你构建、测试、维护、文档化和发布应用的。它们放在根目录下,和`src/`平级。
|
||||
`src/` 文件夹是项目的根文件夹之一。
|
||||
其它文件是用来帮助你构建、测试、维护、文档化和发布应用的。它们放在根目录下,和 `src/` 平级。
|
||||
|
||||
<div class='filetree'>
|
||||
|
||||
|
@ -646,9 +646,9 @@ These files go in the root folder next to `src/`.
|
|||
just so happens to test your main app.
|
||||
That's also why they have their own `tsconfig.e2e.json`.
|
||||
|
||||
在`e2e/`下是端到端(end-to-end)测试。
|
||||
它们不在`src/`下,是因为端到端测试实际上和应用是相互独立的,它只适用于测试你的应用而已。
|
||||
这也就是为什么它会拥有自己的`tsconfig.json`。
|
||||
在 `e2e/` 下是端到端(end-to-end)测试。
|
||||
它们不在 `src/` 下,是因为端到端测试实际上和应用是相互独立的,它只适用于测试你的应用而已。
|
||||
这也就是为什么它会拥有自己的 `tsconfig.json`。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -667,7 +667,7 @@ These files go in the root folder next to `src/`.
|
|||
`Node.js` creates this folder and puts all third party modules listed in
|
||||
`package.json` inside of it.
|
||||
|
||||
`Node.js`创建了这个文件夹,并且把`package.json`中列举的所有第三方模块都放在其中。
|
||||
`Node.js` 创建了这个文件夹,并且把 `package.json` 中列举的所有第三方模块都放在其中。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -688,7 +688,7 @@ These files go in the root folder next to `src/`.
|
|||
when your project is built.
|
||||
Check out the official documentation if you want to know more.
|
||||
|
||||
Angular CLI的配置文件。
|
||||
Angular CLI 的配置文件。
|
||||
在这个文件中,我们可以设置一系列默认值,还可以配置项目编译时要包含的那些文件。
|
||||
要了解更多,请参阅它的官方文档。
|
||||
|
||||
|
@ -712,7 +712,7 @@ These files go in the root folder next to `src/`.
|
|||
See http://editorconfig.org for more information.
|
||||
|
||||
给你的编辑器看的一个简单配置文件,它用来确保参与你项目的每个人都具有基本的编辑器配置。
|
||||
大多数的编辑器都支持`.editorconfig`文件,详情参见 http://editorconfig.org 。
|
||||
大多数的编辑器都支持 `.editorconfig` 文件,详情参见 http://editorconfig.org 。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -730,7 +730,7 @@ These files go in the root folder next to `src/`.
|
|||
|
||||
Git configuration to make sure autogenerated files are not commited to source control.
|
||||
|
||||
一个Git的配置文件,用来确保某些自动生成的文件不会被提交到源码控制系统中。
|
||||
一个 Git 的配置文件,用来确保某些自动生成的文件不会被提交到源码控制系统中。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -749,7 +749,7 @@ These files go in the root folder next to `src/`.
|
|||
Unit test configuration for the [Karma test runner](https://karma-runner.github.io),
|
||||
used when running `ng test`.
|
||||
|
||||
给[Karma](https://karma-runner.github.io)的单元测试配置,当运行`ng test`时会用到它。
|
||||
给[Karma](https://karma-runner.github.io)的单元测试配置,当运行 `ng test` 时会用到它。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -768,7 +768,7 @@ These files go in the root folder next to `src/`.
|
|||
`npm` configuration listing the third party packages your project uses.
|
||||
You can also add your own [custom scripts](https://docs.npmjs.com/misc/scripts) here.
|
||||
|
||||
`npm`配置文件,其中列出了项目使用到的第三方依赖包。
|
||||
`npm` 配置文件,其中列出了项目使用到的第三方依赖包。
|
||||
你还可以在这里添加自己的[自定义脚本](https://docs.npmjs.com/misc/scripts)。
|
||||
|
||||
</td>
|
||||
|
@ -788,7 +788,7 @@ These files go in the root folder next to `src/`.
|
|||
End-to-end test configuration for [Protractor](http://www.protractortest.org/),
|
||||
used when running `ng e2e`.
|
||||
|
||||
给[Protractor](http://www.protractortest.org/)使用的端到端测试配置文件,当运行`ng e2e`的时候会用到它。
|
||||
给[Protractor](http://www.protractortest.org/)使用的端到端测试配置文件,当运行 `ng e2e` 的时候会用到它。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -808,7 +808,7 @@ These files go in the root folder next to `src/`.
|
|||
Make sure to enhance it with project documentation so that anyone
|
||||
checking out the repo can build your app!
|
||||
|
||||
项目的基础文档,预先写入了CLI命令的信息。
|
||||
项目的基础文档,预先写入了 CLI 命令的信息。
|
||||
别忘了用项目文档改进它,以便每个查看此仓库的人都能据此构建出你的应用。
|
||||
|
||||
</td>
|
||||
|
@ -827,7 +827,7 @@ These files go in the root folder next to `src/`.
|
|||
|
||||
TypeScript compiler configuration for your IDE to pick up and give you helpful tooling.
|
||||
|
||||
TypeScript编译器的配置,你的IDE会借助它来给你提供更好的帮助。
|
||||
TypeScript 编译器的配置,你的 IDE 会借助它来给你提供更好的帮助。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -847,8 +847,8 @@ These files go in the root folder next to `src/`.
|
|||
[Codelyzer](http://codelyzer.com/), used when running `ng lint`.
|
||||
Linting helps keep your code style consistent.
|
||||
|
||||
给[TSLint](https://palantir.github.io/tslint/)和[Codelyzer](http://codelyzer.com/)用的配置信息,当运行`ng lint`时会用到。
|
||||
Lint功能可以帮你保持代码风格的统一。
|
||||
给[TSLint](https://palantir.github.io/tslint/)和[Codelyzer](http://codelyzer.com/)用的配置信息,当运行 `ng lint` 时会用到。
|
||||
Lint 功能可以帮你保持代码风格的统一。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -866,7 +866,7 @@ If you're new to Angular, continue with the
|
|||
[tutorial](tutorial "Tour of Heroes tutorial").
|
||||
You can skip the "Setup" step since you're already using the Angular CLI setup.
|
||||
|
||||
如果你刚刚开始使用Angular,我们建议你遵循这个[教程](tutorial "《英雄指南》教程")。
|
||||
如果你刚刚开始使用 Angular,我们建议你遵循这个[教程](tutorial "《英雄指南》教程")。
|
||||
你可以跳过“环境设置”一章,因为你已经在使用 Angular-CLI 设置好环境了。
|
||||
|
||||
</div>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -7,11 +7,11 @@ protections against common web-application vulnerabilities and attacks such as c
|
|||
scripting attacks. It doesn't cover application-level security, such as authentication (_Who is
|
||||
this user?_) and authorization (_What can this user do?_).
|
||||
|
||||
Web应用程序的安全涉及到很多方面。针对常见的漏洞和攻击,比如跨站脚本攻击,Angular提供了一些内置的保护措施。本章将讨论这些内置保护措施,但不会涉及应用级安全,比如用户认证(_这个用户是谁?_)和授权(_这个用户能做什么?_)。
|
||||
Web 应用程序的安全涉及到很多方面。针对常见的漏洞和攻击,比如跨站脚本攻击,Angular 提供了一些内置的保护措施。本章将讨论这些内置保护措施,但不会涉及应用级安全,比如用户认证(_这个用户是谁?_)和授权(_这个用户能做什么?_)。
|
||||
|
||||
For more information about the attacks and mitigations described below, see [OWASP Guide Project](https://www.owasp.org/index.php/Category:OWASP_Guide_Project).
|
||||
|
||||
要了解更多攻防信息,参见[开放式Web应用程序安全项目(OWASP)](https://www.owasp.org/index.php/Category:OWASP_Guide_Project)。
|
||||
要了解更多攻防信息,参见[开放式 Web 应用程序安全项目(OWASP)](https://www.owasp.org/index.php/Category:OWASP_Guide_Project)。
|
||||
|
||||
You can run the <live-example></live-example> in Stackblitz and download the code from there.
|
||||
|
||||
|
@ -23,7 +23,7 @@ You can run the <live-example></live-example> in Stackblitz and download the cod
|
|||
|
||||
To report vulnerabilities in Angular itself, email us at [security@angular.io](mailto:security@angular.io).
|
||||
|
||||
给我们([security@angular.io](mailto:security@angular.io))发邮件,报告Angular本身的漏洞。
|
||||
给我们([security@angular.io](mailto:security@angular.io))发邮件,报告 Angular 本身的漏洞。
|
||||
|
||||
For more information about how Google handles security issues, see [Google's security
|
||||
philosophy](https://www.google.com/about/appsecurity/).
|
||||
|
@ -39,21 +39,21 @@ We regularly update the Angular libraries, and these updates may fix security de
|
|||
previous versions. Check the Angular [change
|
||||
log](https://github.com/angular/angular/blob/master/CHANGELOG.md) for security-related updates.
|
||||
|
||||
**及时把Angular包更新到最新版本。**
|
||||
我们会频繁的更新Angular库,这些更新可能会修复之前版本中发现的安全漏洞。查看Angular的[更新记录](https://github.com/angular/angular/blob/master/CHANGELOG.md),了解与安全有关的更新。
|
||||
**及时把 Angular 包更新到最新版本。**
|
||||
我们会频繁的更新 Angular 库,这些更新可能会修复之前版本中发现的安全漏洞。查看 Angular 的[更新记录](https://github.com/angular/angular/blob/master/CHANGELOG.md),了解与安全有关的更新。
|
||||
|
||||
* **Don't modify your copy of Angular.**
|
||||
Private, customized versions of Angular tend to fall behind the current version and may not include
|
||||
important security fixes and enhancements. Instead, share your Angular improvements with the
|
||||
community and make a pull request.
|
||||
|
||||
**不要修改你的Angular副本。**
|
||||
私有的、定制版的Angular往往跟不上最新版本,这可能导致你忽略重要的安全修复与增强。反之,应该在社区共享你对Angular所做的改进并创建Pull Request。
|
||||
**不要修改你的 Angular 副本。**
|
||||
私有的、定制版的 Angular 往往跟不上最新版本,这可能导致你忽略重要的安全修复与增强。反之,应该在社区共享你对 Angular 所做的改进并创建 Pull Request。
|
||||
|
||||
* **Avoid Angular APIs marked in the documentation as “_Security Risk_.”**
|
||||
For more information, see the [Trusting safe values](guide/security#bypass-security-apis) section of this page.
|
||||
|
||||
**避免使用本文档中带“[_安全风险_](guide/security#bypass-security-apis)”标记的Angular API。**
|
||||
**避免使用本文档中带“[_安全风险_](guide/security#bypass-security-apis)”标记的 Angular API。**
|
||||
要了解更多信息,请参阅本章的[信任那些安全的值](guide/security#bypass-security-apis)部分。
|
||||
|
||||
<h2 id='xss'>Preventing cross-site scripting (XSS)</h2>
|
||||
|
@ -66,7 +66,7 @@ particular, login data) or perform actions to impersonate the user. This is one
|
|||
common attacks on the web.
|
||||
|
||||
[跨站脚本(XSS)](https://en.wikipedia.org/wiki/Cross-site_scripting)允许攻击者将恶意代码注入到页面中。这些代码可以偷取用户数据
|
||||
(特别是它们的登录数据),还可以冒充用户执行操作。它是Web上最常见的攻击方式之一。
|
||||
(特别是它们的登录数据),还可以冒充用户执行操作。它是 Web 上最常见的攻击方式之一。
|
||||
|
||||
To block XSS attacks, you must prevent malicious code from entering the DOM (Document Object Model). For example, if
|
||||
attackers can trick you into inserting a `<script>` tag in the DOM, they can run arbitrary code on
|
||||
|
@ -74,21 +74,21 @@ your website. The attack isn't limited to `<script>` tags—many elements an
|
|||
DOM allow code execution, for example, `<img onerror="...">` and `<a href="javascript:...">`. If
|
||||
attacker-controlled data enters the DOM, expect security vulnerabilities.
|
||||
|
||||
为了防范XSS攻击,我们必须阻止恶意代码进入DOM。比如,如果某个攻击者能骗我们把`<script>`标签插入到DOM,就可以在我们的网站上运行任何代码。
|
||||
除了`<script>`,攻击者还可以使用很多DOM元素和属性来执行代码,比如`<img onerror="...">`、`<a href="javascript:...">`。
|
||||
如果攻击者所控制的数据混进了DOM,就会导致安全漏洞。
|
||||
为了防范 XSS 攻击,我们必须阻止恶意代码进入 DOM。比如,如果某个攻击者能骗我们把 `<script>` 标签插入到 DOM,就可以在我们的网站上运行任何代码。
|
||||
除了 `<script>`,攻击者还可以使用很多 DOM 元素和属性来执行代码,比如 `<img onerror="...">`、`<a href="javascript:...">`。
|
||||
如果攻击者所控制的数据混进了 DOM,就会导致安全漏洞。
|
||||
|
||||
### Angular’s cross-site scripting security model
|
||||
|
||||
### Angular的“跨站脚本安全模型”
|
||||
### Angular 的“跨站脚本安全模型”
|
||||
|
||||
To systematically block XSS bugs, Angular treats all values as untrusted by default. When a value
|
||||
is inserted into the DOM from a template, via property, attribute, style, class binding, or interpolation,
|
||||
Angular sanitizes and escapes untrusted values.
|
||||
|
||||
为了系统性的防范XSS问题,Angular默认把所有值都当做不可信任的。
|
||||
当值从模板中以属性(Property)、DOM元素属性(Attribte)、CSS类绑定或插值表达式等途径插入到DOM中的时候,
|
||||
Angular将对这些值进行无害化处理(Sanitize),对不可信的值进行编码。
|
||||
为了系统性的防范 XSS 问题,Angular 默认把所有值都当做不可信任的。
|
||||
当值从模板中以属性(Property)、DOM 元素属性(Attribte)、CSS 类绑定或插值表达式等途径插入到 DOM 中的时候,
|
||||
Angular 将对这些值进行无害化处理(Sanitize),对不可信的值进行编码。
|
||||
|
||||
_Angular templates are the same as executable code_: HTML, attributes, and binding expressions
|
||||
(but not the values bound) in templates are trusted to be safe. This means that applications must
|
||||
|
@ -97,7 +97,7 @@ template. Never generate template source code by concatenating user input and te
|
|||
To prevent these vulnerabilities, use
|
||||
the [offline template compiler](guide/security#offline-template-compiler), also known as _template injection_.
|
||||
|
||||
**Angular的模板同样是可执行的**:模板中的HTML、Attribute和绑定表达式(还没有绑定到值的时候)会被当做可信任的。
|
||||
**Angular 的模板同样是可执行的**:模板中的 HTML、Attribute 和绑定表达式(还没有绑定到值的时候)会被当做可信任的。
|
||||
这意味着应用必须防止把可能被攻击者控制的值直接编入模板的源码中。永远不要根据用户的输入和原始模板动态生成模板源码!
|
||||
使用[离线模板编译器](guide/security#offline-template-compiler)是防范这类“模板注入”漏洞的有效途径。
|
||||
|
||||
|
@ -109,35 +109,35 @@ _Sanitization_ is the inspection of an untrusted value, turning it into a value
|
|||
the DOM. In many cases, sanitization doesn't change a value at all. Sanitization depends on context:
|
||||
a value that's harmless in CSS is potentially dangerous in a URL.
|
||||
|
||||
无害化处理会审查不可信的值,并将它们转换成可以安全插入到DOM的形式。多数情况下,这些值并不会在处理过程中发生任何变化。
|
||||
无害化处理的方式取决于所在的环境:一个在CSS里面无害的值,可能在URL里很危险。
|
||||
无害化处理会审查不可信的值,并将它们转换成可以安全插入到 DOM 的形式。多数情况下,这些值并不会在处理过程中发生任何变化。
|
||||
无害化处理的方式取决于所在的环境:一个在 CSS 里面无害的值,可能在 URL 里很危险。
|
||||
|
||||
Angular defines the following security contexts:
|
||||
|
||||
Angular定义了四个安全环境 - HTML,样式,URL,和资源URL:
|
||||
Angular 定义了四个安全环境 - HTML,样式,URL,和资源 URL:
|
||||
|
||||
* **HTML** is used when interpreting a value as HTML, for example, when binding to `innerHtml`.
|
||||
|
||||
**HTML**:值需要被解释为HTML时使用,比如当绑定到`innerHTML`时。
|
||||
**HTML**:值需要被解释为 HTML 时使用,比如当绑定到 `innerHTML` 时。
|
||||
|
||||
* **Style** is used when binding CSS into the `style` property.
|
||||
|
||||
**样式**:值需要作为CSS绑定到`style`属性时使用。
|
||||
**样式**:值需要作为 CSS 绑定到 `style` 属性时使用。
|
||||
|
||||
* **URL** is used for URL properties, such as `<a href>`.
|
||||
|
||||
**URL**:值需要被用作URL属性时使用,比如`<a href>`。
|
||||
**URL**:值需要被用作 URL 属性时使用,比如 `<a href>`。
|
||||
|
||||
* **Resource URL** is a URL that will be loaded and executed as code, for example, in `<script src>`.
|
||||
|
||||
**资源URL**:值需要被当做代码而加载并执行时使用,比如`<script src>`中的URL。
|
||||
**资源 URL**:值需要被当做代码而加载并执行时使用,比如 `<script src>` 中的 URL。
|
||||
|
||||
Angular sanitizes untrusted values for HTML, styles, and URLs; sanitizing resource URLs isn't
|
||||
possible because they contain arbitrary code. In development mode, Angular prints a console warning
|
||||
when it has to change a value during sanitization.
|
||||
|
||||
Angular会对前三项中种不可信的值进行无害化处理。但Angular无法对第四种资源URL进行无害化,因为它们可能包含任何代码。在开发模式下,
|
||||
如果Angular在进行无害化处理时需要被迫改变一个值,它就会在控制台上输出一个警告。
|
||||
Angular 会对前三项中种不可信的值进行无害化处理。但 Angular 无法对第四种资源 URL 进行无害化,因为它们可能包含任何代码。在开发模式下,
|
||||
如果 Angular 在进行无害化处理时需要被迫改变一个值,它就会在控制台上输出一个警告。
|
||||
|
||||
### Sanitization example
|
||||
|
||||
|
@ -146,7 +146,7 @@ Angular会对前三项中种不可信的值进行无害化处理。但Angular无
|
|||
The following template binds the value of `htmlSnippet`, once by interpolating it into an element's
|
||||
content, and once by binding it to the `innerHTML` property of an element:
|
||||
|
||||
下面的例子绑定了`htmlSnippet`的值,一次把它放进插值表达式里,另一次把它绑定到元素的`innerHTML`属性上。
|
||||
下面的例子绑定了 `htmlSnippet` 的值,一次把它放进插值表达式里,另一次把它绑定到元素的 `innerHTML` 属性上。
|
||||
|
||||
<code-example path="security/src/app/inner-html-binding.component.html" title="src/app/inner-html-binding.component.html">
|
||||
|
||||
|
@ -155,14 +155,14 @@ content, and once by binding it to the `innerHTML` property of an element:
|
|||
Interpolated content is always escaped—the HTML isn't interpreted and the browser displays
|
||||
angle brackets in the element's text content.
|
||||
|
||||
插值表达式的内容总会被编码 - 其中的HTML不会被解释,所以浏览器会在元素的文本内容中显示尖括号。
|
||||
插值表达式的内容总会被编码 - 其中的 HTML 不会被解释,所以浏览器会在元素的文本内容中显示尖括号。
|
||||
|
||||
For the HTML to be interpreted, bind it to an HTML property such as `innerHTML`. But binding
|
||||
a value that an attacker might control into `innerHTML` normally causes an XSS
|
||||
vulnerability. For example, code contained in a `<script>` tag is executed:
|
||||
|
||||
如果希望这段HTML被正常解释,就必须绑定到一个HTML属性上,比如`innerHTML`。但是如果把一个可能被攻击者控制的值绑定到`innerHTML`就会导致XSS漏洞。
|
||||
比如,包含在`<script>`标签的代码就会被执行:
|
||||
如果希望这段 HTML 被正常解释,就必须绑定到一个 HTML 属性上,比如 `innerHTML`。但是如果把一个可能被攻击者控制的值绑定到 `innerHTML` 就会导致 XSS 漏洞。
|
||||
比如,包含在 `<script>` 标签的代码就会被执行:
|
||||
|
||||
<code-example path="security/src/app/inner-html-binding.component.ts" linenums="false" title="src/app/inner-html-binding.component.ts (class)" region="class">
|
||||
|
||||
|
@ -171,7 +171,7 @@ vulnerability. For example, code contained in a `<script>` tag is executed:
|
|||
Angular recognizes the value as unsafe and automatically sanitizes it, which removes the `<script>`
|
||||
tag but keeps safe content such as the text content of the `<script>` tag and the `<b>` element.
|
||||
|
||||
Angular认为这些值是不安全的,并自动进行无害化处理。它会移除`<script>`标签,但保留安全的内容,比如该片段中的文本内容或`<b>`元素。
|
||||
Angular 认为这些值是不安全的,并自动进行无害化处理。它会移除 `<script>` 标签,但保留安全的内容,比如该片段中的文本内容或 `<b>` 元素。
|
||||
|
||||
<figure>
|
||||
<img src='generated/images/guide/security/binding-inner-html.png' alt='A screenshot showing interpolated and bound HTML values'>
|
||||
|
@ -179,15 +179,15 @@ Angular认为这些值是不安全的,并自动进行无害化处理。它会
|
|||
|
||||
### Avoid direct use of the DOM APIs
|
||||
|
||||
### 避免直接使用DOM API
|
||||
### 避免直接使用 DOM API
|
||||
|
||||
The built-in browser DOM APIs don't automatically protect you from security vulnerabilities.
|
||||
For example, `document`, the node available through `ElementRef`, and many third-party APIs
|
||||
contain unsafe methods. Avoid directly interacting with the DOM and instead use Angular
|
||||
templates where possible.
|
||||
|
||||
浏览器内置的DOM API不会自动针对安全漏洞进行防护。比如,`document`(它可以通过`ElementRef`访问)以及其它第三方API都可能包含不安全的方法。
|
||||
要避免直接与DOM交互,只要可能,就尽量使用Angular模板。
|
||||
浏览器内置的 DOM API 不会自动针对安全漏洞进行防护。比如,`document`(它可以通过 `ElementRef` 访问)以及其它第三方 API 都可能包含不安全的方法。
|
||||
要避免直接与 DOM 交互,只要可能,就尽量使用 Angular 模板。
|
||||
|
||||
### Content security policy
|
||||
|
||||
|
@ -199,9 +199,9 @@ technique to prevent XSS. To enable CSP, configure your web server to return an
|
|||
[An Introduction to Content Security Policy](http://www.html5rocks.com/en/tutorials/security/content-security-policy/)
|
||||
on the HTML5Rocks website.
|
||||
|
||||
[内容安全策略(CSP)](https://developer.mozilla.org/en-)是用来防范XSS的纵深防御技术。
|
||||
要打开CSP,请配置你的Web服务器,让它返回合适的HTTP头`Content_Security_Policy`。
|
||||
要了解关于内容安全策略的更多信息,请参阅HTML5Rocks上的[内容安全策略简介](http://www.html5rocks.com/en/tutorials/security/content-security-policy/)
|
||||
[内容安全策略(CSP)](https://developer.mozilla.org/en-)是用来防范 XSS 的纵深防御技术。
|
||||
要打开 CSP,请配置你的 Web 服务器,让它返回合适的 HTTP 头 `Content_Security_Policy`。
|
||||
要了解关于内容安全策略的更多信息,请参阅 HTML5Rocks 上的[内容安全策略简介](http://www.html5rocks.com/en/tutorials/security/content-security-policy/)
|
||||
|
||||
{@a offline-template-compiler}
|
||||
|
||||
|
@ -217,12 +217,12 @@ For information about dynamically constructing forms in a safe way, see the
|
|||
[Dynamic Forms](guide/dynamic-form) guide page.
|
||||
|
||||
离线模板编译器阻止了一整套被称为“模板注入”的漏洞,并能显著增强应用程序的性能。尽量在产品发布时使用离线模板编译器,
|
||||
而不要动态生成模板(比如在代码中拼接字符串生成模板)。由于Angular会信任模板本身的代码,所以,动态生成的模板 —— 特别是包含用户数据的模板 —— 会绕过Angular自带的保护机制。
|
||||
而不要动态生成模板(比如在代码中拼接字符串生成模板)。由于 Angular 会信任模板本身的代码,所以,动态生成的模板 —— 特别是包含用户数据的模板 —— 会绕过 Angular 自带的保护机制。
|
||||
要了解如何用安全的方式动态创建表单,请参见[动态表单烹饪宝典](guide/dynamic-form)一章。
|
||||
|
||||
### Server-side XSS protection
|
||||
|
||||
### 服务器端XSS保护
|
||||
### 服务器端 XSS 保护
|
||||
|
||||
HTML constructed on the server is vulnerable to injection attacks. Injecting template code into an
|
||||
Angular application is the same as injecting executable code into the
|
||||
|
@ -231,8 +231,8 @@ use a templating language that automatically escapes values to prevent XSS vulne
|
|||
the server. Don't generate Angular templates on the server side using a templating language; doing this
|
||||
carries a high risk of introducing template-injection vulnerabilities.
|
||||
|
||||
服务器端构造的HTML很容易受到注入攻击。当需要在服务器端生成HTML时(比如Angular应用的初始页面),
|
||||
务必使用一个能够自动进行无害化处理以防范XSS漏洞的后端模板语言。不要在服务器端使用模板语言生成Angular模板,
|
||||
服务器端构造的 HTML 很容易受到注入攻击。当需要在服务器端生成 HTML 时(比如 Angular 应用的初始页面),
|
||||
务必使用一个能够自动进行无害化处理以防范 XSS 漏洞的后端模板语言。不要在服务器端使用模板语言生成 Angular 模板,
|
||||
这样会带来很高的“模板注入”风险。
|
||||
|
||||
<h2 id='bypass-security-apis'>Trusting safe values</h2>
|
||||
|
@ -246,14 +246,14 @@ sure it will always be secure. But *be careful*. If you trust a value that might
|
|||
are introducing a security vulnerability into your application. If in doubt, find a professional
|
||||
security reviewer.
|
||||
|
||||
有时候,应用程序确实需要包含可执行的代码,比如使用URL显示`<iframe>`,或者构造出有潜在危险的URL。
|
||||
为了防止在这种情况下被自动无害化,你可以告诉Angular:我已经审查了这个值,检查了它是怎么生成的,并确信它总是安全的。
|
||||
有时候,应用程序确实需要包含可执行的代码,比如使用 URL 显示 `<iframe>`,或者构造出有潜在危险的 URL。
|
||||
为了防止在这种情况下被自动无害化,你可以告诉 Angular:我已经审查了这个值,检查了它是怎么生成的,并确信它总是安全的。
|
||||
但是**千万要小心**!如果你信任了一个可能是恶意的值,就会在应用中引入一个安全漏洞。如果你有疑问,请找一个安全专家复查下。
|
||||
|
||||
To mark a value as trusted, inject `DomSanitizer` and call one of the
|
||||
following methods:
|
||||
|
||||
注入`DomSanitizer`服务,然后调用下面的方法之一,你就可以把一个值标记为可信任的。
|
||||
注入 `DomSanitizer` 服务,然后调用下面的方法之一,你就可以把一个值标记为可信任的。
|
||||
|
||||
* `bypassSecurityTrustHtml`
|
||||
|
||||
|
@ -269,7 +269,7 @@ Remember, whether a value is safe depends on context, so choose the right contex
|
|||
your intended use of the value. Imagine that the following template needs to bind a URL to a
|
||||
`javascript:alert(...)` call:
|
||||
|
||||
记住,一个值是否安全取决于它所在的环境,所以你要为这个值按预定的用法选择正确的环境。假设下面的模板需要把`javascript.alert(...)`方法绑定到URL。
|
||||
记住,一个值是否安全取决于它所在的环境,所以你要为这个值按预定的用法选择正确的环境。假设下面的模板需要把 `javascript.alert(...)` 方法绑定到 URL。
|
||||
|
||||
<code-example path="security/src/app/bypass-security.component.html" linenums="false" title="src/app/bypass-security.component.html (URL)" region="URL">
|
||||
|
||||
|
@ -279,7 +279,7 @@ Normally, Angular automatically sanitizes the URL, disables the dangerous code,
|
|||
in development mode, logs this action to the console. To prevent
|
||||
this, mark the URL value as a trusted URL using the `bypassSecurityTrustUrl` call:
|
||||
|
||||
通常,Angular会自动无害化这个URL并禁止危险的代码。为了防止这种行为,我们可以调用`bypassSecurityTrustUrl`把这个URL值标记为一个可信任的URL:
|
||||
通常,Angular 会自动无害化这个 URL 并禁止危险的代码。为了防止这种行为,我们可以调用 `bypassSecurityTrustUrl` 把这个 URL 值标记为一个可信任的 URL:
|
||||
|
||||
<code-example path="security/src/app/bypass-security.component.ts" linenums="false" title="src/app/bypass-security.component.ts (trust-url)" region="trust-url">
|
||||
|
||||
|
@ -296,9 +296,9 @@ context, because an untrusted source can, for example, smuggle in file downloads
|
|||
could execute. So call a method on the controller to construct a trusted video URL, which causes
|
||||
Angular to allow binding into `<iframe src>`:
|
||||
|
||||
如果需要把用户输入转换为一个可信任的值,我们可以很方便的在控制器方法中处理。下面的模板允许用户输入一个YouTube视频的ID,
|
||||
然后把相应的视频加载到`<iframe>`中。`<iframe src>`是一个“资源URL”的安全环境,因为不可信的源码可能作为文件下载到本地,被毫无防备的用户执行。
|
||||
所以我们要调用一个控制器方法来构造一个新的、可信任的视频URL,然后把它绑定到`<iframe src>`。
|
||||
如果需要把用户输入转换为一个可信任的值,我们可以很方便的在控制器方法中处理。下面的模板允许用户输入一个 YouTube 视频的 ID,
|
||||
然后把相应的视频加载到 `<iframe>` 中。`<iframe src>` 是一个“资源 URL”的安全环境,因为不可信的源码可能作为文件下载到本地,被毫无防备的用户执行。
|
||||
所以我们要调用一个控制器方法来构造一个新的、可信任的视频 URL,然后把它绑定到 `<iframe src>`。
|
||||
|
||||
<code-example path="security/src/app/bypass-security.component.html" linenums="false" title="src/app/bypass-security.component.html (iframe)" region="iframe">
|
||||
|
||||
|
@ -310,14 +310,14 @@ Angular to allow binding into `<iframe src>`:
|
|||
|
||||
<h2 id='http'>HTTP-level vulnerabilities</h2>
|
||||
|
||||
<h2 id='http'>HTTP级别的漏洞</h2>
|
||||
<h2 id='http'>HTTP 级别的漏洞</h2>
|
||||
|
||||
Angular has built-in support to help prevent two common HTTP vulnerabilities, cross-site request
|
||||
forgery (CSRF or XSRF) and cross-site script inclusion (XSSI). Both of these must be mitigated primarily
|
||||
on the server side, but Angular provides helpers to make integration on the client side easier.
|
||||
|
||||
Angular内置了一些支持来防范两个常见的HTTP漏洞:跨站请求伪造(XSRF)和跨站脚本包含(XSSI)。
|
||||
这两个漏洞主要在服务器端防范,但是Angular也自带了一些辅助特性,可以让客户端的集成变得更容易。
|
||||
Angular 内置了一些支持来防范两个常见的 HTTP 漏洞:跨站请求伪造(XSRF)和跨站脚本包含(XSSI)。
|
||||
这两个漏洞主要在服务器端防范,但是 Angular 也自带了一些辅助特性,可以让客户端的集成变得更容易。
|
||||
|
||||
<h3 id='xsrf'>Cross-site request forgery</h3>
|
||||
|
||||
|
@ -327,25 +327,25 @@ In a cross-site request forgery (CSRF or XSRF), an attacker tricks the user into
|
|||
a different web page (such as `evil.com`) with malignant code that secretly sends a malicious request
|
||||
to the application's web server (such as `example-bank.com`).
|
||||
|
||||
在跨站请求伪造(XSRF或CSFR)中,攻击者欺骗用户,让他们访问一个假冒页面(例如`evil.com`),
|
||||
该页面带有恶意代码,秘密的向你的应用程序服务器发送恶意请求(例如`example-bank.com`)。
|
||||
在跨站请求伪造(XSRF 或 CSFR)中,攻击者欺骗用户,让他们访问一个假冒页面(例如 `evil.com`),
|
||||
该页面带有恶意代码,秘密的向你的应用程序服务器发送恶意请求(例如 `example-bank.com`)。
|
||||
|
||||
Assume the user is logged into the application at `example-bank.com`.
|
||||
The user opens an email and clicks a link to `evil.com`, which opens in a new tab.
|
||||
|
||||
假设用户已经在`example-bank.com`登录。用户打开一个邮件,点击里面的链接,在新页面中打开`evil.com`。
|
||||
假设用户已经在 `example-bank.com` 登录。用户打开一个邮件,点击里面的链接,在新页面中打开 `evil.com`。
|
||||
|
||||
The `evil.com` page immediately sends a malicious request to `example-bank.com`.
|
||||
Perhaps it's a request to transfer money from the user's account to the attacker's account.
|
||||
The browser automatically sends the `example-bank.com` cookies (including the authentication cookie) with this request.
|
||||
|
||||
该`evil.com`页面立刻发送恶意请求到`example-bank.com`。这个请求可能是从用户账户转账到攻击者的账户。
|
||||
与该请求一起,浏览器自动发出`example-bank.com`的cookie。
|
||||
该 `evil.com` 页面立刻发送恶意请求到 `example-bank.com`。这个请求可能是从用户账户转账到攻击者的账户。
|
||||
与该请求一起,浏览器自动发出 `example-bank.com` 的 cookie。
|
||||
|
||||
If the `example-bank.com` server lacks XSRF protection, it can't tell the difference between a legitimate
|
||||
request from the application and the forged request from `evil.com`.
|
||||
|
||||
如果`example-bank.com`服务器缺乏XSRF保护,就无法辨识请求是从应用程序发来的合法请求还是从`evil.com`来的假请求。
|
||||
如果 `example-bank.com` 服务器缺乏 XSRF 保护,就无法辨识请求是从应用程序发来的合法请求还是从 `evil.com` 来的假请求。
|
||||
|
||||
To prevent this, the application must ensure that a user request originates from the real
|
||||
application, not from a different site.
|
||||
|
@ -359,20 +359,20 @@ generated authentication token in a cookie.
|
|||
The client code reads the cookie and adds a custom request header with the token in all subsequent requests.
|
||||
The server compares the received cookie value to the request header value and rejects the request if the values are missing or don't match.
|
||||
|
||||
常见的反XSRF技术是服务器随机生成一个用户认证令牌到cookie中。
|
||||
客户端代码获取这个cookie,并用它为接下来所有的请求添加自定义请求页头。
|
||||
服务器比较收到的cookie值与请求页头的值,如果它们不匹配,便拒绝请求。
|
||||
常见的反 XSRF 技术是服务器随机生成一个用户认证令牌到 cookie 中。
|
||||
客户端代码获取这个 cookie,并用它为接下来所有的请求添加自定义请求页头。
|
||||
服务器比较收到的 cookie 值与请求页头的值,如果它们不匹配,便拒绝请求。
|
||||
|
||||
This technique is effective because all browsers implement the _same origin policy_. Only code from the website
|
||||
on which cookies are set can read the cookies from that site and set custom headers on requests to that site.
|
||||
That means only your application can read this cookie token and set the custom header. The malicious code on `evil.com` can't.
|
||||
|
||||
这个技术之所以有效,是因为所有浏览器都实现了_同源策略_。只有设置cookie的网站的代码可以访问该站的cookie,并为该站的请求设置自定义页头。
|
||||
这就是说,只有你的应用程序可以获取这个cookie令牌和设置自定义页头。`evil.com`的恶意代码不能。
|
||||
这个技术之所以有效,是因为所有浏览器都实现了_同源策略_。只有设置 cookie 的网站的代码可以访问该站的 cookie,并为该站的请求设置自定义页头。
|
||||
这就是说,只有你的应用程序可以获取这个 cookie 令牌和设置自定义页头。`evil.com` 的恶意代码不能。
|
||||
|
||||
Angular's `HttpClient` has built-in support for the client-side half of this technique. Read about it more in the [HttpClient guide](/guide/http).
|
||||
|
||||
Angular 的 `HttpClient` 对这项技术的客户端部分提供了内置的支持要了解更多信息,参见 [HttpClient部分](/guide/http)。
|
||||
Angular 的 `HttpClient` 对这项技术的客户端部分提供了内置的支持要了解更多信息,参见 [HttpClient 部分](/guide/http)。
|
||||
|
||||
For information about CSRF at the Open Web Application Security Project (OWASP), see
|
||||
<a href="https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29">Cross-Site Request Forgery (CSRF)</a> and
|
||||
|
@ -380,14 +380,14 @@ For information about CSRF at the Open Web Application Security Project (OWASP),
|
|||
The Stanford University paper
|
||||
<a href="https://seclab.stanford.edu/websec/csrf/csrf.pdf">Robust Defenses for Cross-Site Request Forgery</a> is a rich source of detail.
|
||||
|
||||
到开放式Web应用程序安全项目(OWASP)的[这里](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29)
|
||||
到开放式 Web 应用程序安全项目(OWASP)的[这里](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29)
|
||||
和[这里](https://www.owasp.org/index.php/CSRF_Prevention_Cheat_Sheet)学习更多关于跨站请求伪造(XSRF)的知识。
|
||||
这个[斯坦福大学论文](https://seclab.stanford.edu/websec/csrf/csrf.pdf)有详尽的细节。
|
||||
|
||||
See also Dave Smith's easy-to-understand
|
||||
<a href="https://www.youtube.com/watch?v=9inczw6qtpY" title="Cross Site Request Funkery Securing Your Angular Apps From Evil Doers">talk on XSRF at AngularConnect 2016</a>.
|
||||
|
||||
参见Dave Smith在<a href="https://www.youtube.com/watch?v=9inczw6qtpY" target="_blank" title="Cross Site Request Funkery Securing Your Angular Apps From Evil Doers">AngularConnect 2016关于XSRF的演讲</a>。
|
||||
参见 Dave Smith 在<a href="https://www.youtube.com/watch?v=9inczw6qtpY" target="_blank" title="Cross Site Request Funkery Securing Your Angular Apps From Evil Doers">AngularConnect 2016 关于 XSRF 的演讲</a>。
|
||||
|
||||
<h3 id='xssi'>Cross-site script inclusion (XSSI)</h3>
|
||||
|
||||
|
@ -397,29 +397,29 @@ Cross-site script inclusion, also known as JSON vulnerability, can allow an atta
|
|||
read data from a JSON API. The attack works on older browsers by overriding native JavaScript
|
||||
object constructors, and then including an API URL using a `<script>` tag.
|
||||
|
||||
跨站脚本包含,也被称为Json漏洞,它可以允许一个攻击者的网站从JSON API读取数据。这种攻击发生在老的浏览器上,
|
||||
它重写原生JavaScript对象的构造函数,然后使用`<script>`标签包含一个API的URL。
|
||||
跨站脚本包含,也被称为 Json 漏洞,它可以允许一个攻击者的网站从 JSON API 读取数据。这种攻击发生在老的浏览器上,
|
||||
它重写原生 JavaScript 对象的构造函数,然后使用 `<script>` 标签包含一个 API 的 URL。
|
||||
|
||||
This attack is only successful if the returned JSON is executable as JavaScript. Servers can
|
||||
prevent an attack by prefixing all JSON responses to make them non-executable, by convention, using the
|
||||
well-known string `")]}',\n"`.
|
||||
|
||||
只有在返回的JSON能像JavaScript一样可以被执行时,这种攻击才会生效。所以服务端会约定给所有JSON响应体加上前缀`")]}',\n"`,来把它们标记为不可执行的,
|
||||
只有在返回的 JSON 能像 JavaScript 一样可以被执行时,这种攻击才会生效。所以服务端会约定给所有 JSON 响应体加上前缀 `")]}',\n"`,来把它们标记为不可执行的,
|
||||
以防范这种攻击。
|
||||
|
||||
Angular's `HttpClient` library recognizes this convention and automatically strips the string
|
||||
`")]}',\n"` from all responses before further parsing.
|
||||
|
||||
Angular的`Http`库会识别这种约定,并在进一步解析之前,自动把字符串`")]}',\n"`从所有响应中去掉。
|
||||
Angular 的 `Http` 库会识别这种约定,并在进一步解析之前,自动把字符串 `")]}',\n"` 从所有响应中去掉。
|
||||
|
||||
For more information, see the XSSI section of this [Google web security blog
|
||||
post](https://security.googleblog.com/2011/05/website-security-for-webmasters.html).
|
||||
|
||||
要学习更多这方面的知识,请参见[谷歌Web安全博客文章](https://security.googleblog.com/2011/05/website-security-for-webmasters.html)的XSSI小节。
|
||||
要学习更多这方面的知识,请参见[谷歌 Web 安全博客文章](https://security.googleblog.com/2011/05/website-security-for-webmasters.html)的 XSSI 小节。
|
||||
|
||||
<h2 id='code-review'>Auditing Angular applications</h2>
|
||||
|
||||
<h2 id='code-review'>审计Angular应用程序</h2>
|
||||
<h2 id='code-review'>审计 Angular 应用程序</h2>
|
||||
|
||||
Angular applications must follow the same security principles as regular web applications, and
|
||||
must be audited as such. Angular-specific APIs that should be audited in a security review,
|
||||
|
@ -427,5 +427,5 @@ such as the [_bypassSecurityTrust_](guide/security#bypass-security-apis) methods
|
|||
as security sensitive.
|
||||
|
||||
|
||||
Angular应用应该遵循和常规Web应用一样的安全原则并按照这些原则进行审计。Angular中某些应该在安全评审中被审计的API(
|
||||
Angular 应用应该遵循和常规 Web 应用一样的安全原则并按照这些原则进行审计。Angular 中某些应该在安全评审中被审计的 API(
|
||||
比如[_bypassSecurityTrust_](guide/security#bypass-security-apis) API)都在文档中被明确标记为安全性敏感的。
|
||||
|
|
|
@ -19,7 +19,7 @@ See the <live-example name="set-document-title"></live-example>.
|
|||
|
||||
The obvious approach is to bind a property of the component to the HTML `<title>` like this:
|
||||
|
||||
显而易见的方法是把组件的属性绑定到HTML的`<title>`标签上,像这样:
|
||||
显而易见的方法是把组件的属性绑定到 HTML 的 `<title>` 标签上,像这样:
|
||||
|
||||
<code-example format=''>
|
||||
|
||||
|
@ -31,12 +31,12 @@ Sorry but that won't work.
|
|||
The root component of the application is an element contained within the `<body>` tag.
|
||||
The HTML `<title>` is in the document `<head>`, outside the body, making it inaccessible to Angular data binding.
|
||||
|
||||
抱歉,这样不行。我们应用程序的根组件是一个包含在`<body>`标签里的元素。该HTML的`<title>`在文档的`<head>`元素里,在`<body>`之外,Angular的数据绑定无法访问到它。
|
||||
抱歉,这样不行。我们应用程序的根组件是一个包含在 `<body>` 标签里的元素。该 HTML 的 `<title>` 在文档的 `<head>` 元素里,在 `<body>` 之外,Angular 的数据绑定无法访问到它。
|
||||
|
||||
You could grab the browser `document` object and set the title manually.
|
||||
That's dirty and undermines your chances of running the app outside of a browser someday.
|
||||
|
||||
可以从浏览器获得`document`对象,并且手动设置标题。但是这样看起来很脏,而且将无法在浏览器之外运行应用程序。
|
||||
可以从浏览器获得 `document` 对象,并且手动设置标题。但是这样看起来很脏,而且将无法在浏览器之外运行应用程序。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
|
@ -45,9 +45,9 @@ That's dirty and undermines your chances of running the app outside of a browser
|
|||
inside a Web Worker to improve your app's responsiveness by using multiple threads. And it
|
||||
means that you could run your app inside Electron.js or Windows Universal to deliver it to the desktop.
|
||||
|
||||
在浏览器外运行应用程序意味着:利用服务器端预先渲染,为应用程序实现几乎实时的首次渲染,同时还能支持SEO(搜索引擎优化)。
|
||||
意味着你可以在一个Web Worker中运行你的应用程序,通过多线程技术增强应用程序的响应性。
|
||||
还意味着你可以在Electron.js或者Windows Universal里面运行,发布到桌面环境。
|
||||
在浏览器外运行应用程序意味着:利用服务器端预先渲染,为应用程序实现几乎实时的首次渲染,同时还能支持 SEO(搜索引擎优化)。
|
||||
意味着你可以在一个 Web Worker 中运行你的应用程序,通过多线程技术增强应用程序的响应性。
|
||||
还意味着你可以在 Electron.js 或者 Windows Universal 里面运行,发布到桌面环境。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -59,26 +59,26 @@ Fortunately, Angular bridges the gap by providing a `Title` service as part of t
|
|||
The [Title](api/platform-browser/Title) service is a simple class that provides an API
|
||||
for getting and setting the current HTML document title:
|
||||
|
||||
幸运的是,Angular在*浏览器平台*的包中,提供了一个`Title`服务,弥补了这种差异。
|
||||
[Title](api/platform-browser/Title)服务是一个简单的类,提供了一个API,用来获取和设置当前HTML文档的标题。
|
||||
幸运的是,Angular 在*浏览器平台*的包中,提供了一个 `Title` 服务,弥补了这种差异。
|
||||
[Title](api/platform-browser/Title)服务是一个简单的类,提供了一个 API,用来获取和设置当前 HTML 文档的标题。
|
||||
|
||||
* `getTitle() : string`—Gets the title of the current HTML document.
|
||||
|
||||
`getTitle(): string` —— 获取当前HTML文档的标题。
|
||||
`getTitle(): string` —— 获取当前 HTML 文档的标题。
|
||||
|
||||
* `setTitle( newTitle : string )`—Sets the title of the current HTML document.
|
||||
|
||||
`setTitle( newTitle: string)` —— 设置当前HTML文档的标题。
|
||||
`setTitle( newTitle: string)` —— 设置当前 HTML 文档的标题。
|
||||
|
||||
You can inject the `Title` service into the root `AppComponent` and expose a bindable `setTitle` method that calls it:
|
||||
|
||||
我们来把`Title`服务注入到根组件`AppComponent`,并暴露出可供绑定的`setTitle`方法让别人来调用该服务:
|
||||
我们来把 `Title` 服务注入到根组件 `AppComponent`,并暴露出可供绑定的 `setTitle` 方法让别人来调用该服务:
|
||||
|
||||
<code-example path="set-document-title/src/app/app.component.ts" region="class" title="src/app/app.component.ts (class)" linenums="false"></code-example>
|
||||
|
||||
Bind that method to three anchor tags and voilà!
|
||||
|
||||
我们把这个方法绑定到三个A标签,瞧瞧!
|
||||
我们把这个方法绑定到三个 A 标签,瞧瞧!
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/set-document-title/set-title-anim.gif" alt="Set title">
|
||||
|
@ -102,12 +102,12 @@ Here's the complete solution:
|
|||
|
||||
Generally you want to provide application-wide services in the root application component, `AppComponent`.
|
||||
|
||||
我们通常会推荐在应用程序的根组件`AppComponent`中提供应用程序级的服务。
|
||||
我们通常会推荐在应用程序的根组件 `AppComponent` 中提供应用程序级的服务。
|
||||
|
||||
This cookbook recommends registering the title service during bootstrapping,
|
||||
a location you reserve for configuring the runtime Angular environment.
|
||||
|
||||
但这里,我们推荐在引导过程中注册这个Title服务,这个位置是为设置Angular运行环境而保留的。
|
||||
但这里,我们推荐在引导过程中注册这个 Title 服务,这个位置是为设置 Angular 运行环境而保留的。
|
||||
|
||||
That's exactly what you're doing.
|
||||
The `Title` service is part of the Angular *browser platform*.
|
||||
|
@ -117,4 +117,4 @@ the concept of a "document title" for that specific platform.
|
|||
Ideally, the application itself neither knows nor cares about the runtime environment.
|
||||
|
||||
|
||||
我们的做法正是如此。这里的`Title`服务是Angular*浏览器平台*的一部分。如果在其它平台上引导应用程序,就得提供另一个专为那个平台准备的`Title`服务。
|
||||
我们的做法正是如此。这里的 `Title` 服务是 Angular*浏览器平台*的一部分。如果在其它平台上引导应用程序,就得提供另一个专为那个平台准备的 `Title` 服务。
|
||||
|
|
|
@ -76,7 +76,7 @@ If you do, this page can help you understand their purpose.
|
|||
and the <live-example name="setup" stackblitz="quickstart-specs">unit test</live-example>
|
||||
as _live examples_.
|
||||
|
||||
在live example中试试<live-example name="setup">范例程序</live-example>和<live-example name="setup" stackblitz="quickstart-specs">单元测试</live-example>
|
||||
在 live example 中试试<live-example name="setup">范例程序</live-example>和<live-example name="setup" stackblitz="quickstart-specs">单元测试</live-example>
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -203,11 +203,11 @@ If you do, this page can help you understand their purpose.
|
|||
|
||||
应用的宿主页面。
|
||||
它以特定的顺序加载一些基本脚本。
|
||||
然后它启动应用,将根`AppComponent`放置到自定义`<my-app>`标签里。
|
||||
然后它启动应用,将根 `AppComponent` 放置到自定义 `<my-app>` 标签里。
|
||||
|
||||
The same `index.html` satisfies all documentation application samples.
|
||||
|
||||
同一个 `index.html`满足所有文档应用例子。
|
||||
同一个 `index.html` 满足所有文档应用例子。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -226,7 +226,7 @@ If you do, this page can help you understand their purpose.
|
|||
Configuration for the <a href="https://karma-runner.github.io/1.0/index.html" title="Karma unit test runner">karma</a>
|
||||
test runner described in the [Testing](guide/testing) guide.
|
||||
|
||||
在[测试](guide/testing)指南中提到的 <a href="https://karma-runner.github.io/1.0/index.html" target="_blank" title="Karma测试运行器">karma</a> 测试运行器的配置。
|
||||
在[测试](guide/testing)指南中提到的 <a href="https://karma-runner.github.io/1.0/index.html" target="_blank" title="Karma 测试运行器">karma</a> 测试运行器的配置。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -245,7 +245,7 @@ If you do, this page can help you understand their purpose.
|
|||
Script to run <a href="https://karma-runner.github.io/1.0/index.html" title="Karma unit test runner">karma</a>
|
||||
with SystemJS as described in the [Testing](guide/testing) guide.
|
||||
|
||||
在[测试](guide/testing)指南中提到的 <a href="https://karma-runner.github.io/1.0/index.html" target="_blank" title="Karma测试运行器">karma</a> 测试运行器的脚本。
|
||||
在[测试](guide/testing)指南中提到的 <a href="https://karma-runner.github.io/1.0/index.html" target="_blank" title="Karma 测试运行器">karma</a> 测试运行器的脚本。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -267,9 +267,9 @@ If you do, this page can help you understand their purpose.
|
|||
[_Deleting non-essential files_](guide/setup#non-essential "Setup: Deleting non-essential files") section.
|
||||
*Do this only in the beginning to avoid accidentally deleting your own tests and git setup!*
|
||||
|
||||
这个列表中的文件在清理时可以删除,它是原始的“快速上手”种子工程中的测试和git维护文件。
|
||||
这个列表中的文件在清理时可以删除,它是原始的“快速上手”种子工程中的测试和 git 维护文件。
|
||||
步骤参见可选的[删除非必要文件](guide/setup#non-essential "Setup: Deleting non-essential files")部分。
|
||||
*只在最初做这件事,以免不小心删除了你自己的测试文件和git配置!*
|
||||
*只在最初做这件事,以免不小心删除了你自己的测试文件和 git 配置!*
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -305,14 +305,14 @@ If you do, this page can help you understand their purpose.
|
|||
|
||||
Identifies `npm `package dependencies for the project.
|
||||
|
||||
为项目指定`npm`依赖包。
|
||||
为项目指定 `npm` 依赖包。
|
||||
|
||||
Contains command scripts for running the application,
|
||||
running tests, and more. Enter `npm run` for a listing.
|
||||
<a href="https://github.com/angular/quickstart/blob/master/README.md#npm-scripts"
|
||||
title="npm scripts for Angular documentation samples">Read more</a> about them.
|
||||
|
||||
包含了一些命令脚本,用来运行应用、运行测试与其他。输入`npm run`来查看命令列表。
|
||||
包含了一些命令脚本,用来运行应用、运行测试与其他。输入 `npm run` 来查看命令列表。
|
||||
到<a href="https://github.com/angular/quickstart/blob/master/README.md#npm-scripts"
|
||||
target="_blank" title="Angular 文档例子的 npm 脚本">这里</a>阅读更多关于它们的说明。
|
||||
|
||||
|
@ -372,7 +372,7 @@ If you do, this page can help you understand their purpose.
|
|||
|
||||
Global styles for the application. Initialized with an `<h1>` style for the QuickStart demo.
|
||||
|
||||
应用的全局样式。初始化后,有个为《快速上手》演示准备的`<h1>`样式。
|
||||
应用的全局样式。初始化后,有个为《快速上手》演示准备的 `<h1>` 样式。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -391,7 +391,7 @@ If you do, this page can help you understand their purpose.
|
|||
Tells the **SystemJS** module loader where to find modules
|
||||
referenced in JavaScript `import` statements. For example:
|
||||
|
||||
为 **SystemJS** 模块加载器指定去哪儿查找在 JavaScript 的`import`语句中引用的模块。例如:
|
||||
为 **SystemJS** 模块加载器指定去哪儿查找在 JavaScript 的 `import` 语句中引用的模块。例如:
|
||||
|
||||
<code-example language="ts">
|
||||
|
||||
|
@ -422,7 +422,7 @@ If you do, this page can help you understand their purpose.
|
|||
without changing the original `system.config.js`.
|
||||
|
||||
可选的额外 SystemJS 配置。
|
||||
是添加 SystemJS 映射的途径,例如在无需修改原始`systemjs.config.js`的情况下为应用映射*封装桶*。
|
||||
是添加 SystemJS 映射的途径,例如在无需修改原始 `systemjs.config.js` 的情况下为应用映射*封装桶*。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -460,7 +460,7 @@ If you do, this page can help you understand their purpose.
|
|||
The `npm` installed TypeScript linter inspects your TypeScript code
|
||||
and complains when you violate one of its rules.
|
||||
|
||||
利用`npm`安装的 TypeScript 语法检查器 (linter) 检测 TypeScript 代码并在你违反它的规则时提示你。
|
||||
利用 `npm` 安装的 TypeScript 语法检查器 (linter) 检测 TypeScript 代码并在你违反它的规则时提示你。
|
||||
|
||||
This file defines linting rules favored by the
|
||||
[Angular style guide](guide/styleguide) and by the authors of the documentation.
|
||||
|
|
|
@ -19,7 +19,7 @@ maintained [on github](https://github.com/angular/quickstart "Install the github
|
|||
|
||||
Make sure you have [node and npm installed](guide/setup#install-prerequisites "What if you don't have node and npm?").
|
||||
|
||||
确定你已经安装了 [node和npm](guide/setup#install-prerequisites "如果你没有node和npm?")。
|
||||
确定你已经安装了 [node 和 npm](guide/setup#install-prerequisites "如果你没有 node 和 npm?")。
|
||||
|
||||
{@a clone}
|
||||
|
||||
|
@ -44,7 +44,7 @@ Perform the _clone-to-launch_ steps with these terminal commands.
|
|||
|
||||
`npm start` fails in _Bash for Windows_ in versions earlier than the Creator's Update (April 2017).
|
||||
|
||||
在*Bash for Windows*中`npm start`可能会失败,因为到2017-01为止它还不支持访问网络上的服务器。
|
||||
在*Bash for Windows*中 `npm start` 可能会失败,因为到 2017-01 为止它还不支持访问网络上的服务器。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -72,7 +72,7 @@ and unzip it into your project folder. Then perform the remaining steps with the
|
|||
|
||||
`npm start` fails in _Bash for Windows_ in versions earlier than the Creator's Update (April 2017).
|
||||
|
||||
在*Bash for Windows*中`npm start`可能会失败,因为到2017-01为止它还不支持访问网络上的服务器。
|
||||
在*Bash for Windows*中 `npm start` 可能会失败,因为到 2017-01 为止它还不支持访问网络上的服务器。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -86,13 +86,13 @@ You can quickly delete the _non-essential_ files that concern testing and QuickS
|
|||
(***including all git-related artifacts*** such as the `.git` folder and `.gitignore`!).
|
||||
|
||||
你可以快速删除一些涉及到测试和维护快速开始版本库的 *非必需* 文件
|
||||
(***包括所有git相关的文件***如 `.git` 文件夹和 `.gitignore`!)。
|
||||
(***包括所有 git 相关的文件***如 `.git` 文件夹和 `.gitignore`!)。
|
||||
|
||||
<div class="alert is-important">
|
||||
|
||||
Do this only in the beginning to avoid accidentally deleting your own tests and git setup!
|
||||
|
||||
请只在开始时执行此删除操作,以防你自己的测试和git文件被意外删除!
|
||||
请只在开始时执行此删除操作,以防你自己的测试和 git 文件被意外删除!
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -206,19 +206,19 @@ Each file has a distinct purpose and evolves independently as the application gr
|
|||
Files outside `src/` concern building, deploying, and testing your app.
|
||||
They include configuration files and external dependencies.
|
||||
|
||||
`src/` 目录之外的文件为构建、部署和测试app相关的文件,他们只包括配置文件和外部依赖。
|
||||
`src/` 目录之外的文件为构建、部署和测试 app 相关的文件,他们只包括配置文件和外部依赖。
|
||||
|
||||
Files inside `src/` "belong" to your app.
|
||||
Add new Typescript, HTML and CSS files inside the `src/` directory, most of them inside `src/app`,
|
||||
unless told to do otherwise.
|
||||
|
||||
`src/` 目录下的文件才“属于”你的app。
|
||||
除非明确指出,否则教程中添加的 TypeScript,HTML和CSS文件都在`src/`目录下,
|
||||
大多数在`src/app`目录中。
|
||||
`src/` 目录下的文件才“属于”你的 app。
|
||||
除非明确指出,否则教程中添加的 TypeScript,HTML 和 CSS 文件都在 `src/` 目录下,
|
||||
大多数在 `src/app` 目录中。
|
||||
|
||||
The following are all in `src/`
|
||||
|
||||
`src/`目录文件详情如下:
|
||||
`src/` 目录文件详情如下:
|
||||
|
||||
<style>
|
||||
td, th {vertical-align: top}
|
||||
|
@ -268,7 +268,7 @@ The following are all in `src/`
|
|||
It is the **root** component of what will become a tree of nested components
|
||||
as the application evolves.
|
||||
|
||||
定义与《快速上手》游乐场同样的`AppComponent`。
|
||||
定义与《快速上手》游乐场同样的 `AppComponent`。
|
||||
它是**根**组件,随着应用的演变,它将变成一颗嵌套组件树。
|
||||
|
||||
</td>
|
||||
|
@ -289,8 +289,8 @@ The following are all in `src/`
|
|||
Right now it declares only the `AppComponent`.
|
||||
Soon there will be more components to declare.
|
||||
|
||||
定义`AppModule`,[根模块](guide/bootstrapping "AppModule: 根模块")为 Angular 描述如何组装应用。
|
||||
目前,它只声明了`AppComponent`。
|
||||
定义 `AppModule`,[根模块](guide/bootstrapping "AppModule: 根模块")为 Angular 描述如何组装应用。
|
||||
目前,它只声明了 `AppComponent`。
|
||||
不久,它将声明更多组件。
|
||||
|
||||
</td>
|
||||
|
@ -362,7 +362,7 @@ Get them now</a> if they're not already installed on your machine.
|
|||
by running the commands `node -v` and `npm -v` in a terminal/console window.
|
||||
Older versions produce errors.
|
||||
|
||||
在终端/控制器窗口运行命令`node -v`和`npm -v`,来**确认你运行的 node 是`v4.x.x`或更高,npm 为`3.x.x`或更高。**
|
||||
在终端/控制器窗口运行命令 `node -v` 和 `npm -v`,来**确认你运行的 node 是 `v4.x.x` 或更高,npm 为 `3.x.x` 或更高。**
|
||||
老版本会产生错误。
|
||||
|
||||
We recommend [nvm](https://github.com/creationix/nvm) for managing multiple versions of node and npm.
|
||||
|
@ -393,8 +393,8 @@ It creates the equivalent of `app.module.ts` and `main.ts` internally _for the p
|
|||
so the reader can discover Angular without distraction.
|
||||
The other samples are based on the QuickStart seed.
|
||||
|
||||
[快速上手](guide/quickstart "Angular 快速起步游乐场")仅仅展示了`AppComponent`文件。
|
||||
它在内部创建了只为*游乐场*而准备的等价`app.module.ts`和`main.ts`。
|
||||
[快速上手](guide/quickstart "Angular 快速起步游乐场")仅仅展示了 `AppComponent` 文件。
|
||||
它在内部创建了只为*游乐场*而准备的等价 `app.module.ts` 和 `main.ts`。
|
||||
所以读者可以在零干扰的情况下探索 Angular。
|
||||
其他例子是基于 《快速上手》种子的。
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ Note the following:
|
|||
|
||||
* It re-exports the `CommonModule` and `FormsModule`.
|
||||
|
||||
它重新导出了`CommonModule`和`FormsModule`
|
||||
它重新导出了 `CommonModule` 和 `FormsModule`
|
||||
|
||||
By re-exporting `CommonModule` and `FormsModule`, any other module that imports this
|
||||
`SharedModule`, gets access to directives like `NgIf` and `NgFor` from `CommonModule`
|
||||
|
|
|
@ -120,7 +120,7 @@ Here's `forRoot()` that takes a `UserServiceConfig` object:
|
|||
|
||||
Lastly, call it within the `imports` list of the `AppModule`.
|
||||
|
||||
最后,我们在`AppModule`的`imports`*列表*中调用它。
|
||||
最后,我们在 `AppModule` 的 `imports`*列表*中调用它。
|
||||
|
||||
<code-example path="ngmodules/src/app/app.module.ts" region="import-for-root" title="src/app/app.module.ts (imports)" linenums="false">
|
||||
|
||||
|
@ -162,8 +162,8 @@ The injector returns `null`, the `parentModule` parameter is null,
|
|||
and the constructor concludes uneventfully.
|
||||
|
||||
默认情况下,当注入器找不到想找的提供商时,会抛出一个错误。
|
||||
但`@Optional`装饰器表示找不到该服务也无所谓。
|
||||
于是注入器会返回`null`,`parentModule`参数也就被赋成了空值,而构造函数没有任何异常。
|
||||
但 `@Optional` 装饰器表示找不到该服务也无所谓。
|
||||
于是注入器会返回 `null`,`parentModule` 参数也就被赋成了空值,而构造函数没有任何异常。
|
||||
|
||||
It's a different story if you improperly import `CoreModule` into a lazy-loaded module such as `CustomersModule`.
|
||||
|
||||
|
@ -174,9 +174,9 @@ Of course it finds the instance imported by the root `AppModule`.
|
|||
Now `parentModule` exists and the constructor throws the error.
|
||||
|
||||
Angular 创建一个惰性加载模块,它具有自己的注入器,它是根注入器的*子注入器*。
|
||||
`@SkipSelf`让 Angular 在其父注入器中查找`CoreModule`,这次,它的父注入器却是根注入器了(而上次父注入器是空)。
|
||||
当然,这次它找到了由根模块`AppModule`导入的实例。
|
||||
该构造函数检测到存在`parentModule`,于是抛出一个错误。
|
||||
`@SkipSelf` 让 Angular 在其父注入器中查找 `CoreModule`,这次,它的父注入器却是根注入器了(而上次父注入器是空)。
|
||||
当然,这次它找到了由根模块 `AppModule` 导入的实例。
|
||||
该构造函数检测到存在 `parentModule`,于是抛出一个错误。
|
||||
|
||||
Here are the two files in their entirety for reference:
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
This guide looks at how Angular manipulates the DOM with **structural directives** and
|
||||
how you can write your own structural directives to do the same thing.
|
||||
|
||||
在本章中,我们将看看Angular如何用*结构型指令*操纵DOM树,以及我们该如何写自己的结构型指令来完成同样的任务。
|
||||
在本章中,我们将看看 Angular 如何用*结构型指令*操纵 DOM 树,以及我们该如何写自己的结构型指令来完成同样的任务。
|
||||
|
||||
Try the <live-example></live-example>.
|
||||
|
||||
|
@ -27,8 +27,8 @@ Structural directives are responsible for HTML layout.
|
|||
They shape or reshape the DOM's _structure_, typically by adding, removing, or manipulating
|
||||
elements.
|
||||
|
||||
结构型指令的职责是HTML布局。
|
||||
它们塑造或重塑DOM的结构,比如添加、移除或维护这些元素。
|
||||
结构型指令的职责是 HTML 布局。
|
||||
它们塑造或重塑 DOM 的结构,比如添加、移除或维护这些元素。
|
||||
|
||||
As with other directives, you apply a structural directive to a _host element_.
|
||||
The directive then does whatever it's supposed to do with that host element and its descendants.
|
||||
|
@ -48,7 +48,7 @@ An asterisk (*) precedes the directive attribute name as in this example.
|
|||
|
||||
No brackets. No parentheses. Just `*ngIf` set to a string.
|
||||
|
||||
没有方括号,没有圆括号,只是把`*ngIf`设置为一个字符串。
|
||||
没有方括号,没有圆括号,只是把 `*ngIf` 设置为一个字符串。
|
||||
|
||||
You'll learn in this guide that the [asterisk (*) is a convenience notation](guide/structural-directives#asterisk)
|
||||
and the string is a [_microsyntax_](guide/structural-directives#microsyntax) rather than the usual
|
||||
|
@ -58,7 +58,7 @@ host element and its descendents.
|
|||
Each structural directive does something different with that template.
|
||||
|
||||
在这个例子中,我们将学到[星号(*)这个简写方法](guide/structural-directives#asterisk),而这个字符串是一个[*微语法*](guide/structural-directives#microsyntax),而不是通常的[模板表达式](guide/template-syntax#template-expressions)。
|
||||
Angular会解开这个语法糖,变成一个`<ng-template>`标记,包裹着宿主元素及其子元素。
|
||||
Angular 会解开这个语法糖,变成一个 `<ng-template>` 标记,包裹着宿主元素及其子元素。
|
||||
每个结构型指令都可以用这个模板做点不同的事情。
|
||||
|
||||
Three of the common, built-in structural directives—[NgIf](guide/template-syntax#ngIf),
|
||||
|
@ -67,7 +67,7 @@ described in the [_Template Syntax_](guide/template-syntax) guide and seen in sa
|
|||
Here's an example of them in a template:
|
||||
|
||||
三个常用的内置结构型指令 —— [NgIf](guide/template-syntax#ngIf)、[NgFor](guide/template-syntax#ngFor)和[NgSwitch...](guide/template-syntax#ngSwitch)。
|
||||
我们在[*模板语法*](guide/template-syntax)一章中讲过它,并且在Angular文档的例子中到处都在用它。下面是模板中的例子:
|
||||
我们在[*模板语法*](guide/template-syntax)一章中讲过它,并且在 Angular 文档的例子中到处都在用它。下面是模板中的例子:
|
||||
|
||||
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (built-in)" region="built-in">
|
||||
|
||||
|
@ -89,8 +89,8 @@ Already you've seen `NgIf` and `ngIf`.
|
|||
There's a reason. `NgIf` refers to the directive _class_;
|
||||
`ngIf` refers to the directive's _attribute name_.
|
||||
|
||||
在本章中,我们将看到指令同时具有两种拼写形式*大驼峰`UpperCamelCase`和小驼峰`lowerCamelCase`,比如我们已经看过的`NgIf`和`ngIf`。
|
||||
这里的原因在于,`NgIf`引用的是指令的*类名*,而`ngIf`引用的是指令的*属性名*。
|
||||
在本章中,我们将看到指令同时具有两种拼写形式*大驼峰 `UpperCamelCase` 和小驼峰 `lowerCamelCase`,比如我们已经看过的 `NgIf` 和 `ngIf`。
|
||||
这里的原因在于,`NgIf` 引用的是指令的*类名*,而 `ngIf` 引用的是指令的*属性名*。
|
||||
|
||||
A directive _class_ is spelled in _UpperCamelCase_ (`NgIf`).
|
||||
A directive's _attribute name_ is spelled in _lowerCamelCase_ (`ngIf`).
|
||||
|
@ -99,7 +99,7 @@ The guide refers to the _attribute name_ when describing how
|
|||
you apply the directive to an element in the HTML template.
|
||||
|
||||
指令的*类名*拼写成*大驼峰形式*(`NgIf`),而它的*属性名*则拼写成*小驼峰形式*(`ngIf`)。
|
||||
本章会在谈论指令的属性和工作原理时引用指令的*类名*,在描述如何在HTML模板中把该指令应用到元素时,引用指令的*属性名*。
|
||||
本章会在谈论指令的属性和工作原理时引用指令的*类名*,在描述如何在 HTML 模板中把该指令应用到元素时,引用指令的*属性名*。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -108,12 +108,12 @@ you apply the directive to an element in the HTML template.
|
|||
There are two other kinds of Angular directives, described extensively elsewhere:
|
||||
(1) components and (2) attribute directives.
|
||||
|
||||
还有另外两种Angular指令,在本开发指南的其它地方有讲解:(1) 组件 (2) 属性型指令。
|
||||
还有另外两种 Angular 指令,在本开发指南的其它地方有讲解:(1) 组件 (2) 属性型指令。
|
||||
|
||||
A *component* manages a region of HTML in the manner of a native HTML element.
|
||||
Technically it's a directive with a template.
|
||||
|
||||
*组件*可以在原生HTML元素中管理一小片区域的HTML。从技术角度说,它就是一个带模板的指令。
|
||||
*组件*可以在原生 HTML 元素中管理一小片区域的 HTML。从技术角度说,它就是一个带模板的指令。
|
||||
|
||||
An [*attribute* directive](guide/attribute-directives) changes the appearance or behavior
|
||||
of an element, component, or another directive.
|
||||
|
@ -134,12 +134,12 @@ You can [only apply one](guide/structural-directives#one-per-element) _structura
|
|||
|
||||
## NgIf case study
|
||||
|
||||
## NgIf案例分析
|
||||
## NgIf 案例分析
|
||||
|
||||
`NgIf` is the simplest structural directive and the easiest to understand.
|
||||
It takes a boolean expression and makes an entire chunk of the DOM appear or disappear.
|
||||
|
||||
我们重点看下`ngIf`。它是一个很好的结构型指令案例:它接受一个布尔值,并据此让一整块DOM树出现或消失。
|
||||
我们重点看下 `ngIf`。它是一个很好的结构型指令案例:它接受一个布尔值,并据此让一整块 DOM 树出现或消失。
|
||||
|
||||
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngif-true)" region="ngif-true">
|
||||
|
||||
|
@ -148,7 +148,7 @@ It takes a boolean expression and makes an entire chunk of the DOM appear or dis
|
|||
The `ngIf` directive doesn't hide elements with CSS. It adds and removes them physically from the DOM.
|
||||
Confirm that fact using browser developer tools to inspect the DOM.
|
||||
|
||||
`ngIf`指令并不是使用CSS来隐藏元素的。它会把这些元素从DOM中物理删除。
|
||||
`ngIf` 指令并不是使用 CSS 来隐藏元素的。它会把这些元素从 DOM 中物理删除。
|
||||
使用浏览器的开发者工具就可以确认这一点。
|
||||
|
||||
<figure>
|
||||
|
@ -158,15 +158,15 @@ Confirm that fact using browser developer tools to inspect the DOM.
|
|||
The top paragraph is in the DOM. The bottom, disused paragraph is not;
|
||||
in its place is a comment about "bindings" (more about that [later](guide/structural-directives#asterisk)).
|
||||
|
||||
可以看到第一段文字出现在了DOM中,而第二段则没有,在第二段的位置上是一个关于“绑定”的注释([稍后](guide/structural-directives#asterisk)有更多讲解)。
|
||||
可以看到第一段文字出现在了 DOM 中,而第二段则没有,在第二段的位置上是一个关于“绑定”的注释([稍后](guide/structural-directives#asterisk)有更多讲解)。
|
||||
|
||||
When the condition is false, `NgIf` removes its host element from the DOM,
|
||||
detaches it from DOM events (the attachments that it made),
|
||||
detaches the component from Angular change detection, and destroys it.
|
||||
The component and DOM nodes can be garbage-collected and free up memory.
|
||||
|
||||
当条件为假时,`NgIf`会从DOM中移除它的宿主元素,取消它监听过的那些DOM事件,从Angular变更检测中移除该组件,并销毁它。
|
||||
这些组件和DOM节点可以被当做垃圾收集起来,并且释放它们占用的内存。
|
||||
当条件为假时,`NgIf` 会从 DOM 中移除它的宿主元素,取消它监听过的那些 DOM 事件,从 Angular 变更检测中移除该组件,并销毁它。
|
||||
这些组件和 DOM 节点可以被当做垃圾收集起来,并且释放它们占用的内存。
|
||||
|
||||
### Why *remove* rather than *hide*?
|
||||
|
||||
|
@ -174,7 +174,7 @@ The component and DOM nodes can be garbage-collected and free up memory.
|
|||
|
||||
A directive could hide the unwanted paragraph instead by setting its `display` style to `none`.
|
||||
|
||||
指令也可以通过把它的`display`风格设置为`none`而隐藏不需要的段落。
|
||||
指令也可以通过把它的 `display` 风格设置为 `none` 而隐藏不需要的段落。
|
||||
|
||||
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (display-none)" region="display-none">
|
||||
|
||||
|
@ -182,7 +182,7 @@ A directive could hide the unwanted paragraph instead by setting its `display` s
|
|||
|
||||
While invisible, the element remains in the DOM.
|
||||
|
||||
当不可见时,这个元素仍然留在DOM中。
|
||||
当不可见时,这个元素仍然留在 DOM 中。
|
||||
|
||||
<figure>
|
||||
<img src='generated/images/guide/structural-directives/element-display-in-dom.png' alt="hidden element still in DOM">
|
||||
|
@ -195,8 +195,8 @@ The component stays attached to its DOM element. It keeps listening to events.
|
|||
Angular keeps checking for changes that could affect data bindings.
|
||||
Whatever the component was doing, it keeps doing.
|
||||
|
||||
对于简单的段落,隐藏和移除之间的差异影响不大,但对于资源占用较多的组件是不一样的。当我们隐藏掉一个元素时,组件的行为还在继续 —— 它仍然附加在它所属的DOM元素上,
|
||||
它也仍在监听事件。Angular会继续检查哪些能影响数据绑定的变更。
|
||||
对于简单的段落,隐藏和移除之间的差异影响不大,但对于资源占用较多的组件是不一样的。当我们隐藏掉一个元素时,组件的行为还在继续 —— 它仍然附加在它所属的 DOM 元素上,
|
||||
它也仍在监听事件。Angular 会继续检查哪些能影响数据绑定的变更。
|
||||
组件原本要做的那些事情仍在继续。
|
||||
|
||||
Although invisible, the component—and all of its descendant components—tie up resources.
|
||||
|
@ -219,7 +219,7 @@ But in the absence of a compelling reason to keep them around,
|
|||
your preference should be to remove DOM elements that the user can't see
|
||||
and recover the unused resources with a structural directive like `NgIf` .
|
||||
|
||||
但是,除非有非常强烈的理由来保留它们,否则我们更倾向于移除用户看不见的那些DOM元素,并且使用`NgIf`这样的结构型指令来收回用不到的资源。
|
||||
但是,除非有非常强烈的理由来保留它们,否则我们更倾向于移除用户看不见的那些 DOM 元素,并且使用 `NgIf` 这样的结构型指令来收回用不到的资源。
|
||||
|
||||
**These same considerations apply to every structural directive, whether built-in or custom.**
|
||||
Before applying a structural directive, you might want to pause for a moment
|
||||
|
@ -241,7 +241,7 @@ and wondered why it is necessary and what it does.
|
|||
|
||||
Here is `*ngIf` displaying the hero's name if `hero` exists.
|
||||
|
||||
这里的`*ngIf`会在`hero`存在时显示英雄的名字。
|
||||
这里的 `*ngIf` 会在 `hero` 存在时显示英雄的名字。
|
||||
|
||||
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (asterisk)" region="asterisk">
|
||||
|
||||
|
@ -251,7 +251,7 @@ The asterisk is "syntactic sugar" for something a bit more complicated.
|
|||
Internally, Angular translates the `*ngIf` _attribute_ into a `<ng-template>` _element_, wrapped around the host element, like this.
|
||||
|
||||
星号是一个用来简化更复杂语法的“语法糖”。
|
||||
从内部实现来说,Angular把`*ngIf` *属性* 翻译成一个`<ng-template>` *元素* 并用它来包裹宿主元素,代码如下:
|
||||
从内部实现来说,Angular 把 `*ngIf` *属性* 翻译成一个 `<ng-template>` *元素* 并用它来包裹宿主元素,代码如下:
|
||||
|
||||
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngif-template)" region="ngif-template">
|
||||
|
||||
|
@ -259,16 +259,16 @@ Internally, Angular translates the `*ngIf` _attribute_ into a `<ng-template>` _e
|
|||
|
||||
* The `*ngIf` directive moved to the `<ng-template>` element where it became a property binding,`[ngIf]`.
|
||||
|
||||
`*ngIf`指令被移到了`<ng-template>`元素上。在那里它变成了一个属性绑定`[ngIf]`。
|
||||
`*ngIf` 指令被移到了 `<ng-template>` 元素上。在那里它变成了一个属性绑定 `[ngIf]`。
|
||||
|
||||
* The rest of the `<div>`, including its class attribute, moved inside the `<ng-template>` element.
|
||||
|
||||
`<div>`上的其余部分,包括它的`class`属性在内,移到了内部的`<ng-template>`元素上。
|
||||
`<div>` 上的其余部分,包括它的 `class` 属性在内,移到了内部的 `<ng-template>` 元素上。
|
||||
|
||||
The first form is not actually rendered, only the finished product ends up in the DOM.
|
||||
|
||||
第一种形态永远不会真的渲染出来。
|
||||
只有最终产出的结果才会出现在DOM中。
|
||||
只有最终产出的结果才会出现在 DOM 中。
|
||||
|
||||
<figure>
|
||||
<img src='generated/images/guide/structural-directives/hero-div-in-dom.png' alt="hero div in DOM">
|
||||
|
@ -277,7 +277,7 @@ The first form is not actually rendered, only the finished product ends up in th
|
|||
Angular consumed the `<ng-template>` content during its actual rendering and
|
||||
replaced the `<ng-template>` with a diagnostic comment.
|
||||
|
||||
Angular会在真正渲染的时候填充`<ng-template>`的内容,并且把`<ng-template>`替换为一个供诊断用的注释。
|
||||
Angular 会在真正渲染的时候填充 `<ng-template>` 的内容,并且把 `<ng-template>` 替换为一个供诊断用的注释。
|
||||
|
||||
The [`NgFor`](guide/structural-directives#ngFor) and [`NgSwitch...`](guide/structural-directives#ngSwitch) directives follow the same pattern.
|
||||
|
||||
|
@ -287,15 +287,15 @@ The [`NgFor`](guide/structural-directives#ngFor) and [`NgSwitch...`](guide/struc
|
|||
|
||||
## Inside _*ngFor_
|
||||
|
||||
## `*ngFor`内幕
|
||||
## `*ngFor` 内幕
|
||||
|
||||
Angular transforms the `*ngFor` in similar fashion from asterisk (*) syntax to `<ng-template>` _element_.
|
||||
|
||||
Angular会把`*ngFor`用同样的方式把星号(*)语法的`template`*属性*转换成`<ng-template>`*元素*。
|
||||
Angular 会把 `*ngFor` 用同样的方式把星号(*)语法的 `template`*属性*转换成 `<ng-template>`*元素*。
|
||||
|
||||
Here's a full-featured application of `NgFor`, written both ways:
|
||||
|
||||
这里有一个`NgFor`的全特性应用,同时用了这三种写法:
|
||||
这里有一个 `NgFor` 的全特性应用,同时用了这三种写法:
|
||||
|
||||
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (inside-ngfor)" region="inside-ngfor">
|
||||
|
||||
|
@ -305,13 +305,13 @@ This is manifestly more complicated than `ngIf` and rightly so.
|
|||
The `NgFor` directive has more features, both required and optional, than the `NgIf` shown in this guide.
|
||||
At minimum `NgFor` needs a looping variable (`let hero`) and a list (`heroes`).
|
||||
|
||||
它明显比`ngIf`复杂得多,确实如此。
|
||||
`NgFor`指令比本章展示过的`NgIf`具有更多的必选特性和可选特性。
|
||||
至少`NgFor`会需要一个循环变量(`let hero`)和一个列表(`heroes`)。
|
||||
它明显比 `ngIf` 复杂得多,确实如此。
|
||||
`NgFor` 指令比本章展示过的 `NgIf` 具有更多的必选特性和可选特性。
|
||||
至少 `NgFor` 会需要一个循环变量(`let hero`)和一个列表(`heroes`)。
|
||||
|
||||
You enable these features in the string assigned to `ngFor`, which you write in Angular's [microsyntax](guide/structural-directives#microsyntax).
|
||||
|
||||
我们可以通过把一个字符串赋值给`ngFor`来启用这些特性,这个字符串使用Angular的[微语法](guide/structural-directives#microsyntax)。
|
||||
我们可以通过把一个字符串赋值给 `ngFor` 来启用这些特性,这个字符串使用 Angular 的[微语法](guide/structural-directives#microsyntax)。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
|
@ -319,8 +319,8 @@ Everything _outside_ the `ngFor` string stays with the host element
|
|||
(the `<div>`) as it moves inside the `<ng-template>`.
|
||||
In this example, the `[ngClass]="odd"` stays on the `<div>`.
|
||||
|
||||
`ngFor`字符串*之外*的每一样东西都会留在宿主元素(`<div>`)上,也就是说它移到了`<ng-template>`内部。
|
||||
在这个例子中,`[ngClass]="odd"`留在了`<div>`上。
|
||||
`ngFor` 字符串*之外*的每一样东西都会留在宿主元素(`<div>`)上,也就是说它移到了 `<ng-template>` 内部。
|
||||
在这个例子中,`[ngClass]="odd"` 留在了 `<div>` 上。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -333,37 +333,37 @@ In this example, the `[ngClass]="odd"` stays on the `<div>`.
|
|||
The Angular microsyntax lets you configure a directive in a compact, friendly string.
|
||||
The microsyntax parser translates that string into attributes on the `<ng-template>`:
|
||||
|
||||
Angular微语法能让我们通过简短的、友好的字符串来配置一个指令。
|
||||
微语法解析器把这个字符串翻译成`<ng-template>`上的属性:
|
||||
Angular 微语法能让我们通过简短的、友好的字符串来配置一个指令。
|
||||
微语法解析器把这个字符串翻译成 `<ng-template>` 上的属性:
|
||||
|
||||
* The `let` keyword declares a [_template input variable_](guide/structural-directives#template-input-variable)
|
||||
that you reference within the template. The input variables in this example are `hero`, `i`, and `odd`.
|
||||
The parser translates `let hero`, `let i`, and `let odd` into variables named,
|
||||
`let-hero`, `let-i`, and `let-odd`.
|
||||
|
||||
`let`关键字声明一个[模板输入变量](guide/structural-directives#template-input-variable),我们会在模板中引用它。本例子中,这个输入变量就是`hero`、`i`和`odd`。
|
||||
解析器会把`let hero`、`let i`和`let odd`翻译成命名变量`let-hero`、`let-i`和`let-odd`。
|
||||
`let` 关键字声明一个[模板输入变量](guide/structural-directives#template-input-variable),我们会在模板中引用它。本例子中,这个输入变量就是 `hero`、`i` 和 `odd`。
|
||||
解析器会把 `let hero`、`let i` 和 `let odd` 翻译成命名变量 `let-hero`、`let-i` 和 `let-odd`。
|
||||
|
||||
* The microsyntax parser takes `of` and `trackBy`, title-cases them (`of` -> `Of`, `trackBy` -> `TrackBy`),
|
||||
and prefixes them with the directive's attribute name (`ngFor`), yielding the names `ngForOf` and `ngForTrackBy`.
|
||||
Those are the names of two `NgFor` _input properties_ .
|
||||
That's how the directive learns that the list is `heroes` and the track-by function is `trackById`.
|
||||
|
||||
微语法解析器接收`of`和`trackby`,把它们首字母大写(`of` -> `Of`, `trackBy` -> `TrackBy`),
|
||||
并且给它们加上指令的属性名(`ngFor`)前缀,最终生成的名字是`ngForOf`和`ngForTrackBy`。
|
||||
还有两个`NgFor`的*输入属性*,指令据此了解到列表是`heroes`,而track-by函数是`trackById`。
|
||||
微语法解析器接收 `of` 和 `trackby`,把它们首字母大写(`of` -> `Of`, `trackBy` -> `TrackBy`),
|
||||
并且给它们加上指令的属性名(`ngFor`)前缀,最终生成的名字是 `ngForOf` 和 `ngForTrackBy`。
|
||||
还有两个 `NgFor` 的*输入属性*,指令据此了解到列表是 `heroes`,而 track-by 函数是 `trackById`。
|
||||
|
||||
* As the `NgFor` directive loops through the list, it sets and resets properties of its own _context_ object.
|
||||
These properties include `index` and `odd` and a special property named `$implicit`.
|
||||
|
||||
`NgFor`指令在列表上循环,每个循环中都会设置和重置它自己的*上下文*对象上的属性。
|
||||
这些属性包括`index`和`odd`以及一个特殊的属性名`$implicit`(隐式变量)。
|
||||
`NgFor` 指令在列表上循环,每个循环中都会设置和重置它自己的*上下文*对象上的属性。
|
||||
这些属性包括 `index` 和 `odd` 以及一个特殊的属性名 `$implicit`(隐式变量)。
|
||||
|
||||
* The `let-i` and `let-odd` variables were defined as `let i=index` and `let odd=odd`.
|
||||
Angular sets them to the current value of the context's `index` and `odd` properties.
|
||||
|
||||
`let-i`和`let-odd`变量是通过`let i=index`和`let odd=odd`来定义的。
|
||||
Angular把它们设置为*上下文*对象中的`index`和`odd`属性的当前值。
|
||||
`let-i` 和 `let-odd` 变量是通过 `let i=index` 和 `let odd=odd` 来定义的。
|
||||
Angular 把它们设置为*上下文*对象中的 `index` 和 `odd` 属性的当前值。
|
||||
|
||||
* The context property for `let-hero` wasn't specified.
|
||||
Its intended source is implicit.
|
||||
|
@ -373,11 +373,11 @@ which `NgFor` has initialized with the hero for the current iteration.
|
|||
* The [API guide](api/common/NgForOf "API: NgFor")
|
||||
describes additional `NgFor` directive properties and context properties.
|
||||
|
||||
[API参考手册](api/common/NgForOf "API: NgFor")中描述了`NgFor`指令的其它属性和上下文属性。
|
||||
[API 参考手册](api/common/NgForOf "API: NgFor")中描述了 `NgFor` 指令的其它属性和上下文属性。
|
||||
|
||||
* `NgFor` is implemented by the `NgForOf` directive. Read more about additional `NgForOf` directive properties and context properties [NgForOf API reference](api/common/NgForOf).
|
||||
|
||||
`NgFor`是由`NgForOf`指令来实现的。请参阅[NgForOf API reference](api/common/NgForOf)来了解`NgForOf`指令的更多属性及其上下文属性。
|
||||
`NgFor` 是由 `NgForOf` 指令来实现的。请参阅[NgForOf API reference](api/common/NgForOf)来了解 `NgForOf` 指令的更多属性及其上下文属性。
|
||||
|
||||
These microsyntax mechanisms are available to you when you write your own structural directives.
|
||||
Studying the
|
||||
|
@ -385,8 +385,8 @@ Studying the
|
|||
and [`NgForOf`](https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_for_of.ts "Source: NgForOf")
|
||||
is a great way to learn more.
|
||||
|
||||
这些微语法机制在你写自己的结构型指令时也同样有效,参考[`NgIf`的源码](https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_if.ts "Source: NgIf")
|
||||
和[`NgFor`的源码](https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_for_of.ts "Source: NgFor") 可以学到更多。
|
||||
这些微语法机制在你写自己的结构型指令时也同样有效,参考[`NgIf` 的源码](https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_if.ts "Source: NgIf")
|
||||
和[`NgFor` 的源码](https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_for_of.ts "Source: NgFor") 可以学到更多。
|
||||
|
||||
{@a template-input-variable}
|
||||
|
||||
|
@ -401,8 +401,8 @@ There are several such variables in this example: `hero`, `i`, and `odd`.
|
|||
All are preceded by the keyword `let`.
|
||||
|
||||
*模板输入变量*是这样一种变量,你可以*在单个实例的模板中*引用它的值。
|
||||
这个例子中有好几个模板输入变量:`hero`、`i`和`odd`。
|
||||
它们都是用`let`作为前导关键字。
|
||||
这个例子中有好几个模板输入变量:`hero`、`i` 和 `odd`。
|
||||
它们都是用 `let` 作为前导关键字。
|
||||
|
||||
A _template input variable_ is **_not_** the same as a
|
||||
[template _reference_ variable](guide/template-syntax#ref-vars),
|
||||
|
@ -414,7 +414,7 @@ You declare a template _input_ variable using the `let` keyword (`let hero`).
|
|||
The variable's scope is limited to a _single instance_ of the repeated template.
|
||||
You can use the same variable name again in the definition of other structural directives.
|
||||
|
||||
我们使用`let`关键字(如`let hero`)在模板中声明一个模板*输入*变量。
|
||||
我们使用 `let` 关键字(如 `let hero`)在模板中声明一个模板*输入*变量。
|
||||
这个变量的范围被限制在所重复模板的*单一实例*上。
|
||||
事实上,我们可以在其它结构型指令中使用同样的变量名。
|
||||
|
||||
|
@ -422,13 +422,13 @@ You declare a template _reference_ variable by prefixing the variable name with
|
|||
A _reference_ variable refers to its attached element, component or directive.
|
||||
It can be accessed _anywhere_ in the _entire template_.
|
||||
|
||||
而声明模板*引用*变量使用的是给变量名加`#`前缀的方式(`#var`)。
|
||||
而声明模板*引用*变量使用的是给变量名加 `#` 前缀的方式(`#var`)。
|
||||
一个*引用*变量引用的是它所附着到的元素、组件或指令。它可以在*整个模板*的*任意位置*访问。
|
||||
|
||||
Template _input_ and _reference_ variable names have their own namespaces. The `hero` in `let hero` is never the same
|
||||
variable as the `hero` declared as `#hero`.
|
||||
|
||||
模板*输入*变量和*引用*变量具有各自独立的命名空间。`let hero`中的`hero`和`#hero`中的`hero`并不是同一个变量。
|
||||
模板*输入*变量和*引用*变量具有各自独立的命名空间。`let hero` 中的 `hero` 和 `#hero` 中的 `hero` 并不是同一个变量。
|
||||
|
||||
{@a one-per-element}
|
||||
|
||||
|
@ -441,14 +441,14 @@ You'll _try_ to put both an `*ngFor` and an `*ngIf` on the same host element.
|
|||
Angular won't let you. You may apply only one _structural_ directive to an element.
|
||||
|
||||
有时我们会希望只有当特定的条件为真时才重复渲染一个 HTML 块。
|
||||
你可能试过把`*ngFor`和`*ngIf`放在同一个宿主元素上,但Angular 不允许。这是因为我们在一个元素上只能放一个*结构型*指令。
|
||||
你可能试过把 `*ngFor` 和 `*ngIf` 放在同一个宿主元素上,但 Angular 不允许。这是因为我们在一个元素上只能放一个*结构型*指令。
|
||||
|
||||
The reason is simplicity. Structural directives can do complex things with the host element and its descendents.
|
||||
When two directives lay claim to the same host element, which one takes precedence?
|
||||
Which should go first, the `NgIf` or the `NgFor`? Can the `NgIf` cancel the effect of the `NgFor`?
|
||||
If so (and it seems like it should be so), how should Angular generalize the ability to cancel for other structural directives?
|
||||
|
||||
原因很简单。结构型指令可能会对宿主元素及其子元素做很复杂的事。当两个指令放在同一个元素上时,谁先谁后?`NgIf`优先还是`NgFor`优先?`NgIf`可以取消`NgFor`的效果吗?
|
||||
原因很简单。结构型指令可能会对宿主元素及其子元素做很复杂的事。当两个指令放在同一个元素上时,谁先谁后?`NgIf` 优先还是 `NgFor` 优先?`NgIf` 可以取消 `NgFor` 的效果吗?
|
||||
如果要这样做,Angular 应该如何把这种能力泛化,以取消其它结构型指令的效果呢?
|
||||
|
||||
There are no easy answers to these questions. Prohibiting multiple structural directives makes them moot.
|
||||
|
@ -456,8 +456,8 @@ There's an easy solution for this use case: put the `*ngIf` on a container eleme
|
|||
One or both elements can be an [`ng-container`](guide/structural-directives#ngcontainer) so you don't have to introduce extra levels of HTML.
|
||||
|
||||
对这些问题,没有办法简单回答。而禁止多个结构型指令则可以简单地解决这个问题。
|
||||
这种情况下有一个简单的解决方案:把`*ngIf`放在一个"容器"元素上,再包装进 `*ngFor` 元素。
|
||||
这个元素可以使用[`ng-container`](guide/structural-directives#ngcontainer),以免引入一个新的HTML层级。
|
||||
这种情况下有一个简单的解决方案:把 `*ngIf` 放在一个"容器"元素上,再包装进 `*ngFor` 元素。
|
||||
这个元素可以使用[`ng-container`](guide/structural-directives#ngcontainer),以免引入一个新的 HTML 层级。
|
||||
|
||||
{@a ngSwitch}
|
||||
|
||||
|
@ -480,14 +480,14 @@ Here's an example.
|
|||
The switch value assigned to `NgSwitch` (`hero.emotion`) determines which
|
||||
(if any) of the switch cases are displayed.
|
||||
|
||||
一个值(`hero.emotion`)被被赋值给了`NgSwitch`,以决定要显示哪一个分支。
|
||||
一个值(`hero.emotion`)被被赋值给了 `NgSwitch`,以决定要显示哪一个分支。
|
||||
|
||||
`NgSwitch` itself is not a structural directive.
|
||||
It's an _attribute_ directive that controls the behavior of the other two switch directives.
|
||||
That's why you write `[ngSwitch]`, never `*ngSwitch`.
|
||||
|
||||
`NgSwitch`本身不是结构型指令,而是一个*属性型*指令,它控制其它两个switch指令的行为。
|
||||
这也就是为什么我们要写成`[ngSwitch]`而不是`*ngSwitch`的原因。
|
||||
`NgSwitch` 本身不是结构型指令,而是一个*属性型*指令,它控制其它两个 switch 指令的行为。
|
||||
这也就是为什么我们要写成 `[ngSwitch]` 而不是 `*ngSwitch` 的原因。
|
||||
|
||||
`NgSwitchCase` and `NgSwitchDefault` _are_ structural directives.
|
||||
You attach them to elements using the asterisk (*) prefix notation.
|
||||
|
@ -496,8 +496,8 @@ The `NgSwitchDefault` displays its host element when no sibling `NgSwitchCase` m
|
|||
|
||||
`NgSwitchCase` 和 `NgSwitchDefault` *都是*结构型指令。
|
||||
因此我们要使用星号(`*`)前缀来把它们附着到元素上。
|
||||
`NgSwitchCase`会在它的值匹配上选项值的时候显示它的宿主元素。
|
||||
`NgSwitchDefault`则会当没有兄弟`NgSwitchCase`匹配上时显示它的宿主元素。
|
||||
`NgSwitchCase` 会在它的值匹配上选项值的时候显示它的宿主元素。
|
||||
`NgSwitchDefault` 则会当没有兄弟 `NgSwitchCase` 匹配上时显示它的宿主元素。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
|
@ -537,8 +537,8 @@ While there's rarely a good reason to apply a structural directive in template _
|
|||
it's still important to know that Angular creates a `<ng-template>` and to understand how it works.
|
||||
You'll refer to the `<ng-template>` when you [write your own structural directive](guide/structural-directives#unless).
|
||||
|
||||
虽然很少有理由在模板中使用结构型指令的*属性*形式和*元素*形式,但这些幕后知识仍然是很重要的,即:Angular会创建`<ng-template>`,还要了解它的工作原理。
|
||||
当需要[写自己的结构型指令](guide/structural-directives#unless)时,我们就要使用`<ng-template>`。
|
||||
虽然很少有理由在模板中使用结构型指令的*属性*形式和*元素*形式,但这些幕后知识仍然是很重要的,即:Angular 会创建 `<ng-template>`,还要了解它的工作原理。
|
||||
当需要[写自己的结构型指令](guide/structural-directives#unless)时,我们就要使用 `<ng-template>`。
|
||||
|
||||
{@a template}
|
||||
|
||||
|
@ -550,15 +550,15 @@ The <ng-template> is an Angular element for rendering HTML.
|
|||
It is never displayed directly.
|
||||
In fact, before rendering the view, Angular _replaces_ the `<ng-template>` and its contents with a comment.
|
||||
|
||||
<ng-template>是一个 Angular 元素,用来渲染HTML。
|
||||
<ng-template>是一个 Angular 元素,用来渲染 HTML。
|
||||
它永远不会直接显示出来。
|
||||
事实上,在渲染视图之前,Angular 会把`<ng-template>`及其内容*替换为*一个注释。
|
||||
事实上,在渲染视图之前,Angular 会把 `<ng-template>` 及其内容*替换为*一个注释。
|
||||
|
||||
If there is no structural directive and you merely wrap some elements in a `<ng-template>`,
|
||||
those elements disappear.
|
||||
That's the fate of the middle "Hip!" in the phrase "Hip! Hip! Hooray!".
|
||||
|
||||
如果没有使用结构型指令,而仅仅把一些别的元素包装进`<ng-template>`中,那些元素就是不可见的。
|
||||
如果没有使用结构型指令,而仅仅把一些别的元素包装进 `<ng-template>` 中,那些元素就是不可见的。
|
||||
在下面的这个短语"Hip! Hip! Hooray!"中,中间的这个 "Hip!"(欢呼声) 就是如此。
|
||||
|
||||
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (template-tag)" region="template-tag">
|
||||
|
@ -576,7 +576,7 @@ Angular 抹掉了中间的那个 "Hip!" ,让欢呼声显得不再那么热烈
|
|||
A structural directive puts a `<ng-template>` to work
|
||||
as you'll see when you [write your own structural directive](guide/structural-directives#unless).
|
||||
|
||||
结构型指令会让`<ng-template>`正常工作,在我们[写自己的结构型指令](guide/structural-directives#unless)时就会看到这一点。
|
||||
结构型指令会让 `<ng-template>` 正常工作,在我们[写自己的结构型指令](guide/structural-directives#unless)时就会看到这一点。
|
||||
|
||||
{@a ngcontainer}
|
||||
|
||||
|
@ -590,7 +590,7 @@ There's often a _root_ element that can and should host the structural directive
|
|||
The list element (`<li>`) is a typical host element of an `NgFor` repeater.
|
||||
|
||||
通常都要有一个*根*元素作为结构型指令的数组。
|
||||
列表元素(`<li>`)就是一个典型的供`NgFor`使用的宿主元素。
|
||||
列表元素(`<li>`)就是一个典型的供 `NgFor` 使用的宿主元素。
|
||||
|
||||
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngfor-li)" region="ngfor-li">
|
||||
|
||||
|
@ -599,7 +599,7 @@ The list element (`<li>`) is a typical host element of an `NgFor` repeater.
|
|||
When there isn't a host element, you can usually wrap the content in a native HTML container element,
|
||||
such as a `<div>`, and attach the directive to that wrapper.
|
||||
|
||||
当没有这样一个单一的宿主元素时,我们可以把这些内容包裹在一个原生的HTML容器元素中,比如`<div>`,并且把结构型指令附加到这个"包裹"上。
|
||||
当没有这样一个单一的宿主元素时,我们可以把这些内容包裹在一个原生的 HTML 容器元素中,比如 `<div>`,并且把结构型指令附加到这个"包裹"上。
|
||||
|
||||
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngif)" region="ngif">
|
||||
|
||||
|
@ -609,13 +609,13 @@ Introducing another container element—typically a `<span>` or `<div>`&mdas
|
|||
group the elements under a single _root_ is usually harmless.
|
||||
_Usually_ ... but not _always_.
|
||||
|
||||
但引入另一个容器元素(通常是`<span>`或`<div>`)来把一些元素归到一个单一的*根元素*下,通常也会带来问题。注意,是"通常"而不是"总会"。
|
||||
但引入另一个容器元素(通常是 `<span>` 或 `<div>`)来把一些元素归到一个单一的*根元素*下,通常也会带来问题。注意,是"通常"而不是"总会"。
|
||||
|
||||
The grouping element may break the template appearance because CSS styles
|
||||
neither expect nor accommodate the new layout.
|
||||
For example, suppose you have the following paragraph layout.
|
||||
|
||||
这种用于分组的元素可能会破坏模板的外观表现,因为CSS的样式既不曾期待也不会接受这种新的元素布局。
|
||||
这种用于分组的元素可能会破坏模板的外观表现,因为 CSS 的样式既不曾期待也不会接受这种新的元素布局。
|
||||
比如,假设你有下列分段布局。
|
||||
|
||||
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngif-span)" region="ngif-span">
|
||||
|
@ -624,7 +624,7 @@ For example, suppose you have the following paragraph layout.
|
|||
|
||||
You also have a CSS style rule that happens to apply to a `<span>` within a `<p>`aragraph.
|
||||
|
||||
而我们的CSS样式规则是应用于`<p>`元素下的`<span>`的。
|
||||
而我们的 CSS 样式规则是应用于 `<p>` 元素下的 `<span>` 的。
|
||||
|
||||
<code-example path="structural-directives/src/app/app.component.css" linenums="false" title="src/app/app.component.css (p-span)" region="p-span">
|
||||
|
||||
|
@ -640,14 +640,14 @@ The constructed paragraph renders strangely.
|
|||
|
||||
The `p span` style, intended for use elsewhere, was inadvertently applied here.
|
||||
|
||||
本来为其它地方准备的`p span`样式,被意外的应用到了这里。
|
||||
本来为其它地方准备的 `p span` 样式,被意外的应用到了这里。
|
||||
|
||||
Another problem: some HTML elements require all immediate children to be of a specific type.
|
||||
For example, the `<select>` element requires `<option>` children.
|
||||
You can't wrap the _options_ in a conditional `<div>` or a `<span>`.
|
||||
|
||||
另一个问题是:有些HTML元素需要所有的直属下级都具有特定的类型。
|
||||
比如,`<select>`元素要求直属下级必须为`<option>`,那么我们就没办法把这些选项包装进`<div>`或`<span>`中。
|
||||
另一个问题是:有些 HTML 元素需要所有的直属下级都具有特定的类型。
|
||||
比如,`<select>` 元素要求直属下级必须为 `<option>`,那么我们就没办法把这些选项包装进 `<div>` 或 `<span>` 中。
|
||||
|
||||
When you try this,
|
||||
|
||||
|
@ -667,7 +667,7 @@ the drop down is empty.
|
|||
|
||||
The browser won't display an `<option>` within a `<span>`.
|
||||
|
||||
浏览器不会显示`<span>`中的`<option>`。
|
||||
浏览器不会显示 `<span>` 中的 `<option>`。
|
||||
|
||||
### <ng-container> to the rescue
|
||||
|
||||
|
@ -676,11 +676,11 @@ The browser won't display an `<option>` within a `<span>`.
|
|||
The Angular `<ng-container>` is a grouping element that doesn't interfere with styles or layout
|
||||
because Angular _doesn't put it in the DOM_.
|
||||
|
||||
Angular的`<ng-container>`是一个分组元素,但它不会污染样式或元素布局,因为 Angular *压根不会把它放进 DOM* 中。
|
||||
Angular 的 `<ng-container>` 是一个分组元素,但它不会污染样式或元素布局,因为 Angular *压根不会把它放进 DOM* 中。
|
||||
|
||||
Here's the conditional paragraph again, this time using `<ng-container>`.
|
||||
|
||||
下面是重新实现的条件化段落,这次我们使用`<ng-container>`。
|
||||
下面是重新实现的条件化段落,这次我们使用 `<ng-container>`。
|
||||
|
||||
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngif-ngcontainer)" region="ngif-ngcontainer">
|
||||
|
||||
|
@ -696,7 +696,7 @@ It renders properly.
|
|||
|
||||
Now conditionally exclude a _select_ `<option>` with `<ng-container>`.
|
||||
|
||||
我们再用`<ng-container>`来根据条件排除选择框中的某个`<option>`。
|
||||
我们再用 `<ng-container>` 来根据条件排除选择框中的某个 `<option>`。
|
||||
|
||||
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (select-ngcontainer)" region="select-ngcontainer">
|
||||
|
||||
|
@ -714,7 +714,7 @@ The `<ng-container>` is a syntax element recognized by the Angular parser.
|
|||
It's not a directive, component, class, or interface.
|
||||
It's more like the curly braces in a JavaScript `if`-block:
|
||||
|
||||
`<ng-container>`是一个由 Angular 解析器负责识别处理的语法元素。
|
||||
`<ng-container>` 是一个由 Angular 解析器负责识别处理的语法元素。
|
||||
它不是一个指令、组件、类或接口,更像是 JavaScript 中 `if` 块中的花括号。
|
||||
|
||||
<code-example language="javascript">
|
||||
|
@ -732,7 +732,7 @@ when you intend to conditionally execute all of them as a single block.
|
|||
The `<ng-container>` satisfies a similar need in Angular templates.
|
||||
|
||||
没有这些花括号,JavaScript 只会执行第一句,而你原本的意图是把其中的所有语句都视为一体来根据条件执行。
|
||||
而`<ng-container>`满足了 Angular 模板中类似的需求。
|
||||
而 `<ng-container>` 满足了 Angular 模板中类似的需求。
|
||||
|
||||
{@a unless}
|
||||
|
||||
|
@ -745,8 +745,8 @@ that does the opposite of `NgIf`.
|
|||
`NgIf` displays the template content when the condition is `true`.
|
||||
`UnlessDirective` displays the content when the condition is ***false***.
|
||||
|
||||
在本节中,我们会写一个名叫`UnlessDirective`的结构型指令,它是`NgIf`的反义词。
|
||||
`NgIf`在条件为`true`的时候显示模板内容,而`UnlessDirective`则会在条件为`false`时显示模板内容。
|
||||
在本节中,我们会写一个名叫 `UnlessDirective` 的结构型指令,它是 `NgIf` 的反义词。
|
||||
`NgIf` 在条件为 `true` 的时候显示模板内容,而 `UnlessDirective` 则会在条件为 `false` 时显示模板内容。
|
||||
|
||||
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (appUnless-1)" region="appUnless-1">
|
||||
|
||||
|
@ -758,11 +758,11 @@ Creating a directive is similar to creating a component.
|
|||
|
||||
* Import the `Directive` decorator (instead of the `Component` decorator).
|
||||
|
||||
导入`Directive`装饰器(而不再是`Component`)。
|
||||
导入 `Directive` 装饰器(而不再是 `Component`)。
|
||||
|
||||
* Import the `Input`, `TemplateRef`, and `ViewContainerRef` symbols; you'll need them for _any_ structural directive.
|
||||
|
||||
导入符号`Input`、`TemplateRef` 和 `ViewContainerRef`,我们在*任何*结构型指令中都会需要它们。
|
||||
导入符号 `Input`、`TemplateRef` 和 `ViewContainerRef`,我们在*任何*结构型指令中都会需要它们。
|
||||
|
||||
* Apply the decorator to the directive class.
|
||||
|
||||
|
@ -784,7 +784,7 @@ The directive's _selector_ is typically the directive's **attribute name** in sq
|
|||
The brackets define a CSS
|
||||
<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors" title="MDN: Attribute selectors">attribute selector</a>.
|
||||
|
||||
指令的*选择器*通常是把指令的属性名括在方括号中,如`[appUnless]`。
|
||||
指令的*选择器*通常是把指令的属性名括在方括号中,如 `[appUnless]`。
|
||||
这个方括号定义出了一个 CSS <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors" title="MDN: Attribute selectors">属性选择器</a>。
|
||||
|
||||
The directive _attribute name_ should be spelled in _lowerCamelCase_ and begin with a prefix.
|
||||
|
@ -793,14 +793,14 @@ Pick something short that fits you or your company.
|
|||
In this example, the prefix is `app`.
|
||||
|
||||
该指令的*属性名*应该拼写成*小驼峰*形式,并且带有一个前缀。
|
||||
但是,这个前缀不能用`ng`,因为它只属于 Angular 本身。
|
||||
但是,这个前缀不能用 `ng`,因为它只属于 Angular 本身。
|
||||
请选择一些简短的,适合你自己或公司的前缀。
|
||||
在这个例子中,前缀是`my`。
|
||||
在这个例子中,前缀是 `my`。
|
||||
|
||||
The directive _class_ name ends in `Directive` per the [style guide](guide/styleguide#02-03 "Angular Style Guide").
|
||||
Angular's own directives do not.
|
||||
|
||||
指令的*类名*用`Directive`结尾,参见[风格指南](guide/styleguide#02-03 "Angular 风格指南")。
|
||||
指令的*类名*用 `Directive` 结尾,参见[风格指南](guide/styleguide#02-03 "Angular 风格指南")。
|
||||
但 Angular 自己的指令例外。
|
||||
|
||||
### _TemplateRef_ and _ViewContainerRef_
|
||||
|
@ -813,14 +813,14 @@ from the Angular-generated `<ng-template>` and inserts that view in a
|
|||
[_view container_](api/core/ViewContainerRef "API: ViewContainerRef")
|
||||
adjacent to the directive's original `<p>` host element.
|
||||
|
||||
像这个例子一样的简单结构型指令会从 Angular 生成的`<ng-template>`元素中创建一个[*内嵌的视图*](api/core/EmbeddedViewRef "API: EmbeddedViewRef"),并把这个视图插入到一个[*视图容器*](api/core/ViewContainerRef "API: ViewContainerRef")中,紧挨着本指令原来的宿主元素`<p>`(译注:注意不是子节点,而是兄弟节点)。
|
||||
像这个例子一样的简单结构型指令会从 Angular 生成的 `<ng-template>` 元素中创建一个[*内嵌的视图*](api/core/EmbeddedViewRef "API: EmbeddedViewRef"),并把这个视图插入到一个[*视图容器*](api/core/ViewContainerRef "API: ViewContainerRef")中,紧挨着本指令原来的宿主元素 `<p>`(译注:注意不是子节点,而是兄弟节点)。
|
||||
|
||||
You'll acquire the `<ng-template>` contents with a
|
||||
[`TemplateRef`](api/core/TemplateRef "API: TemplateRef")
|
||||
and access the _view container_ through a
|
||||
[`ViewContainerRef`](api/core/ViewContainerRef "API: ViewContainerRef").
|
||||
|
||||
我们可以使用[`TemplateRef`](api/core/TemplateRef "API: TemplateRef")取得`<ng-template>`的内容,并通过[`ViewContainerRef`](api/core/ViewContainerRef "API: ViewContainerRef")来访问这个*视图容器*。
|
||||
我们可以使用[`TemplateRef`](api/core/TemplateRef "API: TemplateRef")取得 `<ng-template>` 的内容,并通过[`ViewContainerRef`](api/core/ViewContainerRef "API: ViewContainerRef")来访问这个*视图容器*。
|
||||
|
||||
You inject both in the directive constructor as private variables of the class.
|
||||
|
||||
|
@ -837,14 +837,14 @@ You inject both in the directive constructor as private variables of the class.
|
|||
The directive consumer expects to bind a true/false condition to `[appUnless]`.
|
||||
That means the directive needs an `appUnless` property, decorated with `@Input`
|
||||
|
||||
该指令的使用者会把一个true/false条件绑定到`[appUnless]`属性上。
|
||||
也就是说,该指令需要一个带有`@Input`的`appUnless`属性。
|
||||
该指令的使用者会把一个 true/false 条件绑定到 `[appUnless]` 属性上。
|
||||
也就是说,该指令需要一个带有 `@Input` 的 `appUnless` 属性。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
Read about `@Input` in the [_Template Syntax_](guide/template-syntax#inputs-outputs) guide.
|
||||
|
||||
要了解关于`@Input`的更多知识,参见[*模板语法*](guide/template-syntax#inputs-outputs)一章。
|
||||
要了解关于 `@Input` 的更多知识,参见[*模板语法*](guide/template-syntax#inputs-outputs)一章。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -869,7 +869,7 @@ clear the container which also destroys the view.
|
|||
|
||||
Nobody reads the `appUnless` property so it doesn't need a getter.
|
||||
|
||||
没有人会读取`appUnless`属性,因此它不需要定义 getter。
|
||||
没有人会读取 `appUnless` 属性,因此它不需要定义 getter。
|
||||
|
||||
The completed directive code looks like this:
|
||||
|
||||
|
@ -881,7 +881,7 @@ The completed directive code looks like this:
|
|||
|
||||
Add this directive to the `declarations` array of the AppModule.
|
||||
|
||||
把这个指令添加到AppModule的`declarations`数组中。
|
||||
把这个指令添加到 AppModule 的 `declarations` 数组中。
|
||||
|
||||
Then create some HTML to try it.
|
||||
|
||||
|
@ -894,8 +894,8 @@ Then create some HTML to try it.
|
|||
When the `condition` is falsy, the top (A) paragraph appears and the bottom (B) paragraph disappears.
|
||||
When the `condition` is truthy, the top (A) paragraph is removed and the bottom (B) paragraph appears.
|
||||
|
||||
当`condition`为`false`时,顶部的段落就会显示出来,而底部的段落消失了。
|
||||
当`condition`为`true`时,顶部的段落被移除了,而底部的段落显示了出来。
|
||||
当 `condition` 为 `false` 时,顶部的段落就会显示出来,而底部的段落消失了。
|
||||
当 `condition` 为 `true` 时,顶部的段落被移除了,而底部的段落显示了出来。
|
||||
|
||||
<figure>
|
||||
<img src='generated/images/guide/structural-directives/unless-anim.gif' alt="UnlessDirective in action">
|
||||
|
@ -961,11 +961,11 @@ You learned
|
|||
|
||||
* that the Angular desugars [asterisk (*) syntax](guide/structural-directives#asterisk) into a `<ng-template>`.
|
||||
|
||||
Angular 会把[星号(*)语法](guide/structural-directives#asterisk)解开成`<ng-template>`。
|
||||
Angular 会把[星号(*)语法](guide/structural-directives#asterisk)解开成 `<ng-template>`。
|
||||
|
||||
* how that works for the `NgIf`, `NgFor` and `NgSwitch` built-in directives.
|
||||
|
||||
内置指令`NgIf`、`NgFor`和`NgSwitch`的工作原理。
|
||||
内置指令 `NgIf`、`NgFor` 和 `NgSwitch` 的工作原理。
|
||||
|
||||
* about the [_microsyntax_](guide/structural-directives#microsyntax) that expands into a [`<ng-template>`](guide/structural-directives#template).
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ For example, `hero.component.ts` and `hero.component.html`.
|
|||
|
||||
The guideline uses the shortcut `hero.component.ts|html|css|spec` to represent those various files. Using this shortcut makes this guide's file structures easier to read and more terse.
|
||||
|
||||
本指南将会使用像`hero.component.ts|html|css|spec`的简写来表示上面描述的多个文件,目的是保持本指南的简洁性,增加描述文件结构时的可读性。
|
||||
本指南将会使用像 `hero.component.ts|html|css|spec` 的简写来表示上面描述的多个文件,目的是保持本指南的简洁性,增加描述文件结构时的可读性。
|
||||
|
||||
{@a single-responsibility}
|
||||
|
||||
|
@ -146,7 +146,7 @@ The following *negative* example defines the `AppComponent`, bootstraps the app,
|
|||
defines the `Hero` model object, and loads heroes from the server all in the same file.
|
||||
*Don't do this*.
|
||||
|
||||
下面的*负面*例子定义了`AppComponent`,它来引导应用程序,定义了`Hero`模型对象,并从服务器加载了英雄 ... 所有都在同一个文件。 *不要这么做*。
|
||||
下面的*负面*例子定义了 `AppComponent`,它来引导应用程序,定义了 `Hero` 模型对象,并从服务器加载了英雄 ... 所有都在同一个文件。 *不要这么做*。
|
||||
|
||||
<code-example path="styleguide/src/01-01/app/heroes/hero.component.avoid.ts" title="app/heroes/hero.component.ts">
|
||||
|
||||
|
@ -297,7 +297,7 @@ Naming conventions are hugely important to maintainability and readability. This
|
|||
|
||||
**Do** follow a pattern that describes the symbol's feature then its type. The recommended pattern is `feature.type.ts`.
|
||||
|
||||
**坚持**遵循同一个模式来描述符号的特性和类型。推荐的模式为`feature.type.ts`。
|
||||
**坚持**遵循同一个模式来描述符号的特性和类型。推荐的模式为 `feature.type.ts`。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -323,7 +323,7 @@ Naming conventions are hugely important to maintainability and readability. This
|
|||
**Why?** Names of folders and files should clearly convey their intent. For example, `app/heroes/hero-list.component.ts` may contain a component that manages a list of heroes.
|
||||
|
||||
**为何?**目录名和文件名应该清楚的传递它们的意图。
|
||||
例如,`app/heroes/hero-list.component.ts`包含了一个用来管理英雄列表的组件。
|
||||
例如,`app/heroes/hero-list.component.ts` 包含了一个用来管理英雄列表的组件。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -361,7 +361,7 @@ Naming conventions are hugely important to maintainability and readability. This
|
|||
|
||||
**Do** use consistent type names for all components following a pattern that describes the component's feature then its type. A recommended pattern is `feature.type.ts`.
|
||||
|
||||
**坚持**遵循先描述组件特性,再描述它的类型的模式,对所有组件使用一致的类型命名规则。推荐的模式为`feature.type.ts`。
|
||||
**坚持**遵循先描述组件特性,再描述它的类型的模式,对所有组件使用一致的类型命名规则。推荐的模式为 `feature.type.ts`。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -370,7 +370,7 @@ Naming conventions are hugely important to maintainability and readability. This
|
|||
**Do** use conventional type names including `.service`, `.component`, `.pipe`, `.module`, and `.directive`.
|
||||
Invent additional type names if you must but take care not to create too many.
|
||||
|
||||
**坚持**使用惯用的后缀来描述类型,包括`*.service`、`*.component`、`*.pipe`、`.module`、`.directive`。
|
||||
**坚持**使用惯用的后缀来描述类型,包括 `*.service`、`*.component`、`*.pipe`、`.module`、`.directive`。
|
||||
必要时可以创建更多类型名,但必须注意,不要创建太多。
|
||||
|
||||
</div>
|
||||
|
@ -396,8 +396,8 @@ Invent additional type names if you must but take care not to create too many.
|
|||
**Why?** Unabbreviated type names such as `.service` are descriptive and unambiguous.
|
||||
Abbreviations such as `.srv`, `.svc`, and `.serv` can be confusing.
|
||||
|
||||
**为何?** 像`.service`这样的没有简写过的类型名字,描述清楚,毫不含糊。
|
||||
像`.srv`, `.svc`, 和 `.serv`这样的简写可能令人困惑。
|
||||
**为何?** 像 `.service` 这样的没有简写过的类型名字,描述清楚,毫不含糊。
|
||||
像 `.srv`, `.svc`, 和 `.serv` 这样的简写可能令人困惑。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -443,7 +443,7 @@ Abbreviations such as `.srv`, `.svc`, and `.serv` can be confusing.
|
|||
|
||||
**Do** match the name of the symbol to the name of the file.
|
||||
|
||||
**坚持**在符号名后面追加约定的类型后缀(例如`Component`、`Directive`、`Module`、`Pipe`、`Service`)。
|
||||
**坚持**在符号名后面追加约定的类型后缀(例如 `Component`、`Directive`、`Module`、`Pipe`、`Service`)。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -452,7 +452,7 @@ Abbreviations such as `.srv`, `.svc`, and `.serv` can be confusing.
|
|||
**Do** append the symbol name with the conventional suffix (such as `Component`,
|
||||
`Directive`, `Module`, `Pipe`, or `Service`) for a thing of that type.
|
||||
|
||||
**坚持**在符号名后面追加约定的类型后缀(例如`.component.ts`、`.directive.ts`、`.module.ts`、`.pipe.ts`、`.service.ts`)。
|
||||
**坚持**在符号名后面追加约定的类型后缀(例如 `.component.ts`、`.directive.ts`、`.module.ts`、`.pipe.ts`、`.service.ts`)。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -461,7 +461,7 @@ Abbreviations such as `.srv`, `.svc`, and `.serv` can be confusing.
|
|||
**Do** give the filename the conventional suffix (such as `.component.ts`, `.directive.ts`,
|
||||
`.module.ts`, `.pipe.ts`, or `.service.ts`) for a file of that type.
|
||||
|
||||
**坚持**在文件名后面追加约定的类型后缀(例如`.component.ts`、`.directive.ts`、`.module.ts`、`.pipe.ts`、`.service.ts`)。
|
||||
**坚持**在文件名后面追加约定的类型后缀(例如 `.component.ts`、`.directive.ts`、`.module.ts`、`.pipe.ts`、`.service.ts`)。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -702,8 +702,8 @@ and reference assets of different types.
|
|||
For example, something that gets data or heroes
|
||||
should be called a `DataService` or a `HeroService`.
|
||||
|
||||
**坚持**为服务的类名加上`Service`后缀。
|
||||
例如,获取数据或英雄列表的服务应该命名为`DataService`或`HeroService`。
|
||||
**坚持**为服务的类名加上 `Service` 后缀。
|
||||
例如,获取数据或英雄列表的服务应该命名为 `DataService` 或 `HeroService`。
|
||||
|
||||
A few terms are unambiguously services. They typically
|
||||
indicate agency by ending in "-er". You may prefer to name
|
||||
|
@ -711,7 +711,7 @@ a service that logs messages `Logger` rather than `LoggerService`.
|
|||
Decide if this exception is agreeable in your project.
|
||||
As always, strive for consistency.
|
||||
|
||||
有些词汇显然就是服务,比如那些以“-er”后缀结尾的。比如把记日志的服务命名为`Logger`就比`LoggerService`更好些。需要在你的项目中决定这种特例是否可以接受。
|
||||
有些词汇显然就是服务,比如那些以“-er”后缀结尾的。比如把记日志的服务命名为 `Logger` 就比 `LoggerService` 更好些。需要在你的项目中决定这种特例是否可以接受。
|
||||
但无论如何,都要尽量保持一致。
|
||||
|
||||
</div>
|
||||
|
@ -728,7 +728,7 @@ As always, strive for consistency.
|
|||
|
||||
**Why?** Clear service names such as `Logger` do not require a suffix.
|
||||
|
||||
**为何?**像`Logger`这样的清楚的服务名不需要后缀。
|
||||
**为何?**像 `Logger` 这样的清楚的服务名不需要后缀。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -736,7 +736,7 @@ As always, strive for consistency.
|
|||
|
||||
**Why?** Service names such as `Credit` are nouns and require a suffix and should be named with a suffix when it is not obvious if it is a service or something else.
|
||||
|
||||
**为何?**像`Credit`这样的,服务名是名词,需要一个后缀。当不能明显分辨它是服务还是其它东西时,应该添加后缀。
|
||||
**为何?**像 `Credit` 这样的,服务名是名词,需要一个后缀。当不能明显分辨它是服务还是其它东西时,应该添加后缀。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -853,7 +853,7 @@ As always, strive for consistency.
|
|||
|
||||
**Do** put bootstrapping and platform logic for the app in a file named `main.ts`.
|
||||
|
||||
**坚持**把应用的引导程序和平台相关的逻辑放到名为`main.ts`的文件里。
|
||||
**坚持**把应用的引导程序和平台相关的逻辑放到名为 `main.ts` 的文件里。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -869,7 +869,7 @@ As always, strive for consistency.
|
|||
|
||||
**Avoid** putting app logic in `main.ts`. Instead, consider placing it in a component or service.
|
||||
|
||||
**避免**把应用逻辑放在`main.ts`中,而应放在组件或服务里。
|
||||
**避免**把应用逻辑放在 `main.ts` 中,而应放在组件或服务里。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -949,7 +949,7 @@ As always, strive for consistency.
|
|||
|
||||
**Do** use a hyphenated, lowercase element selector value (e.g. `admin-users`).
|
||||
|
||||
**坚持**使用带连字符的小写元素选择器值(例如`admin-users`)。
|
||||
**坚持**使用带连字符的小写元素选择器值(例如 `admin-users`)。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -959,7 +959,7 @@ As always, strive for consistency.
|
|||
For example, the prefix `toh` represents from **T**our **o**f **H**eroes and the prefix `admin` represents an admin feature area.
|
||||
|
||||
**坚持**为组件选择器添加自定义前缀。
|
||||
例如,`toh`前缀表示 **T**our **o**f **H**eroes(英雄指南),而前缀`admin表示管理特性区。
|
||||
例如,`toh` 前缀表示 **T**our **o**f **H**eroes(英雄指南),而前缀 `admin 表示管理特性区。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -1025,7 +1025,7 @@ For example, the prefix `toh` represents from **T**our **o**f **H**eroes and the
|
|||
|
||||
**Do** use a custom prefix for the selector of directives (e.g, the prefix `toh` from **T**our **o**f **H**eroes).
|
||||
|
||||
**坚持**为指令的选择器添加自定义前缀(例如前缀`toh`来自**T**our **o**f **H**eroes)。
|
||||
**坚持**为指令的选择器添加自定义前缀(例如前缀 `toh` 来自**T**our **o**f **H**eroes)。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -1191,7 +1191,7 @@ For example, the prefix `toh` represents from **T**our **o**f **H**eroes and the
|
|||
|
||||
**Do** name test specification files with a suffix of `.spec`.
|
||||
|
||||
**坚持**测试规格文件名添加`.spec`后缀。
|
||||
**坚持**测试规格文件名添加 `.spec` 后缀。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -1325,7 +1325,7 @@ For example, the prefix `toh` represents from **T**our **o**f **H**eroes and the
|
|||
|
||||
**Do** name end-to-end test specification files after the feature they test with a suffix of `.e2e-spec`.
|
||||
|
||||
**坚持**端到端测试规格文件和它们所测试的特性同名,添加`.e2e-spec`后缀。
|
||||
**坚持**端到端测试规格文件和它们所测试的特性同名,添加 `.e2e-spec` 后缀。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -1415,7 +1415,7 @@ For example, the prefix `toh` represents from **T**our **o**f **H**eroes and the
|
|||
|
||||
**Do** append the symbol name with the suffix `Module`.
|
||||
|
||||
**坚持**为符号名添加`Module`后缀
|
||||
**坚持**为符号名添加 `Module` 后缀
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -1423,7 +1423,7 @@ For example, the prefix `toh` represents from **T**our **o**f **H**eroes and the
|
|||
|
||||
**Do** give the file name the `.module.ts` extension.
|
||||
|
||||
**坚持**为文件名添加`.module.ts`扩展名。
|
||||
**坚持**为文件名添加 `.module.ts` 扩展名。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -1463,7 +1463,7 @@ For example, the prefix `toh` represents from **T**our **o**f **H**eroes and the
|
|||
|
||||
**Do** suffix a _RoutingModule_ class name with `RoutingModule`.
|
||||
|
||||
**坚持**为 *RoutingModule* 类名添加`RoutingModule`后缀。
|
||||
**坚持**为 *RoutingModule* 类名添加 `RoutingModule` 后缀。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -1471,7 +1471,7 @@ For example, the prefix `toh` represents from **T**our **o**f **H**eroes and the
|
|||
|
||||
**Do** end the filename of a _RoutingModule_ with `-routing.module.ts`.
|
||||
|
||||
**坚持**为 *RoutingModule* 的文件名添加`-routing.module.ts`后缀。
|
||||
**坚持**为 *RoutingModule* 的文件名添加 `-routing.module.ts` 后缀。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -1480,7 +1480,7 @@ For example, the prefix `toh` represents from **T**our **o**f **H**eroes and the
|
|||
**Why?** A `RoutingModule` is a module dedicated exclusively to configuring the Angular router.
|
||||
A consistent class and file name convention make these modules easy to spot and verify.
|
||||
|
||||
**为何?**`RoutingModule`是一种专门用来配置 Angular 路由器的模块。
|
||||
**为何?**`RoutingModule` 是一种专门用来配置 Angular 路由器的模块。
|
||||
“类名和文件名保持一致”的约定使这些模块易于发现和验证。
|
||||
|
||||
</div>
|
||||
|
@ -1695,7 +1695,7 @@ By convention, upper camel case indicates a constructable asset.
|
|||
|
||||
**Do** declare variables with `const` if their values should not change during the application lifetime.
|
||||
|
||||
**坚持**用`const`声明变量,除非它们的值在应用的生命周期内会发生变化。
|
||||
**坚持**用 `const` 声明变量,除非它们的值在应用的生命周期内会发生变化。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -1740,7 +1740,7 @@ an era before the modern IDEs that quickly reveal the `const` declaration.
|
|||
TypeScript prevents accidental reassignment.
|
||||
|
||||
**为何?** 把常量命名为大写蛇形命名法的传统源于现代 IDE 出现之前,
|
||||
以便阅读时可以快速发现那些`const`定义。
|
||||
以便阅读时可以快速发现那些 `const` 定义。
|
||||
TypeScript 本身就能够防止意外赋值。
|
||||
|
||||
</div>
|
||||
|
@ -1749,7 +1749,7 @@ TypeScript 本身就能够防止意外赋值。
|
|||
|
||||
**Do** tolerate _existing_ `const` variables that are spelled in UPPER_SNAKE_CASE.
|
||||
|
||||
**坚持**容许_现存的_`const`常量沿用大写蛇形命名法。
|
||||
**坚持**容许_现存的_`const` 常量沿用大写蛇形命名法。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -1794,7 +1794,7 @@ It is rarely worth the effort to change them at the risk of breaking existing co
|
|||
|
||||
**Consider** naming an interface without an `I` prefix.
|
||||
|
||||
**考虑**不要在接口名字前面加`I`前缀。
|
||||
**考虑**不要在接口名字前面加 `I` 前缀。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -1835,7 +1835,7 @@ discourage the `I` prefix.
|
|||
|
||||
**Why?** A class can act as an interface (use `implements` instead of `extends`).
|
||||
|
||||
**为何?**类可以作为接口使用(只是用`implements`代替`extends`而已)。
|
||||
**为何?**类可以作为接口使用(只是用 `implements` 代替 `extends` 而已)。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -1994,7 +1994,7 @@ Have a near-term view of implementation and a long-term vision. Start small but
|
|||
All of the app's code goes in a folder named `src`.
|
||||
All feature areas are in their own folder, with their own NgModule.
|
||||
|
||||
所有应用程序的源代码都放到名叫`src`的目录里。
|
||||
所有应用程序的源代码都放到名叫 `src` 的目录里。
|
||||
所有特性区都在自己的文件夹中,带有它们自己的 Angular 模块。
|
||||
|
||||
All content is one asset per file. Each component, service, and pipe is in its own file.
|
||||
|
@ -2003,7 +2003,7 @@ You didn't write them and you don't want them cluttering `src`.
|
|||
Use the naming conventions for files in this guide.
|
||||
|
||||
所有内容都遵循每个文件一个特性的原则。每个组件、服务和管道都在自己的文件里。
|
||||
所有第三方程序包保存到其它目录里,而不是`src`目录。
|
||||
所有第三方程序包保存到其它目录里,而不是 `src` 目录。
|
||||
你不会修改它们,所以不希望它们弄乱我们的应用程序。
|
||||
使用本指南介绍的文件命名约定。
|
||||
|
||||
|
@ -2026,7 +2026,7 @@ Use the naming conventions for files in this guide.
|
|||
keep the **F**lattest structure you can, and
|
||||
**T**ry to be DRY.
|
||||
|
||||
**坚持**组织应用的结构,达到这些目的:快速定位 (`L`ocate) 代码、一眼识别 (`I`dentify) 代码、 尽量保持扁平结构 (`F`lattest) 和尝试 (`T`ry) 遵循DRY (Do Not Repeat Yourself, 不重复自己) 原则。
|
||||
**坚持**组织应用的结构,达到这些目的:快速定位 (`L`ocate) 代码、一眼识别 (`I`dentify) 代码、 尽量保持扁平结构 (`F`lattest) 和尝试 (`T`ry) 遵循 DRY (Do Not Repeat Yourself, 不重复自己) 原则。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -2044,7 +2044,7 @@ keep the **F**lattest structure you can, and
|
|||
To confirm your intuition about a particular structure, ask:
|
||||
_can I quickly open and start work in all of the related files for this feature_?
|
||||
|
||||
**为何?**LIFT提供了一致的结构,它具有扩展性强、模块化的特性。因为容易快速锁定代码,提高了开发者的效率。
|
||||
**为何?**LIFT 提供了一致的结构,它具有扩展性强、模块化的特性。因为容易快速锁定代码,提高了开发者的效率。
|
||||
另外,检查应用结构是否合理的方法是问问自己:我们能快速打开与此特性有关的所有文件并开始工作吗?
|
||||
|
||||
</div>
|
||||
|
@ -2061,7 +2061,7 @@ _can I quickly open and start work in all of the related files for this feature_
|
|||
|
||||
#### Style 04-02
|
||||
|
||||
#### 风格04-02
|
||||
#### 风格 04-02
|
||||
|
||||
<div class="s-rule do">
|
||||
|
||||
|
@ -2178,7 +2178,7 @@ in a single file than as multiple files. Be wary of this loophole.
|
|||
|
||||
**Consider** configuring the IDE to hide distracting, irrelevant files such as generated `.js` and `.js.map` files.
|
||||
|
||||
**考虑**配置 IDE,以隐藏无关的文件,例如生成出来的`.js`文件和`.js.map`文件等。
|
||||
**考虑**配置 IDE,以隐藏无关的文件,例如生成出来的 `.js` 文件和 `.js.map` 文件等。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -2246,7 +2246,7 @@ But if something is not obvious or departs from a convention, then spell it out.
|
|||
|
||||
**为何?**虽然 DRY 很重要,但如果要以牺牲 LIFT 的其它原则为代价,那就不值得了。
|
||||
这也就是为什么它被称为 *T-DRY*。
|
||||
例如,把组件命名为`hero-view.component.html`是多余的,因为带有`.html`扩展名的文件显然就是一个视图 (view)。
|
||||
例如,把组件命名为 `hero-view.component.html` 是多余的,因为带有 `.html` 扩展名的文件显然就是一个视图 (view)。
|
||||
但如果它不那么显著,或不符合常规,就把它写出来。
|
||||
|
||||
</div>
|
||||
|
@ -2285,7 +2285,7 @@ But if something is not obvious or departs from a convention, then spell it out.
|
|||
|
||||
**Do** put all of the app's code in a folder named `src`.
|
||||
|
||||
**坚持**把所有源代码都放到名为`src`的目录里。
|
||||
**坚持**把所有源代码都放到名为 `src` 的目录里。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -2293,7 +2293,7 @@ But if something is not obvious or departs from a convention, then spell it out.
|
|||
|
||||
**Consider** creating a folder for a component when it has multiple accompanying files (`.ts`, `.html`, `.css` and `.spec`).
|
||||
|
||||
**坚持**如果组件具有多个伴隨文件 (`.ts`、`.html`、`.css`和`.spec`),就为它创建一个文件夹。
|
||||
**坚持**如果组件具有多个伴隨文件 (`.ts`、`.html`、`.css` 和 `.spec`),就为它创建一个文件夹。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -2748,7 +2748,7 @@ and more difficult in a flat structure.
|
|||
**Do** create an NgModule in the app's root folder,
|
||||
for example, in `/src/app`.
|
||||
|
||||
**坚持**在应用的根目录创建一个 Angular 模块(例如`/src/app`)。
|
||||
**坚持**在应用的根目录创建一个 Angular 模块(例如 `/src/app`)。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -2764,7 +2764,7 @@ for example, in `/src/app`.
|
|||
|
||||
**Consider** naming the root module `app.module.ts`.
|
||||
|
||||
**考虑**把根模块命名为`app.module.ts`。
|
||||
**考虑**把根模块命名为 `app.module.ts`。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -2808,7 +2808,7 @@ for example, a `Heroes` feature.
|
|||
**Do** place the feature module in the same named folder as the feature area;
|
||||
for example, in `app/heroes`.
|
||||
|
||||
**坚持**把特性模块放在与特性区同名的目录中(例如`app/heroes`)。
|
||||
**坚持**把特性模块放在与特性区同名的目录中(例如 `app/heroes`)。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -2817,7 +2817,7 @@ for example, in `app/heroes`.
|
|||
**Do** name the feature module file reflecting the name of the feature area
|
||||
and folder; for example, `app/heroes/heroes.module.ts`.
|
||||
|
||||
**坚持**特性模块的文件名应该能反映出特性区的名字和目录(例如`app/heroes/heroes.module.ts`)。
|
||||
**坚持**特性模块的文件名应该能反映出特性区的名字和目录(例如 `app/heroes/heroes.module.ts`)。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -2826,7 +2826,7 @@ and folder; for example, `app/heroes/heroes.module.ts`.
|
|||
**Do** name the feature module symbol reflecting the name of the feature
|
||||
area, folder, and file; for example, `app/heroes/heroes.module.ts` defines `HeroesModule`.
|
||||
|
||||
**坚持**特性模块的符号名应该能反映出特性区、目录和文件名(例如在`app/heroes/heroes.module.ts`中定义`HeroesModule`)。
|
||||
**坚持**特性模块的符号名应该能反映出特性区、目录和文件名(例如在 `app/heroes/heroes.module.ts` 中定义 `HeroesModule`)。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -2897,7 +2897,7 @@ area, folder, and file; for example, `app/heroes/heroes.module.ts` defines `Hero
|
|||
**Do** create a feature module named `SharedModule` in a `shared` folder;
|
||||
for example, `app/shared/shared.module.ts` defines `SharedModule`.
|
||||
|
||||
**坚持**在`shared`目录中创建名叫`SharedModule`的特性模块(例如在`app/shared/shared.module.ts`中定义`SharedModule`)。
|
||||
**坚持**在 `shared` 目录中创建名叫 `SharedModule` 的特性模块(例如在 `app/shared/shared.module.ts` 中定义 `SharedModule`)。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -2915,7 +2915,7 @@ items will be re-used and referenced by the components declared in other feature
|
|||
**Consider** using the name SharedModule when the contents of a shared
|
||||
module are referenced across the entire application.
|
||||
|
||||
**考虑**把可能在整个应用中到处引用的模块命名为SharedModule
|
||||
**考虑**把可能在整个应用中到处引用的模块命名为 SharedModule
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -2934,7 +2934,7 @@ in a particular feature module.
|
|||
**Do** import all modules required by the assets in the `SharedModule`;
|
||||
for example, `CommonModule` and `FormsModule`.
|
||||
|
||||
**坚持**在`SharedModule`中导入所有模块都需要的资产(例如`CommonModule`和`FormsModule`)。
|
||||
**坚持**在 `SharedModule` 中导入所有模块都需要的资产(例如 `CommonModule` 和 `FormsModule`)。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -2944,7 +2944,7 @@ for example, `CommonModule` and `FormsModule`.
|
|||
that may need features from another common module; for example,
|
||||
`ngFor` in `CommonModule`.
|
||||
|
||||
**为何?** `SharedModule`中包含的组件、指令和管道可能需要来自其它公共模块的特性(例如来自`CommonModule`中的`ngFor`指令)。
|
||||
**为何?** `SharedModule` 中包含的组件、指令和管道可能需要来自其它公共模块的特性(例如来自 `CommonModule` 中的 `ngFor` 指令)。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -2952,7 +2952,7 @@ that may need features from another common module; for example,
|
|||
|
||||
**Do** declare all components, directives, and pipes in the `SharedModule`.
|
||||
|
||||
**坚持**在`SharedModule`中声明所有组件、指令和管道。
|
||||
**坚持**在 `SharedModule` 中声明所有组件、指令和管道。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -2960,7 +2960,7 @@ that may need features from another common module; for example,
|
|||
|
||||
**Do** export all symbols from the `SharedModule` that other feature modules need to use.
|
||||
|
||||
**坚持**从`SharedModule`中导出其它特性模块所需的全部符号。
|
||||
**坚持**从 `SharedModule` 中导出其它特性模块所需的全部符号。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -2968,7 +2968,7 @@ that may need features from another common module; for example,
|
|||
|
||||
**Why?** `SharedModule` exists to make commonly used components, directives and pipes available for use in the templates of components in many other modules.
|
||||
|
||||
**为何?** `SharedModule`的存在,能让常用的组件、指令和管道在很多其它模块的组件模板中都自动可用。
|
||||
**为何?** `SharedModule` 的存在,能让常用的组件、指令和管道在很多其它模块的组件模板中都自动可用。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -2976,7 +2976,7 @@ that may need features from another common module; for example,
|
|||
|
||||
**Avoid** specifying app-wide singleton providers in a `SharedModule`. Intentional singletons are OK. Take care.
|
||||
|
||||
**避免**在`SharedModule`中指定应用级的单例服务提供商。如果是刻意要得到多个服务单例也行,不过还是要小心。
|
||||
**避免**在 `SharedModule` 中指定应用级的单例服务提供商。如果是刻意要得到多个服务单例也行,不过还是要小心。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -2994,7 +2994,7 @@ that may need features from another common module; for example,
|
|||
Yet there is a real danger of that happening if the `SharedModule` provides a service.
|
||||
|
||||
**为何?**对于单例服务,你不希望每个模块都有自己的实例。
|
||||
而如果`SharedModule`提供了一个服务,那就有可能发生这种情况。
|
||||
而如果 `SharedModule` 提供了一个服务,那就有可能发生这种情况。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -3132,7 +3132,7 @@ Yet there is a real danger of that happening if the `SharedModule` provides a se
|
|||
|
||||
#### Style 04-11
|
||||
|
||||
#### 风格04-11
|
||||
#### 风格 04-11
|
||||
|
||||
<div class="s-rule consider">
|
||||
|
||||
|
@ -3149,7 +3149,7 @@ to simplify the apparent structure of a feature module.
|
|||
Importing `CoreModule` into the root `AppModule` reduces its complexity
|
||||
and emphasizes its role as orchestrator of the application as a whole.
|
||||
|
||||
**坚持**把那些“只用一次”的类收集到`CoreModule`中,并对外隐藏它们的实现细节。简化的`AppModule`会导入`CoreModule`,并且把它作为整个应用的总指挥。
|
||||
**坚持**把那些“只用一次”的类收集到 `CoreModule` 中,并对外隐藏它们的实现细节。简化的 `AppModule` 会导入 `CoreModule`,并且把它作为整个应用的总指挥。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -3157,7 +3157,7 @@ and emphasizes its role as orchestrator of the application as a whole.
|
|||
|
||||
**Do** create a feature module named `CoreModule` in a `core` folder (e.g. `app/core/core.module.ts` defines `CoreModule`).
|
||||
|
||||
**坚持**在`core`目录下创建一个名叫`CoreModule`的特性模块(例如在`app/core/core.module.ts`中定义`CoreModule`)。
|
||||
**坚持**在 `core` 目录下创建一个名叫 `CoreModule` 的特性模块(例如在 `app/core/core.module.ts` 中定义 `CoreModule`)。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -3165,7 +3165,7 @@ and emphasizes its role as orchestrator of the application as a whole.
|
|||
|
||||
**Do** put a singleton service whose instance will be shared throughout the application in the `CoreModule` (e.g. `ExceptionService` and `LoggerService`).
|
||||
|
||||
**坚持**把要共享给整个应用的单例服务放进`CoreModule`中(例如`ExceptionService`和`LoggerService`)。
|
||||
**坚持**把要共享给整个应用的单例服务放进 `CoreModule` 中(例如 `ExceptionService` 和 `LoggerService`)。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -3173,7 +3173,7 @@ and emphasizes its role as orchestrator of the application as a whole.
|
|||
|
||||
**Do** import all modules required by the assets in the `CoreModule` (e.g. `CommonModule` and `FormsModule`).
|
||||
|
||||
**坚持**导入`CoreModule`中的资产所需要的全部模块(例如`CommonModule`和`FormsModule`)。
|
||||
**坚持**导入 `CoreModule` 中的资产所需要的全部模块(例如 `CommonModule` 和 `FormsModule`)。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -3181,7 +3181,7 @@ and emphasizes its role as orchestrator of the application as a whole.
|
|||
|
||||
**Why?** `CoreModule` provides one or more singleton services. Angular registers the providers with the app root injector, making a singleton instance of each service available to any component that needs them, whether that component is eagerly or lazily loaded.
|
||||
|
||||
**为何?** `CoreModule`提供了一个或多个单例服务。Angular使用应用的根注入器注册这些服务提供商,让每个服务的这个单例对象对所有需要它们的组件都是可用的,而不用管该组件是通过主动加载还是惰性加载的方式加载的。
|
||||
**为何?** `CoreModule` 提供了一个或多个单例服务。Angular 使用应用的根注入器注册这些服务提供商,让每个服务的这个单例对象对所有需要它们的组件都是可用的,而不用管该组件是通过主动加载还是惰性加载的方式加载的。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -3189,7 +3189,7 @@ and emphasizes its role as orchestrator of the application as a whole.
|
|||
|
||||
**Why?** `CoreModule` will contain singleton services. When a lazy loaded module imports these, it will get a new instance and not the intended app-wide singleton.
|
||||
|
||||
**为何?**`CoreModule`将包含一些单例服务。而如果是由惰性加载模块来导入这些服务,它就会得到一个新实例,而不是所期望的全应用级单例。
|
||||
**为何?**`CoreModule` 将包含一些单例服务。而如果是由惰性加载模块来导入这些服务,它就会得到一个新实例,而不是所期望的全应用级单例。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -3198,8 +3198,8 @@ and emphasizes its role as orchestrator of the application as a whole.
|
|||
**Do** gather application-wide, single use components in the `CoreModule`.
|
||||
Import it once (in the `AppModule`) when the app starts and never import it anywhere else. (e.g. `NavComponent` and `SpinnerComponent`).
|
||||
|
||||
**坚持**把应用级、只用一次的组件收集到`CoreModule`中。
|
||||
只在应用启动时从`AppModule`中导入它一次,以后再也不要导入它(例如`NavComponent`和`SpinnerComponent`)。
|
||||
**坚持**把应用级、只用一次的组件收集到 `CoreModule` 中。
|
||||
只在应用启动时从 `AppModule` 中导入它一次,以后再也不要导入它(例如 `NavComponent` 和 `SpinnerComponent`)。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -3209,7 +3209,7 @@ Import it once (in the `AppModule`) when the app starts and never import it anyw
|
|||
They are not imported elsewhere so they're not shared in that sense.
|
||||
Yet they're too big and messy to leave loose in the root folder.
|
||||
|
||||
**为何?**真实世界中的应用会有很多只用一次的组件(例如加载动画、消息浮层、模态框等),它们只会在`AppComponent`的模板中出现。
|
||||
**为何?**真实世界中的应用会有很多只用一次的组件(例如加载动画、消息浮层、模态框等),它们只会在 `AppComponent` 的模板中出现。
|
||||
不会在其它地方导入它们,所以没有共享的价值。
|
||||
然而它们又太大了,放在根目录中就会显得乱七八糟的。
|
||||
|
||||
|
@ -3219,7 +3219,7 @@ Yet they're too big and messy to leave loose in the root folder.
|
|||
|
||||
**Avoid** importing the `CoreModule` anywhere except in the `AppModule`.
|
||||
|
||||
**避免**在`AppModule`之外的任何地方导入`CoreModule`。
|
||||
**避免**在 `AppModule` 之外的任何地方导入 `CoreModule`。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -3227,7 +3227,7 @@ Yet they're too big and messy to leave loose in the root folder.
|
|||
|
||||
**Why?** A lazily loaded feature module that directly imports the `CoreModule` will make its own copy of services and likely have undesirable results.
|
||||
|
||||
**为何?**如果惰性加载的特性模块直接导入`CoreModule`,就会创建它自己的服务副本,并导致意料之外的后果。
|
||||
**为何?**如果惰性加载的特性模块直接导入 `CoreModule`,就会创建它自己的服务副本,并导致意料之外的后果。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -3235,7 +3235,7 @@ Yet they're too big and messy to leave loose in the root folder.
|
|||
|
||||
**Why?** An eagerly loaded feature module already has access to the `AppModule`'s injector, and thus the `CoreModule`'s services.
|
||||
|
||||
**为何?**主动加载的特性模块已经准备好了访问`AppModule`的注入器,因此也能取得`CoreModule`中的服务。
|
||||
**为何?**主动加载的特性模块已经准备好了访问 `AppModule` 的注入器,因此也能取得 `CoreModule` 中的服务。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -3243,7 +3243,7 @@ Yet they're too big and messy to leave loose in the root folder.
|
|||
|
||||
**Do** export all symbols from the `CoreModule` that the `AppModule` will import and make available for other feature modules to use.
|
||||
|
||||
**坚持**从`CoreModule`中导出`AppModule`需导入的所有符号,使它们在所有特性模块中可用。
|
||||
**坚持**从 `CoreModule` 中导出 `AppModule` 需导入的所有符号,使它们在所有特性模块中可用。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -3251,7 +3251,7 @@ Yet they're too big and messy to leave loose in the root folder.
|
|||
|
||||
**Why?** `CoreModule` exists to make commonly used singleton services available for use in the many other modules.
|
||||
|
||||
**为何?**`CoreModule`的存在就让常用的单例服务在所有其它模块中可用。
|
||||
**为何?**`CoreModule` 的存在就让常用的单例服务在所有其它模块中可用。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -3263,7 +3263,7 @@ Yet there is a real danger of that happening accidentally if the `CoreModule` pr
|
|||
|
||||
**为何?**你希望整个应用都使用这个单例服务。
|
||||
你不希望每个模块都有这个单例服务的单独的实例。
|
||||
然而,如果`CoreModule`中提供了一个服务,就可能偶尔导致这种后果。
|
||||
然而,如果 `CoreModule` 中提供了一个服务,就可能偶尔导致这种后果。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -3430,10 +3430,10 @@ Yet there is a real danger of that happening accidentally if the `CoreModule` pr
|
|||
`AppModule` delegates to imported modules rather than doing work.
|
||||
`AppModule` is focused on its main task, orchestrating the app as a whole.
|
||||
|
||||
`AppModule`变得更小了,因为很多应用根部的类都被移到了其它模块中。
|
||||
`AppModule`变得稳定了,因为你将会往其它模块中添加特性组件和服务提供商,而不是这个`AppModule`。
|
||||
`AppModule`把工作委托给了导入的模块,而不是亲力亲为。
|
||||
`AppModule`聚焦在它自己的主要任务上:作为整个应用的总指挥。
|
||||
`AppModule` 变得更小了,因为很多应用根部的类都被移到了其它模块中。
|
||||
`AppModule` 变得稳定了,因为你将会往其它模块中添加特性组件和服务提供商,而不是这个 `AppModule`。
|
||||
`AppModule` 把工作委托给了导入的模块,而不是亲力亲为。
|
||||
`AppModule` 聚焦在它自己的主要任务上:作为整个应用的总指挥。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -3445,7 +3445,7 @@ Yet there is a real danger of that happening accidentally if the `CoreModule` pr
|
|||
|
||||
### Prevent re-import of the core module
|
||||
|
||||
### 防止多次导入`CoreModule`
|
||||
### 防止多次导入 `CoreModule`
|
||||
|
||||
#### Style 04-12
|
||||
|
||||
|
@ -3453,13 +3453,13 @@ Yet there is a real danger of that happening accidentally if the `CoreModule` pr
|
|||
|
||||
Only the root `AppModule` should import the `CoreModule`.
|
||||
|
||||
应该只有`AppModule`才允许导入`CoreModule`。
|
||||
应该只有 `AppModule` 才允许导入 `CoreModule`。
|
||||
|
||||
<div class="s-rule do">
|
||||
|
||||
**Do** guard against reimporting of `CoreModule` and fail fast by adding guard logic.
|
||||
|
||||
**坚持**防范多次导入`CoreModule`,并通过添加守卫逻辑来尽快失败。
|
||||
**坚持**防范多次导入 `CoreModule`,并通过添加守卫逻辑来尽快失败。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -3467,7 +3467,7 @@ Only the root `AppModule` should import the `CoreModule`.
|
|||
|
||||
**Why?** Guards against reimporting of the `CoreModule`.
|
||||
|
||||
**为何?**守卫可以阻止对`CoreModule`的多次导入。
|
||||
**为何?**守卫可以阻止对 `CoreModule` 的多次导入。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -3573,7 +3573,7 @@ A typical *lazy loaded folder* contains a *routing component*, its child compone
|
|||
|
||||
#### Style 05-02
|
||||
|
||||
#### 风格05-02
|
||||
#### 风格 05-02
|
||||
|
||||
<div class="s-rule do">
|
||||
|
||||
|
@ -3636,7 +3636,7 @@ They display content.
|
|||
Developers place components on the page as they would native HTML elements and web components.
|
||||
|
||||
**为何?**组件有很多包含 HTML 以及可选 Angular 模板语法的模板。
|
||||
它们显示内容。开发人员会把组件像原生HTML元素和WebComponents一样放进页面中。
|
||||
它们显示内容。开发人员会把组件像原生 HTML 元素和 WebComponents 一样放进页面中。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -3703,7 +3703,7 @@ There are a few cases where you give a component an attribute, such as when you
|
|||
|
||||
**Do** name the template file `[component-name].component.html`, where [component-name] is the component name.
|
||||
|
||||
**坚持**把模板文件命名为`[component-name].component.html`,其中,[component-name] 是组件名。
|
||||
**坚持**把模板文件命名为 `[component-name].component.html`,其中,[component-name] 是组件名。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -3711,7 +3711,7 @@ There are a few cases where you give a component an attribute, such as when you
|
|||
|
||||
**Do** name the style file `[component-name].component.css`, where [component-name] is the component name.
|
||||
|
||||
**坚持**把样式文件命名为`[component-name].component.css`,其中,[component-name] 是组件名。
|
||||
**坚持**把样式文件命名为 `[component-name].component.css`,其中,[component-name] 是组件名。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -3719,7 +3719,7 @@ There are a few cases where you give a component an attribute, such as when you
|
|||
|
||||
**Do** specify _component-relative_ URLs, prefixed with `./`.
|
||||
|
||||
**坚持**指定*相对于模块的* URL ,给它加上`./`前缀。
|
||||
**坚持**指定*相对于模块的* URL ,给它加上 `./` 前缀。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -3738,7 +3738,7 @@ The Angular TypeScript Language Service (forthcoming) promises to overcome this
|
|||
in those editors that support it; it won't help with CSS styles.
|
||||
|
||||
**为何?**在多数编辑器中,编写内联的模板和样式表时都无法使用语法提示和代码片段功能。
|
||||
Angular的TypeScript语言服务(即将到来)可以帮助那些编辑器在编写HTML模板时克服这一缺陷,但对CSS样式没有帮助。
|
||||
Angular 的 TypeScript 语言服务(即将到来)可以帮助那些编辑器在编写 HTML 模板时克服这一缺陷,但对 CSS 样式没有帮助。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -3746,7 +3746,7 @@ Angular的TypeScript语言服务(即将到来)可以帮助那些编辑器在
|
|||
|
||||
**Why?** A _component relative_ URL requires no change when you move the component files, as long as the files stay together.
|
||||
|
||||
**为何?**当你移动组件文件时,相对于组件的URL不需要修改,因为这些文件始终会在一起。
|
||||
**为何?**当你移动组件文件时,相对于组件的 URL 不需要修改,因为这些文件始终会在一起。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -3754,7 +3754,7 @@ Angular的TypeScript语言服务(即将到来)可以帮助那些编辑器在
|
|||
|
||||
**Why?** The `./` prefix is standard syntax for relative URLs; don't depend on Angular's current ability to do without that prefix.
|
||||
|
||||
**为何?**`./`前缀是相对URL的标准语法,不必依赖Angular的特殊处理,如果没有前缀则不行。
|
||||
**为何?**`./` 前缀是相对 URL 的标准语法,不必依赖 Angular 的特殊处理,如果没有前缀则不行。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -3797,7 +3797,7 @@ Angular的TypeScript语言服务(即将到来)可以帮助那些编辑器在
|
|||
**Do** use the `@Input()` and `@Output()` class decorators instead of the `inputs` and `outputs` properties of the
|
||||
`@Directive` and `@Component` metadata:
|
||||
|
||||
**坚持** 使用`@Input()`和`@Output()`,而非`@Directive`和`@Component`装饰器的`inputs`和`outputs`属性:
|
||||
**坚持** 使用 `@Input()` 和 `@Output()`,而非 `@Directive` 和 `@Component` 装饰器的 `inputs` 和 `outputs` 属性:
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -3805,7 +3805,7 @@ Angular的TypeScript语言服务(即将到来)可以帮助那些编辑器在
|
|||
|
||||
**Consider** placing `@Input()` or `@Output()` on the same line as the property it decorates.
|
||||
|
||||
**坚持**把`@Input()`或者`@Output()`放到所装饰的属性的同一行。
|
||||
**坚持**把 `@Input()` 或者 `@Output()` 放到所装饰的属性的同一行。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -3822,7 +3822,7 @@ Angular的TypeScript语言服务(即将到来)可以帮助那些编辑器在
|
|||
**Why?** If you ever need to rename the property or event name associated with
|
||||
`@Input` or `@Output`, you can modify it in a single place.
|
||||
|
||||
**为何?** 如果需要重命名与`@Input`或者`@Output`关联的属性或事件名,你可以在一个位置修改。
|
||||
**为何?** 如果需要重命名与 `@Input` 或者 `@Output` 关联的属性或事件名,你可以在一个位置修改。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -4049,7 +4049,7 @@ helps instantly identify which members of the component serve which purpose.
|
|||
|
||||
**Do** name events without the prefix `on`.
|
||||
|
||||
**坚持**命名事件时,不要带前缀`on`。
|
||||
**坚持**命名事件时,不要带前缀 `on`。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -4057,7 +4057,7 @@ helps instantly identify which members of the component serve which purpose.
|
|||
|
||||
**Do** name event handler methods with the prefix `on` followed by the event name.
|
||||
|
||||
**坚持**把事件处理器方法命名为`on`前缀之后紧跟着事件名。
|
||||
**坚持**把事件处理器方法命名为 `on` 前缀之后紧跟着事件名。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -4073,7 +4073,7 @@ helps instantly identify which members of the component serve which purpose.
|
|||
|
||||
**Why?** Angular allows for an [alternative syntax](guide/template-syntax#binding-syntax) `on-*`. If the event itself was prefixed with `on` this would result in an `on-onEvent` binding expression.
|
||||
|
||||
**为何?**Angular 允许[另一种备选语法](guide/template-syntax#binding-syntax) `on-*`。如果事件的名字本身带有前缀`on`,那么绑定的表达式可能是`on-onEvent`。
|
||||
**为何?**Angular 允许[另一种备选语法](guide/template-syntax#binding-syntax) `on-*`。如果事件的名字本身带有前缀 `on`,那么绑定的表达式可能是 `on-onEvent`。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -4212,7 +4212,7 @@ helps instantly identify which members of the component serve which purpose.
|
|||
**Consider** preferring the `@HostListener` and `@HostBinding` to the
|
||||
`host` property of the `@Directive` and `@Component` decorators.
|
||||
|
||||
**考虑**优先使用`@HostListener`和`@HostBinding`,而不是`@Directive`和`@Component`装饰器的`host`属性。
|
||||
**考虑**优先使用 `@HostListener` 和 `@HostBinding`,而不是 `@Directive` 和 `@Component` 装饰器的 `host` 属性。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -4231,8 +4231,8 @@ can be modified only in a single place—in the directive's class.
|
|||
If you use the `host` metadata property, you must modify both the property/method declaration in the
|
||||
directive's class and the metadata in the decorator associated with the directive.
|
||||
|
||||
**为何?**对于关联到`@HostBinding`的属性或关联到`@HostListener`的方法,要修改时,只需在指令类中的一个地方修改。
|
||||
如果使用元数据属性`host`,你就得在组件类中修改属性声明的同时修改相关的元数据。
|
||||
**为何?**对于关联到 `@HostBinding` 的属性或关联到 `@HostListener` 的方法,要修改时,只需在指令类中的一个地方修改。
|
||||
如果使用元数据属性 `host`,你就得在组件类中修改属性声明的同时修改相关的元数据。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -4242,13 +4242,13 @@ directive's class and the metadata in the decorator associated with the directiv
|
|||
|
||||
Compare with the less preferred `host` metadata alternative.
|
||||
|
||||
与不推荐的方式(`host`元数据)比较一下。
|
||||
与不推荐的方式(`host` 元数据)比较一下。
|
||||
|
||||
<div class="s-why-last">
|
||||
|
||||
**Why?** The `host` metadata is only one term to remember and doesn't require extra ES imports.
|
||||
|
||||
**为何?**`host`元数据只是一个便于记忆的名字而已,并不需要额外的 ES 导入。
|
||||
**为何?**`host` 元数据只是一个便于记忆的名字而已,并不需要额外的 ES 导入。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -4433,7 +4433,7 @@ that instance is shared and available to all child components of that top level
|
|||
|
||||
**Do** use the `@Injectable()` class decorator instead of the `@Inject` parameter decorator when using types as tokens for the dependencies of a service.
|
||||
|
||||
**坚持**当使用类型作为令牌来注入服务的依赖时,使用`@Injectable()`类装饰器,而非`@Inject()`参数装饰器。
|
||||
**坚持**当使用类型作为令牌来注入服务的依赖时,使用 `@Injectable()` 类装饰器,而非 `@Inject()` 参数装饰器。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -4450,7 +4450,7 @@ dependencies based on the declared types of that service's constructor parameter
|
|||
|
||||
**Why?** When a service accepts only dependencies associated with type tokens, the `@Injectable()` syntax is much less verbose compared to using `@Inject()` on each individual constructor parameter.
|
||||
|
||||
**为何?**当服务只接受类型令牌相关的依赖时,比起在每个构造函数参数上使用`@Inject()`,`@Injectable()`的语法简洁多了。
|
||||
**为何?**当服务只接受类型令牌相关的依赖时,比起在每个构造函数参数上使用 `@Inject()`,`@Injectable()` 的语法简洁多了。
|
||||
|
||||
</div>
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -5,26 +5,26 @@
|
|||
TypeScript is a primary language for Angular application development.
|
||||
It is a superset of JavaScript with design-time support for type safety and tooling.
|
||||
|
||||
TypeScript是Angular应用开发中使用的主语言。
|
||||
它是JavaScript的“方言”之一,为类型安全和工具化而做了设计期支持。
|
||||
TypeScript 是 Angular 应用开发中使用的主语言。
|
||||
它是 JavaScript 的“方言”之一,为类型安全和工具化而做了设计期支持。
|
||||
|
||||
Browsers can't execute TypeScript directly. Typescript must be "transpiled" into JavaScript using the *tsc* compiler,
|
||||
which requires some configuration.
|
||||
|
||||
浏览器不能直接执行TypeScript。它得先用*tsc*编译器转译(transpile)成JavaScript,而且编译器需要进行一些配置。
|
||||
浏览器不能直接执行 TypeScript。它得先用*tsc*编译器转译(transpile)成 JavaScript,而且编译器需要进行一些配置。
|
||||
|
||||
This page covers some aspects of TypeScript configuration and the TypeScript environment
|
||||
that are important to Angular developers, including details about the following files:
|
||||
|
||||
本页面会涵盖TypeScript配置与环境的某些方面,这些对Angular开发者是很重要的。具体来说包括下列文件:
|
||||
本页面会涵盖 TypeScript 配置与环境的某些方面,这些对 Angular 开发者是很重要的。具体来说包括下列文件:
|
||||
|
||||
* [tsconfig.json](guide/typescript-configuration#tsconfig)—TypeScript compiler configuration.
|
||||
|
||||
[tsconfig.json](guide/typescript-configuration#tsconfig) - TypeScript编译器配置。
|
||||
[tsconfig.json](guide/typescript-configuration#tsconfig) - TypeScript 编译器配置。
|
||||
|
||||
* [typings](guide/typescript-configuration#typings)—TypesScript declaration files.
|
||||
|
||||
[typings](guide/typescript-configuration#typings) - TypesScript类型声明文件。
|
||||
[typings](guide/typescript-configuration#typings) - TypesScript 类型声明文件。
|
||||
|
||||
{@a tsconfig}
|
||||
|
||||
|
@ -35,27 +35,27 @@ that are important to Angular developers, including details about the following
|
|||
Typically, you add a TypeScript configuration file called `tsconfig.json` to your project to
|
||||
guide the compiler as it generates JavaScript files.
|
||||
|
||||
我们通常会往项目中加入一个TypeScript配置文件(`tsconfig.json`),来指导编译器如何生成JavaScript文件。
|
||||
我们通常会往项目中加入一个 TypeScript 配置文件(`tsconfig.json`),来指导编译器如何生成 JavaScript 文件。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
For details about `tsconfig.json`, see the official
|
||||
[TypeScript wiki](http://www.typescriptlang.org/docs/handbook/tsconfig-json.html).
|
||||
|
||||
要了解关于`tsconfig.json`的详情,请参阅官方提供的
|
||||
要了解关于 `tsconfig.json` 的详情,请参阅官方提供的
|
||||
[TypeScript wiki](http://www.typescriptlang.org/docs/handbook/tsconfig-json.html)。
|
||||
|
||||
</div>
|
||||
|
||||
The [Setup](guide/setup) guide uses the following `tsconfig.json`:
|
||||
|
||||
我们在[搭建本地开发环境](guide/setup)中创建过如下的`tsconfig.json`:
|
||||
我们在[搭建本地开发环境](guide/setup)中创建过如下的 `tsconfig.json`:
|
||||
|
||||
<code-example path="quickstart/src/tsconfig.1.json" title="tsconfig.json" linenums="false"></code-example>
|
||||
|
||||
This file contains options and flags that are essential for Angular applications.
|
||||
|
||||
该文件中的选项和标志是写Angular应用程序的基础。
|
||||
该文件中的选项和标志是写 Angular 应用程序的基础。
|
||||
|
||||
{@a noImplicitAny}
|
||||
|
||||
|
@ -67,7 +67,7 @@ TypeScript developers disagree about whether the `noImplicitAny` flag should be
|
|||
There is no correct answer and you can change the flag later.
|
||||
But your choice now can make a difference in larger projects, so it merits discussion.
|
||||
|
||||
TypeScript开发者们在`noImplicitAny`标志应该是`true`还是`false`上存在分歧。
|
||||
TypeScript 开发者们在 `noImplicitAny` 标志应该是 `true` 还是 `false` 上存在分歧。
|
||||
这没有标准答案,我们以后还可以修改这个标志。
|
||||
但是我们的选择会在大项目中产生显著差异,所以它值得讨论一番。
|
||||
|
||||
|
@ -75,8 +75,8 @@ When the `noImplicitAny` flag is `false` (the default), and if
|
|||
the compiler cannot infer the variable type based on how it's used,
|
||||
the compiler silently defaults the type to `any`. That's what is meant by *implicit `any`*.
|
||||
|
||||
当`noImplicitAny`标志是`false`(默认值)时,
|
||||
如果编译器无法根据变量的用途推断出变量的类型,它就会悄悄的把变量类型默认为`any`。这就是*隐式`any`*的含义。
|
||||
当 `noImplicitAny` 标志是 `false`(默认值)时,
|
||||
如果编译器无法根据变量的用途推断出变量的类型,它就会悄悄的把变量类型默认为 `any`。这就是*隐式 `any`*的含义。
|
||||
|
||||
The documentation setup sets the `noImplicitAny` flag to `true`.
|
||||
When the `noImplicitAny` flag is `true` and the TypeScript compiler cannot infer
|
||||
|
@ -84,20 +84,20 @@ the type, it still generates the JavaScript files, but it also **reports an erro
|
|||
Many seasoned developers prefer this stricter setting because type checking catches more
|
||||
unintentional errors at compile time.
|
||||
|
||||
本文档在环境搭建时将`noImplicitAny`标志设置为`true`。
|
||||
当`noImplicitAny`标志是`true`并且TypeScript编译器无法推断出类型时,它仍然会生成JavaScript文件。
|
||||
本文档在环境搭建时将 `noImplicitAny` 标志设置为 `true`。
|
||||
当 `noImplicitAny` 标志是 `true` 并且 TypeScript 编译器无法推断出类型时,它仍然会生成 JavaScript 文件。
|
||||
但是它也会**报告一个错误**。
|
||||
很多饱经沧桑的程序员更喜欢这种严格的设置,因为类型检查能在编译期间捕获更多意外错误。
|
||||
|
||||
You can set a variable's type to `any` even when the `noImplicitAny` flag is `true`.
|
||||
|
||||
即使`noImplicitAny`标志被设置成了`true`,你也可以把变量的类型设置为`any`。
|
||||
即使 `noImplicitAny` 标志被设置成了 `true`,你也可以把变量的类型设置为 `any`。
|
||||
|
||||
When the `noImplicitAny` flag is `true`, you may get *implicit index errors* as well.
|
||||
Most developers feel that *this particular error* is more annoying than helpful.
|
||||
You can suppress them with the following additional flag:
|
||||
|
||||
如果我们把`noImplicitAny`标志设置为了`true`,我们可能会得到*隐式索引错*。
|
||||
如果我们把 `noImplicitAny` 标志设置为了 `true`,我们可能会得到*隐式索引错*。
|
||||
大多数程序员可能觉得*这种错误*是个烦恼而不是助力。
|
||||
我们可以使用另一个标志来禁止它们。
|
||||
|
||||
|
@ -109,43 +109,43 @@ You can suppress them with the following additional flag:
|
|||
|
||||
The documentation setup sets this flag to `true` as well.
|
||||
|
||||
本文档在环境搭建时将`noImplicitAny`标志设置为`true`。
|
||||
本文档在环境搭建时将 `noImplicitAny` 标志设置为 `true`。
|
||||
|
||||
{@a typings}
|
||||
|
||||
## TypeScript Typings
|
||||
|
||||
## TypeScript类型定义(typings)
|
||||
## TypeScript 类型定义(typings)
|
||||
|
||||
Many JavaScript libraries, such as jQuery, the Jasmine testing library, and Angular,
|
||||
extend the JavaScript environment with features and syntax
|
||||
that the TypeScript compiler doesn't recognize natively.
|
||||
When the compiler doesn't recognize something, it throws an error.
|
||||
|
||||
很多JavaScript库,比如jQuery、Jasmine测试库和Angular,会通过新的特性和语法来扩展JavaScript环境。
|
||||
而TypeScript编译器并不能原生的识别它们。
|
||||
很多 JavaScript 库,比如 jQuery、Jasmine 测试库和 Angular,会通过新的特性和语法来扩展 JavaScript 环境。
|
||||
而 TypeScript 编译器并不能原生的识别它们。
|
||||
当编译器不能识别时,它就会抛出一个错误。
|
||||
|
||||
Use [TypeScript type definition files](https://www.typescriptlang.org/docs/handbook/writing-declaration-files.html)—`d.ts files`—to tell the compiler about the libraries you load.
|
||||
|
||||
我们可以使用[TypeScript类型定义文件](https://www.typescriptlang.org/docs/handbook/writing-declaration-files.html)
|
||||
—— `.d.ts`文件 —— 来告诉编译器要加载的库的类型定义。
|
||||
我们可以使用[TypeScript 类型定义文件](https://www.typescriptlang.org/docs/handbook/writing-declaration-files.html)
|
||||
—— `.d.ts` 文件 —— 来告诉编译器要加载的库的类型定义。
|
||||
|
||||
TypeScript-aware editors leverage these same definition files to display type information about library features.
|
||||
|
||||
TypeScript敏感的编辑器借助这些定义文件来显示这些库中各个特性的类型定义。
|
||||
TypeScript 敏感的编辑器借助这些定义文件来显示这些库中各个特性的类型定义。
|
||||
|
||||
Many libraries include definition files in their npm packages where both the TypeScript compiler and editors
|
||||
can find them. Angular is one such library.
|
||||
The `node_modules/@angular/core/` folder of any Angular application contains several `d.ts` files that describe parts of Angular.
|
||||
|
||||
很多库在自己的npm包中都包含了它们的类型定义文件,TypeScript编译器和编辑器都能找到它们。Angular库也是这样的。
|
||||
任何Angular应用程序的`node_modules/@angular/core/`目录下,都包含几个`d.ts`文件,它们描述了Angular的各个部分。
|
||||
很多库在自己的 npm 包中都包含了它们的类型定义文件,TypeScript 编译器和编辑器都能找到它们。Angular 库也是这样的。
|
||||
任何 Angular 应用程序的 `node_modules/@angular/core/` 目录下,都包含几个 `d.ts` 文件,它们描述了 Angular 的各个部分。
|
||||
|
||||
**You need do nothing to get *typings* files for library packages that include `d.ts` files.
|
||||
Angular packages include them already.**
|
||||
|
||||
**我们不需要为那些包含了`d.ts`文件的库获取*类型定义*文件 —— Angular的所有包都是如此。**
|
||||
**我们不需要为那些包含了 `d.ts` 文件的库获取*类型定义*文件 —— Angular 的所有包都是如此。**
|
||||
|
||||
### lib.d.ts
|
||||
|
||||
|
@ -153,17 +153,17 @@ Angular packages include them already.**
|
|||
|
||||
TypeScript includes a special declaration file called `lib.d.ts`. This file contains the ambient declarations for various common JavaScript constructs present in JavaScript runtimes and the DOM.
|
||||
|
||||
TypeScript带有一个特殊的声明文件,名为`lib.d.ts`。该文件包含了JavaScript运行库和DOM的各种常用JavaScript环境声明。
|
||||
TypeScript 带有一个特殊的声明文件,名为 `lib.d.ts`。该文件包含了 JavaScript 运行库和 DOM 的各种常用 JavaScript 环境声明。
|
||||
|
||||
Based on the `--target`, TypeScript adds _additional_ ambient declarations
|
||||
like `Promise` if the target is `es6`.
|
||||
|
||||
基于`--target`,TypeScript添加*额外*的环境声明,例如如果目标为`es6`时将添加`Promise`。
|
||||
基于 `--target`,TypeScript 添加*额外*的环境声明,例如如果目标为 `es6` 时将添加 `Promise`。
|
||||
|
||||
Since the QuickStart is targeting `es5`, you can override the
|
||||
list of declaration files to be included:
|
||||
|
||||
因为《快速上手》的目标为`es5`,所以我们可以重写声明文件列表来包含:
|
||||
因为《快速上手》的目标为 `es5`,所以我们可以重写声明文件列表来包含:
|
||||
|
||||
<code-example format=".">
|
||||
|
||||
|
@ -173,7 +173,7 @@ list of declaration files to be included:
|
|||
|
||||
Thanks to that, you have all the `es6` typings even when targeting `es5`.
|
||||
|
||||
得益于这项设置,即使编译目标设置为`es5`,我们也能获得所有的`es6`类型信息。
|
||||
得益于这项设置,即使编译目标设置为 `es5`,我们也能获得所有的 `es6` 类型信息。
|
||||
|
||||
### Installable typings files
|
||||
|
||||
|
@ -183,19 +183,19 @@ Many libraries—jQuery, Jasmine, and Lodash among them—do *not* inclu
|
|||
Fortunately, either their authors or community contributors have created separate `d.ts` files for these libraries and
|
||||
published them in well-known locations.
|
||||
|
||||
遗憾的是,很多库 —— jQuery、Jasmine和Lodash等库 —— 都*没有*在它们自己的npm包中包含`d.ts`文件。
|
||||
幸运的是,它们的作者或社区中的贡献者已经为这些库创建了独立的`d.ts`文件,并且把它们发布到了一个众所周知的位置。
|
||||
遗憾的是,很多库 —— jQuery、Jasmine 和 Lodash 等库 —— 都*没有*在它们自己的 npm 包中包含 `d.ts` 文件。
|
||||
幸运的是,它们的作者或社区中的贡献者已经为这些库创建了独立的 `d.ts` 文件,并且把它们发布到了一个众所周知的位置。
|
||||
|
||||
You can install these typings via `npm` using the
|
||||
[`@types/*` scoped package](http://www.typescriptlang.org/docs/handbook/declaration-files/consumption.html)
|
||||
and Typescript, starting at 2.0, automatically recognizes them.
|
||||
|
||||
我们还可以通过`npm`来使用[`@types/*`范围化包](http://www.typescriptlang.org/docs/handbook/declaration-files/consumption.html)来安装这些类型信息,
|
||||
而TypeScript自从2.0开始,可以自动识别它们。
|
||||
我们还可以通过 `npm` 来使用[`@types/*` 范围化包](http://www.typescriptlang.org/docs/handbook/declaration-files/consumption.html)来安装这些类型信息,
|
||||
而 TypeScript 自从 2.0 开始,可以自动识别它们。
|
||||
|
||||
For instance, to install typings for `jasmine` you could do `npm install @types/jasmine --save-dev`.
|
||||
|
||||
比如,要安装`jasmine`的类型信息,我们可以执行`npm install @types/jasmine --save-dev`。
|
||||
比如,要安装 `jasmine` 的类型信息,我们可以执行 `npm install @types/jasmine --save-dev`。
|
||||
|
||||
QuickStart identifies two *typings*, or `d.ts`, files:
|
||||
|
||||
|
@ -203,7 +203,7 @@ QuickStart identifies two *typings*, or `d.ts`, files:
|
|||
|
||||
* [jasmine](http://jasmine.github.io/) typings for the Jasmine test framework.
|
||||
|
||||
[jasmine](http://jasmine.github.io/)是Jasmine测试框架的类型定义
|
||||
[jasmine](http://jasmine.github.io/)是 Jasmine 测试框架的类型定义
|
||||
|
||||
* [node](https://www.npmjs.com/package/@types/node) for code that references objects in the *nodejs* environment;
|
||||
you can view an example in the [webpack](guide/webpack) page.
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -46,8 +46,8 @@ The text in quotes to the right of the equals sign
|
|||
is the **template statement**, which responds
|
||||
to the click event by calling the component's `onClickMe` method.
|
||||
|
||||
等号左边的`(click)`表示把按钮的点击事件作为**绑定目标**。
|
||||
等号右边引号中的文本是**模板语句**,通过调用组件的`onClickMe`方法来响应这个点击事件。
|
||||
等号左边的 `(click)` 表示把按钮的点击事件作为**绑定目标**。
|
||||
等号右边引号中的文本是**模板语句**,通过调用组件的 `onClickMe` 方法来响应这个点击事件。
|
||||
|
||||
When writing a binding, be aware of a template statement's **execution context**.
|
||||
The identifiers in a template statement belong to a specific context object,
|
||||
|
@ -65,7 +65,7 @@ The example above shows a single line of HTML, but that HTML belongs to a larger
|
|||
|
||||
When the user clicks the button, Angular calls the `onClickMe` method from `ClickMeComponent`.
|
||||
|
||||
当用户点击按钮时,Angular 调用`ClickMeComponent`的`onClickMe`方法。
|
||||
当用户点击按钮时,Angular 调用 `ClickMeComponent` 的 `onClickMe` 方法。
|
||||
|
||||
## Get user input from the $event object
|
||||
|
||||
|
@ -75,11 +75,11 @@ DOM events carry a payload of information that may be useful to the component.
|
|||
This section shows how to bind to the `keyup` event of an input box to get the user's input after each keystroke.
|
||||
|
||||
DOM 事件可以携带可能对组件有用的信息。
|
||||
本节将展示如何绑定输入框的`keyup`事件,在每个敲击键盘时获取用户输入。
|
||||
本节将展示如何绑定输入框的 `keyup` 事件,在每个敲击键盘时获取用户输入。
|
||||
|
||||
The following code listens to the `keyup` event and passes the entire event payload (`$event`) to the component event handler.
|
||||
|
||||
下面的代码监听`keyup`事件,并将整个事件载荷 (`$event`) 传递给组件的事件处理器。
|
||||
下面的代码监听 `keyup` 事件,并将整个事件载荷 (`$event`) 传递给组件的事件处理器。
|
||||
|
||||
<code-example path="user-input/src/app/keyup.components.ts" region="key-up-component-1-template" title="src/app/keyup.components.ts (template v.1)" linenums="false">
|
||||
|
||||
|
@ -88,8 +88,8 @@ The following code listens to the `keyup` event and passes the entire event payl
|
|||
When a user presses and releases a key, the `keyup` event occurs, and Angular provides a corresponding
|
||||
DOM event object in the `$event` variable which this code passes as a parameter to the component's `onKey()` method.
|
||||
|
||||
当用户按下并释放一个按键时,触发`keyup`事件,Angular 在`$event`变量提供一个相应的 DOM
|
||||
事件对象,上面的代码将它作为参数传递给`onKey()`方法。
|
||||
当用户按下并释放一个按键时,触发 `keyup` 事件,Angular 在 `$event` 变量提供一个相应的 DOM
|
||||
事件对象,上面的代码将它作为参数传递给 `onKey()` 方法。
|
||||
|
||||
<code-example path="user-input/src/app/keyup.components.ts" region="key-up-component-1-class-no-type" title="src/app/keyup.components.ts (class v.1)" linenums="false">
|
||||
|
||||
|
@ -98,25 +98,25 @@ DOM event object in the `$event` variable which this code passes as a parameter
|
|||
The properties of an `$event` object vary depending on the type of DOM event. For example,
|
||||
a mouse event includes different information than a input box editing event.
|
||||
|
||||
`$event`对象的属性取决于 DOM 事件的类型。例如,鼠标事件与输入框编辑事件包含了不同的信息。
|
||||
`$event` 对象的属性取决于 DOM 事件的类型。例如,鼠标事件与输入框编辑事件包含了不同的信息。
|
||||
|
||||
All [standard DOM event objects](https://developer.mozilla.org/en-US/docs/Web/API/Event)
|
||||
have a `target` property, a reference to the element that raised the event.
|
||||
In this case, `target` refers to the [`<input>` element](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement) and
|
||||
`event.target.value` returns the current contents of that element.
|
||||
|
||||
所有[标准 DOM 事件对象](https://developer.mozilla.org/en-US/docs/Web/API/Event)都有一个`target`属性,
|
||||
所有[标准 DOM 事件对象](https://developer.mozilla.org/en-US/docs/Web/API/Event)都有一个 `target` 属性,
|
||||
引用触发该事件的元素。
|
||||
在本例中,`target`是[`<input>`元素](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement),
|
||||
`event.target.value`返回该元素的当前内容。
|
||||
在本例中,`target` 是[`<input>` 元素](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement),
|
||||
`event.target.value` 返回该元素的当前内容。
|
||||
|
||||
After each call, the `onKey()` method appends the contents of the input box value to the list
|
||||
in the component's `values` property, followed by a separator character (|).
|
||||
The [interpolation](guide/template-syntax#interpolation)
|
||||
displays the accumulating input box changes from the `values` property.
|
||||
|
||||
在组件的`onKey()`方法中,把输入框的值和分隔符 (|) 追加组件的`values`属性。
|
||||
使用[插值表达式](guide/template-syntax#interpolation)来把存放累加结果的`values`属性回显到屏幕上。
|
||||
在组件的 `onKey()` 方法中,把输入框的值和分隔符 (|) 追加组件的 `values` 属性。
|
||||
使用[插值表达式](guide/template-syntax#interpolation)来把存放累加结果的 `values` 属性回显到屏幕上。
|
||||
|
||||
Suppose the user enters the letters "abc", and then backspaces to remove them one by one.
|
||||
Here's what the UI displays:
|
||||
|
@ -139,7 +139,7 @@ Here's what the UI displays:
|
|||
Alternatively, you could accumulate the individual keys themselves by substituting `event.key`
|
||||
for `event.target.value` in which case the same user input would produce:
|
||||
|
||||
或者,你可以用`event.key`替代`event.target.value`,积累各个按键本身,这样同样的用户输入可以产生:
|
||||
或者,你可以用 `event.key` 替代 `event.target.value`,积累各个按键本身,这样同样的用户输入可以产生:
|
||||
|
||||
<code-example>
|
||||
|
||||
|
@ -160,7 +160,7 @@ That simplifies the code at a cost.
|
|||
There is no type information
|
||||
that could reveal properties of the event object and prevent silly mistakes.
|
||||
|
||||
上例将`$event`转换为`any`类型。
|
||||
上例将 `$event` 转换为 `any` 类型。
|
||||
这样简化了代码,但是有成本。
|
||||
没有任何类型信息能够揭示事件对象的属性,防止简单的错误。
|
||||
|
||||
|
@ -176,9 +176,9 @@ The `$event` is now a specific `KeyboardEvent`.
|
|||
Not all elements have a `value` property so it casts `target` to an input element.
|
||||
The `OnKey` method more clearly expresses what it expects from the template and how it interprets the event.
|
||||
|
||||
`$event`的类型现在是`KeyboardEvent`。
|
||||
不是所有的元素都有`value`属性,所以它将`target`转换为输入元素。
|
||||
`OnKey`方法更加清晰的表达了它期望从模板得到什么,以及它是如何解析事件的。
|
||||
`$event` 的类型现在是 `KeyboardEvent`。
|
||||
不是所有的元素都有 `value` 属性,所以它将 `target` 转换为输入元素。
|
||||
`OnKey` 方法更加清晰的表达了它期望从模板得到什么,以及它是如何解析事件的。
|
||||
|
||||
### Passing _$event_ is a dubious practice
|
||||
|
||||
|
@ -225,8 +225,8 @@ refers to the `<input>` element itself.
|
|||
The code uses the `box` variable to get the input element's `value` and display it
|
||||
with interpolation between `<p>` tags.
|
||||
|
||||
这个模板引用变量名叫`box`,在`<input>`元素声明,它引用`<input>`元素本身。
|
||||
代码使用`box`获得输入元素的`value`值,并通过插值表达式把它显示在`<p>`标签中。
|
||||
这个模板引用变量名叫 `box`,在 `<input>` 元素声明,它引用 `<input>` 元素本身。
|
||||
代码使用 `box` 获得输入元素的 `value` 值,并通过插值表达式把它显示在 `<p>` 标签中。
|
||||
|
||||
The template is completely self contained. It doesn't bind to the component,
|
||||
and the component does nothing.
|
||||
|
@ -255,7 +255,7 @@ While the statement does nothing useful,
|
|||
it satisfies Angular's requirement so that Angular will update the screen.
|
||||
|
||||
只有在应用做了些异步事件(如击键),Angular 才更新绑定(并最终影响到屏幕)。
|
||||
本例代码将`keyup`事件绑定到了数字0,这可能是最短的模板语句了。
|
||||
本例代码将 `keyup` 事件绑定到了数字 0,这可能是最短的模板语句了。
|
||||
虽然这个语句不做什么,但它满足 Angular 的要求,所以 Angular 将更新屏幕。
|
||||
|
||||
</div>
|
||||
|
@ -264,8 +264,8 @@ It's easier to get to the input box with the template reference
|
|||
variable than to go through the `$event` object. Here's a rewrite of the previous
|
||||
`keyup` example that uses a template reference variable to get the user's input.
|
||||
|
||||
从模板变量获得输入框比通过`$event`对象更加简单。
|
||||
下面的代码重写了之前`keyup`示例,它使用变量来获得用户输入。
|
||||
从模板变量获得输入框比通过 `$event` 对象更加简单。
|
||||
下面的代码重写了之前 `keyup` 示例,它使用变量来获得用户输入。
|
||||
|
||||
<code-example path="user-input/src/app/keyup.components.ts" region="key-up-component-2" title="src/app/keyup.components.ts (v2)" linenums="false">
|
||||
|
||||
|
@ -274,26 +274,26 @@ variable than to go through the `$event` object. Here's a rewrite of the previou
|
|||
A nice aspect of this approach is that the component gets clean data values from the view.
|
||||
It no longer requires knowledge of the `$event` and its structure.
|
||||
|
||||
这个方法最漂亮的一点是:组件代码从视图中获得了干净的数据值。再也不用了解`$event`变量及其结构了。
|
||||
这个方法最漂亮的一点是:组件代码从视图中获得了干净的数据值。再也不用了解 `$event` 变量及其结构了。
|
||||
|
||||
{@a key-event}
|
||||
|
||||
## Key event filtering (with `key.enter`)
|
||||
|
||||
## 按键事件过滤(通过`key.enter`)
|
||||
## 按键事件过滤(通过 `key.enter`)
|
||||
|
||||
The `(keyup)` event handler hears *every keystroke*.
|
||||
Sometimes only the _Enter_ key matters, because it signals that the user has finished typing.
|
||||
One way to reduce the noise would be to examine every `$event.keyCode` and take action only when the key is _Enter_.
|
||||
|
||||
`(keyup)`事件处理器监听*每一次按键*。
|
||||
`(keyup)` 事件处理器监听*每一次按键*。
|
||||
有时只在意*回车*键,因为它标志着用户结束输入。
|
||||
解决这个问题的一种方法是检查每个`$event.keyCode`,只有键值是*回车*键时才采取行动。
|
||||
解决这个问题的一种方法是检查每个 `$event.keyCode`,只有键值是*回车*键时才采取行动。
|
||||
|
||||
There's an easier way: bind to Angular's `keyup.enter` pseudo-event.
|
||||
Then Angular calls the event handler only when the user presses _Enter_.
|
||||
|
||||
更简单的方法是:绑定到 Angular 的`keyup.enter` 模拟事件。
|
||||
更简单的方法是:绑定到 Angular 的 `keyup.enter` 模拟事件。
|
||||
然后,只有当用户敲*回车*键时,Angular 才会调用事件处理器。
|
||||
|
||||
<code-example path="user-input/src/app/keyup.components.ts" region="key-up-component-3" title="src/app/keyup.components.ts (v3)" linenums="false">
|
||||
|
@ -318,7 +318,7 @@ without first pressing _Enter_.
|
|||
The component's `value` property is updated only when the user presses _Enter_.
|
||||
|
||||
前上例中,如果用户没有先按回车键,而是移开了鼠标,点击了页面中其它地方,输入框的当前值就会丢失。
|
||||
只有当用户按下了回车键候,组件的`values`属性才能更新。
|
||||
只有当用户按下了回车键候,组件的 `values` 属性才能更新。
|
||||
|
||||
To fix this issue, listen to both the _Enter_ key and the _blur_ event.
|
||||
|
||||
|
@ -366,15 +366,15 @@ Below is the "Little Tour of Heroes" component.
|
|||
The `newHero` template variable refers to the `<input>` element.
|
||||
You can reference `newHero` from any sibling or child of the `<input>` element.
|
||||
|
||||
**使用模板变量来引用元素** — `newHero`模板变量引用了`<input>`元素。
|
||||
你可以在`<input>`的任何兄弟或子级元素中引用`newHero`。
|
||||
**使用模板变量来引用元素** — `newHero` 模板变量引用了 `<input>` 元素。
|
||||
你可以在 `<input>` 的任何兄弟或子级元素中引用 `newHero`。
|
||||
|
||||
* **Pass values, not elements** —
|
||||
Instead of passing the `newHero` into the component's `addHero` method,
|
||||
get the input box value and pass *that* to `addHero`.
|
||||
|
||||
**传递数值,而非元素** —
|
||||
获取输入框的值并将*它*传递给组件的`addHero`,而不要传递`newHero`。
|
||||
获取输入框的值并将*它*传递给组件的 `addHero`,而不要传递 `newHero`。
|
||||
|
||||
* **Keep template statements simple** —
|
||||
The `(blur)` event is bound to two JavaScript statements.
|
||||
|
@ -382,8 +382,8 @@ The first statement calls `addHero`. The second statement, `newHero.value=''`,
|
|||
clears the input box after a new hero is added to the list.
|
||||
|
||||
**保持模板语句简单** —
|
||||
`(blur)`事件被绑定到两个 JavaScript 语句。
|
||||
第一句调用`addHero`。第二句`newHero.value=''`在添加新英雄到列表中后清除输入框。
|
||||
`(blur)` 事件被绑定到两个 JavaScript 语句。
|
||||
第一句调用 `addHero`。第二句 `newHero.value=''` 在添加新英雄到列表中后清除输入框。
|
||||
|
||||
## Source code
|
||||
|
||||
|
@ -431,4 +431,4 @@ two-way bindings with `NgModel`.
|
|||
|
||||
这些技术对小规模演示很实用,但是在处理大量用户输入时,很容易变得累赘和笨拙。
|
||||
要在数据录入字段和模型属性之间传递数据,双向数据绑定是更加优雅和简洁的方式。
|
||||
下一章`表单`解释了如何用`NgModel`来进行双向绑定。
|
||||
下一章 ` 表单 ` 解释了如何用 `NgModel` 来进行双向绑定。
|
||||
|
|
|
@ -6,19 +6,19 @@
|
|||
|
||||
Some developers prefer Visual Studio as their Integrated Development Environment (IDE).
|
||||
|
||||
有些开发者喜欢用Visual Studio。
|
||||
有些开发者喜欢用 Visual Studio。
|
||||
|
||||
This cookbook describes the steps required to set up and use the
|
||||
Angular QuickStart files in **Visual Studio 2015 within an ASP.NET 4.x project**.
|
||||
|
||||
本烹饪宝典介绍了在**Visual Studio 2015的ASP.NET 4.x项目中**,用Angular实现“快速上手”所需的步骤。
|
||||
本烹饪宝典介绍了在**Visual Studio 2015 的 ASP.NET 4.x 项目中**,用 Angular 实现“快速上手”所需的步骤。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
There is no *live example* for this cookbook because it describes Visual Studio, not
|
||||
the QuickStart application itself.
|
||||
|
||||
本烹饪宝典中没有*在线例子*,因为它介绍的是Visual Studio,而不是《快速上手》应用程序本身。
|
||||
本烹饪宝典中没有*在线例子*,因为它介绍的是 Visual Studio,而不是《快速上手》应用程序本身。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -31,7 +31,7 @@ the QuickStart application itself.
|
|||
To set up the QuickStart files with an **ASP.NET 4.x project** in
|
||||
Visual Studio 2015, follow these steps:
|
||||
|
||||
要用Visual Studio 2015在**ASP.NET 4.x项目**中设置**《快速上手》**文件,请遵循如下步骤:
|
||||
要用 Visual Studio 2015 在**ASP.NET 4.x 项目**中设置**《快速上手》**文件,请遵循如下步骤:
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
|
@ -53,7 +53,7 @@ Note that the resulting code does not map to the docs. Adjust accordingly.
|
|||
Install **[Node.js® and npm](https://nodejs.org/en/download/)**
|
||||
if they are not already on your machine.
|
||||
|
||||
如果你的电脑里没有Node.js®和npm,请安装**[它们](https://nodejs.org/en/download/)**。
|
||||
如果你的电脑里没有 Node.js®和 npm,请安装**[它们](https://nodejs.org/en/download/)**。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
|
@ -61,7 +61,7 @@ if they are not already on your machine.
|
|||
by running `node -v` and `npm -v` in a terminal window.
|
||||
Older versions produce errors.
|
||||
|
||||
在终端或者控制台中运行`node -v`和`npm -v`,**请确认你的Node版本为`4.6.x`或更高,npm的版本为`3.x.x`或更高**。老版本会引起错误。
|
||||
在终端或者控制台中运行 `node -v` 和 `npm -v`,**请确认你的 Node 版本为 `4.6.x` 或更高,npm 的版本为 `3.x.x` 或更高**。老版本会引起错误。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -73,62 +73,62 @@ The minimum requirement for developing Angular applications with Visual Studio i
|
|||
Earlier versions do not follow the best practices for developing applications with TypeScript.
|
||||
To view your version of Visual Studio 2015, go to `Help | About Visual Studio`.
|
||||
|
||||
使用Visual Studio开发Angular应用程序的最低要求是Update 3。
|
||||
早期版本没有遵循使用TypeScript开发应用程序的最佳实践。
|
||||
要查看你的Visual Studio 2015版本号,到`Help | About Visual Studio`。
|
||||
使用 Visual Studio 开发 Angular 应用程序的最低要求是 Update 3。
|
||||
早期版本没有遵循使用 TypeScript 开发应用程序的最佳实践。
|
||||
要查看你的 Visual Studio 2015 版本号,到 `Help | About Visual Studio`。
|
||||
|
||||
If you don't have it, install **[Visual Studio 2015 Update 3](https://www.visualstudio.com/en-us/news/releasenotes/vs2015-update3-vs)**.
|
||||
Or use `Tools | Extensions and Updates` to update to Update 3 directly from Visual Studio 2015.
|
||||
|
||||
如果还没有,安装**[Visual Studio 2015 Update 3](https://www.visualstudio.com/en-us/news/releasenotes/vs2015-update3-vs)**。或者使用`Tools | Extensions and Updates`来直接在Visual Studio 2015中更新到Update 3。
|
||||
如果还没有,安装**[Visual Studio 2015 Update 3](https://www.visualstudio.com/en-us/news/releasenotes/vs2015-update3-vs)**。或者使用 `Tools | Extensions and Updates` 来直接在 Visual Studio 2015 中更新到 Update 3。
|
||||
|
||||
<h2 id='prereq3'>Prerequisite: Configure External Web tools</h2>
|
||||
|
||||
<h2 id='prereq3'>前提条件: 配置External Web tools</h2>
|
||||
<h2 id='prereq3'>前提条件: 配置 External Web tools</h2>
|
||||
|
||||
Configure Visual Studio to use the global external web tools instead of the tools that ship with Visual Studio:
|
||||
|
||||
配置Visual Studio来使用全局External Web Tools,而非Visual Studio默认的工具:
|
||||
配置 Visual Studio 来使用全局 External Web Tools,而非 Visual Studio 默认的工具:
|
||||
|
||||
* Open the **Options** dialog with `Tools` | `Options`.
|
||||
|
||||
到`Tools` | `Options`打开**Options**对话框
|
||||
到 `Tools` | `Options` 打开**Options**对话框
|
||||
|
||||
* In the tree on the left, select `Projects and Solutions` | `External Web Tools`.
|
||||
|
||||
在左边树型项目中,选择`Projects and Solutions` | `External Web Tools`。
|
||||
在左边树型项目中,选择 `Projects and Solutions` | `External Web Tools`。
|
||||
|
||||
* On the right, move the `$(PATH)` entry above the `$(DevEnvDir`) entries. This tells Visual Studio to
|
||||
use the external tools (such as npm) found in the global path before using its own version of the external tools.
|
||||
|
||||
* 在右侧,将`$(PATH)`移动到 `$(DevEnvDir`)上面。这样,Visual Stuio就会在使用自带的外部工具时,优先使用全局路径中的外部工具(比如npm)。
|
||||
* 在右侧,将 `$(PATH)` 移动到 `$(DevEnvDir`)上面。这样,Visual Stuio 就会在使用自带的外部工具时,优先使用全局路径中的外部工具(比如 npm)。
|
||||
|
||||
* Click OK to close the dialog.
|
||||
|
||||
点击OK关闭对话框。
|
||||
点击 OK 关闭对话框。
|
||||
|
||||
* Restart Visual Studio for this change to take effect.
|
||||
|
||||
重启Visual Studio,以让设置变化生效。
|
||||
重启 Visual Studio,以让设置变化生效。
|
||||
|
||||
Visual Studio now looks first for external tools in the current workspace and
|
||||
if it doesn't find them, it looks in the global path. If Visual Studio doesn't
|
||||
find them in either location, it will use its own versions of the tools.
|
||||
|
||||
Visual Studio将优先在当前的工作区查找外部工具,如果没有找到,便查找全局路径,如果还没有找到,Visual Studio就使用自带的工具版本。
|
||||
Visual Studio 将优先在当前的工作区查找外部工具,如果没有找到,便查找全局路径,如果还没有找到,Visual Studio 就使用自带的工具版本。
|
||||
|
||||
<h2 id='prereq4'>Prerequisite: Install TypeScript 2.2 for Visual Studio 2015</h2>
|
||||
|
||||
<h2 id='prereq4'>前提条件: 安装TypeScript 2.2 for Visual Studio 2015</h2>
|
||||
<h2 id='prereq4'>前提条件: 安装 TypeScript 2.2 for Visual Studio 2015</h2>
|
||||
|
||||
While Visual Studio Update 3 ships with TypeScript support out of the box, it currently doesn’t ship with TypeScript 2.2,
|
||||
which you need to develop Angular applications.
|
||||
|
||||
Visual Studio Update 3自带TypeScript支持,但是它的TypeScript版本开发Angular应用需要的不是2.2。
|
||||
Visual Studio Update 3 自带 TypeScript 支持,但是它的 TypeScript 版本开发 Angular 应用需要的不是 2.2。
|
||||
|
||||
To install TypeScript 2.2:
|
||||
|
||||
要安装TypeScript 2.2:
|
||||
要安装 TypeScript 2.2:
|
||||
|
||||
* Download and install **[TypeScript 2.2 for Visual Studio 2015](https://www.microsoft.com/en-us/download/details.aspx?id=48593)**
|
||||
|
||||
|
@ -136,16 +136,16 @@ To install TypeScript 2.2:
|
|||
|
||||
* OR install it with npm: `npm install -g typescript@2.2`.
|
||||
|
||||
或通过npm安装:`npm install -g typescript@2.2`。
|
||||
或通过 npm 安装:`npm install -g typescript@2.2`。
|
||||
|
||||
You can find out more about TypeScript 2.2 support in Visual studio **[here](https://blogs.msdn.microsoft.com/typescript/2017/02/22/announcing-typescript-2-2/)**.
|
||||
|
||||
你可以在**[这儿](https://blogs.msdn.microsoft.com/typescript/2017/02/22/announcing-typescript-2-2/)**查看更多Visual Studio中TypeScript 2.2的支持。
|
||||
你可以在**[这儿](https://blogs.msdn.microsoft.com/typescript/2017/02/22/announcing-typescript-2-2/)**查看更多 Visual Studio 中 TypeScript 2.2 的支持。
|
||||
|
||||
At this point, Visual Studio is ready. It’s a good idea to close Visual Studio and
|
||||
restart it to make sure everything is clean.
|
||||
|
||||
至此,Visual Studio准备好了。重新启动Visual Stuido,这样我们可以有一个崭新的开始。
|
||||
至此,Visual Studio 准备好了。重新启动 Visual Stuido,这样我们可以有一个崭新的开始。
|
||||
|
||||
<h2 id='download'>Step 1: Download the QuickStart files</h2>
|
||||
|
||||
|
@ -154,63 +154,63 @@ restart it to make sure everything is clean.
|
|||
[Download the QuickStart source](https://github.com/angular/quickstart)
|
||||
from GitHub. If you downloaded as a zip file, extract the files.
|
||||
|
||||
从GitHub[下载“快速上手”的源代码](https://github.com/angular/quickstart)。如果下载的是一个压缩的zip文件,解压它。
|
||||
从 GitHub[下载“快速上手”的源代码](https://github.com/angular/quickstart)。如果下载的是一个压缩的 zip 文件,解压它。
|
||||
|
||||
<h2 id='create-project'>Step 2: Create the Visual Studio ASP.NET project</h2>
|
||||
|
||||
<h2 id='create-project'>第二步:创建Visual Studio ASP.net项目</h2>
|
||||
<h2 id='create-project'>第二步:创建 Visual Studio ASP.net 项目</h2>
|
||||
|
||||
Create the ASP.NET 4.x project in the usual way as follows:
|
||||
|
||||
按照下列步骤创建ASP.NET 4.x项目:
|
||||
按照下列步骤创建 ASP.NET 4.x 项目:
|
||||
|
||||
* In Visual Studio, select `File` | `New` | `Project` from the menu.
|
||||
|
||||
在Visual Studio中,选择`File` | `New` | `Project`菜单。
|
||||
在 Visual Studio 中,选择 `File` | `New` | `Project` 菜单。
|
||||
|
||||
* In the template tree, select `Templates` | `Visual C#` (or `Visual Basic`) | `Web`.
|
||||
|
||||
在模板树中,选择`Templates` | `Visual C#`(或`Visual Basic`) | `Web`菜单。
|
||||
在模板树中,选择 `Templates` | `Visual C#`(或 `Visual Basic`) | `Web` 菜单。
|
||||
|
||||
* Select the `ASP.NET Web Application` template, give the project a name, and click OK.
|
||||
|
||||
选择`ASP.NET Web Application`模板,输入项目名,点击“OK”按钮。
|
||||
选择 `ASP.NET Web Application` 模板,输入项目名,点击“OK”按钮。
|
||||
|
||||
* Select the desired ASP.NET 4.5.2 template and click OK.
|
||||
|
||||
选择自己喜欢的ASP.NET 4.5.2模板,点击OK。
|
||||
选择自己喜欢的 ASP.NET 4.5.2 模板,点击 OK。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
This cookbook uses the `Empty` template with no added folders,
|
||||
no authentication, and no hosting. Pick the template and options appropriate for your project.
|
||||
|
||||
本烹饪宝典选择了`Empty`模板,它没有添加过任何目录,没有身份验证,没有服务器托管。为你的项目选择合适的模板和选项。
|
||||
本烹饪宝典选择了 `Empty` 模板,它没有添加过任何目录,没有身份验证,没有服务器托管。为你的项目选择合适的模板和选项。
|
||||
|
||||
</div>
|
||||
|
||||
<h2 id='copy'>Step 3: Copy the QuickStart files into the ASP.NET project folder</h2>
|
||||
|
||||
<h2 id='copy'>第三步: 把“快速上手”的文件复制到ASP.NET项目所在的目录</h2>
|
||||
<h2 id='copy'>第三步: 把“快速上手”的文件复制到 ASP.NET 项目所在的目录</h2>
|
||||
|
||||
Copy the QuickStart files you downloaded from GitHub into the folder containing the `.csproj` file.
|
||||
Include the files in the Visual Studio project as follows:
|
||||
|
||||
拷贝从GitHub下载的“快速上手”文件到包含`.csproj`文件的目录中。按照下面的步骤把它们加到Visual Studio中:
|
||||
拷贝从 GitHub 下载的“快速上手”文件到包含 `.csproj` 文件的目录中。按照下面的步骤把它们加到 Visual Studio 中:
|
||||
|
||||
* Click the `Show All Files` button in Solution Explorer to reveal all of the hidden files in the project.
|
||||
|
||||
在Solution Explorer中点击`Show All Files`按钮,显示项目中所有隐藏文件。
|
||||
在 Solution Explorer 中点击 `Show All Files` 按钮,显示项目中所有隐藏文件。
|
||||
|
||||
* Right-click on each folder/file to be included in the project and select `Include in Project`.
|
||||
Minimally, include the following folder/files:
|
||||
|
||||
右键点击每个目录和文件,选择`Include in Project`。
|
||||
右键点击每个目录和文件,选择 `Include in Project`。
|
||||
最少要添加下列文件:
|
||||
|
||||
* src/app folder (answer *No* if asked to search for TypeScript Typings)
|
||||
|
||||
src/app目录(如果询问是否要搜索TypeScript类型,回答*No*)
|
||||
src/app 目录(如果询问是否要搜索 TypeScript 类型,回答*No*)
|
||||
|
||||
* src/styles.css
|
||||
|
||||
|
@ -226,19 +226,19 @@ Include the files in the Visual Studio project as follows:
|
|||
|
||||
Restore the packages required for an Angular application as follows:
|
||||
|
||||
按下面的步骤恢复Angular应用程序需要的包:
|
||||
按下面的步骤恢复 Angular 应用程序需要的包:
|
||||
|
||||
* Right-click on the `package.json` file in Solution Explorer and select `Restore Packages`.
|
||||
<br>This uses `npm` to install all of the packages defined in the `package.json` file.
|
||||
It may take some time.
|
||||
|
||||
在Solution Explorer中右键点击`package.json`,选择`Restore Packages`。
|
||||
<br>这样,Visual Studio会使用`npm`来安装在`package.json`中定义的所有包.
|
||||
在 Solution Explorer 中右键点击 `package.json`,选择 `Restore Packages`。
|
||||
<br>这样,Visual Studio 会使用 `npm` 来安装在 `package.json` 中定义的所有包.
|
||||
这可能需要花一点时间。
|
||||
|
||||
* If desired, open the Output window (`View` | `Output`) to watch the npm commands execute.
|
||||
|
||||
如果愿意,打开Output窗口(`View` | `Output`)来监控npm命令的执行情况。
|
||||
如果愿意,打开 Output 窗口(`View` | `Output`)来监控 npm 命令的执行情况。
|
||||
|
||||
* Ignore the warnings.
|
||||
|
||||
|
@ -251,11 +251,11 @@ Restore the packages required for an Angular application as follows:
|
|||
|
||||
* Click the `Refresh` icon in Solution Explorer.
|
||||
|
||||
在Solution Explorer里,点击`Refresh`图标。
|
||||
在 Solution Explorer 里,点击 `Refresh` 图标。
|
||||
|
||||
* **Do not** include the `node_modules` folder in the project. Let it be a hidden project folder.
|
||||
|
||||
**不要**将`node_modules`目录添加到项目中,让它隐藏。
|
||||
**不要**将 `node_modules` 目录添加到项目中,让它隐藏。
|
||||
|
||||
<h2 id='build-and-run'>Step 5: Build and run the app</h2>
|
||||
|
||||
|
@ -264,8 +264,8 @@ Restore the packages required for an Angular application as follows:
|
|||
First, ensure that `src/index.html` is set as the start page.
|
||||
Right-click `index.html` in Solution Explorer and select option `Set As Start Page`.
|
||||
|
||||
首先,确认`src/index.html`已被设置为开始页面。
|
||||
在Solution Explorer中,右键点击`index.html`,选择选项`Set As Start Page`。
|
||||
首先,确认 `src/index.html` 已被设置为开始页面。
|
||||
在 Solution Explorer 中,右键点击 `index.html`,选择选项 `Set As Start Page`。
|
||||
|
||||
### To run in VS with F5
|
||||
|
||||
|
@ -284,19 +284,19 @@ To use the IIS server with the QuickStart app, you must make the following three
|
|||
2. Also in `index.html`, change the scripts to use `/node_modules` with a slash
|
||||
instead of `node_modules` without the slash.
|
||||
|
||||
同样在`index.html`中,修改脚本来用带有斜杠的`/node_modules`代替不带斜杠的`node_modules`。
|
||||
同样在 `index.html` 中,修改脚本来用带有斜杠的 `/node_modules` 代替不带斜杠的 `node_modules`。
|
||||
|
||||
3. In `src/systemjs.config.js`, near the top of the file,
|
||||
change the npm `path` to `/node_modules/` with a slash.
|
||||
|
||||
在`src/systemjs.config.js`的顶部,把 npm 的 `path` 设置为带斜杠的`/node_modules/`。
|
||||
在 `src/systemjs.config.js` 的顶部,把 npm 的 `path` 设置为带斜杠的 `/node_modules/`。
|
||||
|
||||
<div class="alert is-important">
|
||||
|
||||
After these changes, `npm start` no longer works.
|
||||
You must choose to configure _either_ for F5 with IIS _or_ for `npm start` with the lite-server.
|
||||
|
||||
做完这些修改之后,`npm start`不再工作了。我们必须选择配置为IIS + F5,还是`npm start` + lite-server。
|
||||
做完这些修改之后,`npm start` 不再工作了。我们必须选择配置为 IIS + F5,还是 `npm start` + lite-server。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -308,7 +308,7 @@ If your app uses routing, you need to teach the server to always return
|
|||
`index.html` when the user asks for an HTML page
|
||||
for reasons explained in the [Deployment](guide/deployment#fallback) guide.
|
||||
|
||||
如果应用要使用路由,就要让服务器在用户要求 HTML 页面时始终返回`index.html`。
|
||||
如果应用要使用路由,就要让服务器在用户要求 HTML 页面时始终返回 `index.html`。
|
||||
此中原因,在[发布](guide/deployment#fallback)一章中有解释。
|
||||
|
||||
Everything seems fine while you move about _within_ the app.
|
||||
|
@ -327,8 +327,8 @@ The `lite-server` development server does out-of-the-box.
|
|||
If you've switched over to F5 and IIS, you have to configure IIS to do it.
|
||||
This section walks through the steps to adapt the QuickStart application.
|
||||
|
||||
我们就要配置服务器,为那些"未知"的页面返回`index.html`。
|
||||
`lite-server`开发服务器内置了这项功能。如果要切换到 F5 + IIS,我们就要自己来配置IIS实现它了。
|
||||
我们就要配置服务器,为那些"未知"的页面返回 `index.html`。
|
||||
`lite-server` 开发服务器内置了这项功能。如果要切换到 F5 + IIS,我们就要自己来配置 IIS 实现它了。
|
||||
接下来我们就看看对快速起步应用做配置的步骤。
|
||||
|
||||
#### Configure IIS rewrite rules
|
||||
|
@ -345,7 +345,7 @@ Visual Studio 自带了一个 IIS Express,其中有一个重写(rewrite)
|
|||
Tell Visual Studio how to handle requests for route app pages by adding these
|
||||
rewrite rules near the bottom of the `web.config`:
|
||||
|
||||
通过把下列重写规则添加到`web.config`的底部,就可以告诉 Visual Studio如何处理到应用页面的请求。
|
||||
通过把下列重写规则添加到 `web.config` 的底部,就可以告诉 Visual Studio 如何处理到应用页面的请求。
|
||||
|
||||
<code-example format='.'>
|
||||
|
||||
|
@ -371,24 +371,24 @@ rewrite rules near the bottom of the `web.config`:
|
|||
The match url, `<match url=".*" />`, will rewrite every request. You'll have to adjust this if
|
||||
you want some requests to get through, such as web API requests.
|
||||
|
||||
匹配 url `<match url=".*" />`语句将会重写每一个请求。如果需要直接放行某些请求,比如一些Web API请求,我们就必须调整它才行。
|
||||
匹配 url `<match url=".*" />` 语句将会重写每一个请求。如果需要直接放行某些请求,比如一些 Web API 请求,我们就必须调整它才行。
|
||||
|
||||
The URL in `<action type="Rewrite" url="/src/"/>` should
|
||||
match the base href in `index.html`.
|
||||
|
||||
`<action type="Rewrite" url="/src/"/>`中的 url将会匹配`index.html`中的基地址(base href)。
|
||||
`<action type="Rewrite" url="/src/"/>` 中的 url 将会匹配 `index.html` 中的基地址(base href)。
|
||||
|
||||
</div>
|
||||
|
||||
Build and launch the app with debugger by clicking the **Run** button or by pressing `F5`.
|
||||
|
||||
点击**Run**按钮或者按`F5`键,用调试器构建和启动应用。
|
||||
点击**Run**按钮或者按 `F5` 键,用调试器构建和启动应用。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
It's faster to run without the debugger by pressing `Ctrl-F5`.
|
||||
|
||||
按`Ctrl-F5`不带调试器的运行应用,速度会更快。
|
||||
按 `Ctrl-F5` 不带调试器的运行应用,速度会更快。
|
||||
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Webpack: An Introduction
|
||||
|
||||
# Webpack简介
|
||||
# Webpack 简介
|
||||
|
||||
<style>
|
||||
h4 {font-size: 17px !important; text-transform: none !important;}
|
||||
|
@ -18,7 +18,7 @@ and for loading that code from a server into a browser.
|
|||
It's an excellent alternative to the *SystemJS* approach used elsewhere in the documentation.
|
||||
This guide offers a taste of Webpack and explains how to use it with Angular applications.
|
||||
|
||||
它是我们在文档中到处使用的*SystemJS*的一个优秀替代品。这篇指南会带我们尝尝Webpack的滋味,并解释如何在Angular程序中使用它。
|
||||
它是我们在文档中到处使用的*SystemJS*的一个优秀替代品。这篇指南会带我们尝尝 Webpack 的滋味,并解释如何在 Angular 程序中使用它。
|
||||
|
||||
{@a top}
|
||||
|
||||
|
@ -30,7 +30,7 @@ This guide offers a taste of Webpack and explains how to use it with Angular app
|
|||
|
||||
* [What is Webpack?](guide/webpack#what-is-webpack)
|
||||
|
||||
[什么是Webpack?](guide/webpack#what-is-webpack)
|
||||
[什么是 Webpack?](guide/webpack#what-is-webpack)
|
||||
|
||||
* [Entries and outputs](guide/webpack#entries-outputs)
|
||||
|
||||
|
@ -50,7 +50,7 @@ This guide offers a taste of Webpack and explains how to use it with Angular app
|
|||
|
||||
* [Configuring Webpack](guide/webpack#configure-webpack)
|
||||
|
||||
[配置Webpack](guide/webpack#configure-webpack)
|
||||
[配置 Webpack](guide/webpack#configure-webpack)
|
||||
|
||||
* [Polyfills](guide/webpack#polyfills)
|
||||
|
||||
|
@ -60,7 +60,7 @@ This guide offers a taste of Webpack and explains how to use it with Angular app
|
|||
|
||||
* [Inside `webpack.common.js`](guide/webpack#inside-webpack-commonjs)
|
||||
|
||||
[深入`webpack.common.js`](guide/webpack#inside-webpack-commonjs)
|
||||
[深入 `webpack.common.js`](guide/webpack#inside-webpack-commonjs)
|
||||
|
||||
* [entry](guide/webpack#common-entries)
|
||||
|
||||
|
@ -118,27 +118,27 @@ You can also <a href="generated/zips/webpack/webpack.zip" target="_blank">downlo
|
|||
|
||||
## What is Webpack?
|
||||
|
||||
## 什么是Webpack?
|
||||
## 什么是 Webpack?
|
||||
|
||||
Webpack is a powerful module bundler.
|
||||
A _bundle_ is a JavaScript file that incorporates _assets_ that *belong* together and
|
||||
should be served to the client in a response to a single file request.
|
||||
A bundle can include JavaScript, CSS styles, HTML, and almost any other kind of file.
|
||||
|
||||
Webpack是一个强力的模块打包器。
|
||||
所谓_包(bundle)_就是一个JavaScript文件,它把一堆_资源(assets)_合并在一起,以便它们可以在同一个文件请求中发回给客户端。
|
||||
包中可以包含JavaScript、CSS样式、HTML以及很多其它类型的文件。
|
||||
Webpack 是一个强力的模块打包器。
|
||||
所谓_包(bundle)_就是一个 JavaScript 文件,它把一堆_资源(assets)_合并在一起,以便它们可以在同一个文件请求中发回给客户端。
|
||||
包中可以包含 JavaScript、CSS 样式、HTML 以及很多其它类型的文件。
|
||||
|
||||
Webpack roams over your application source code,
|
||||
looking for `import` statements, building a dependency graph, and emitting one or more _bundles_.
|
||||
With plugins and rules, Webpack can preprocess and minify different non-JavaScript files such as TypeScript, SASS, and LESS files.
|
||||
|
||||
Webpack会遍历你应用中的所有源码,查找`import`语句,构建出依赖图谱,并产出一个(或多个)_包_。
|
||||
通过插件和规则,Webpack可以对各种非JavaScript文件进行预处理和最小化(Minify),比如TypeScript、SASS和LESS文件等。
|
||||
Webpack 会遍历你应用中的所有源码,查找 `import` 语句,构建出依赖图谱,并产出一个(或多个)_包_。
|
||||
通过插件和规则,Webpack 可以对各种非 JavaScript 文件进行预处理和最小化(Minify),比如 TypeScript、SASS 和 LESS 文件等。
|
||||
|
||||
You determine what Webpack does and how it does it with a JavaScript configuration file, `webpack.config.js`.
|
||||
|
||||
我们通过一个JavaScript配置文件`webpack.config.js`来决定Webpack做什么以及如何做。
|
||||
我们通过一个 JavaScript 配置文件 `webpack.config.js` 来决定 Webpack 做什么以及如何做。
|
||||
|
||||
{@a entries-outputs}
|
||||
|
||||
|
@ -149,8 +149,8 @@ You determine what Webpack does and how it does it with a JavaScript configurati
|
|||
You supply Webpack with one or more *entry* files and let it find and incorporate the dependencies that radiate from those entries.
|
||||
The one entry point file in this example is the application's root file, `src/main.ts`:
|
||||
|
||||
我们给Webpack提供一个或多个*入口*文件,来让它查找与合并那些从这些入口点发散出去的依赖。
|
||||
在下面这个例子中,我们的入口点是该应用的根文件`src/app.ts`:
|
||||
我们给 Webpack 提供一个或多个*入口*文件,来让它查找与合并那些从这些入口点发散出去的依赖。
|
||||
在下面这个例子中,我们的入口点是该应用的根文件 `src/app.ts`:
|
||||
|
||||
<code-example path="webpack/config/webpack.common.js" region="one-entry" title="webpack.config.js (single entry)" linenums="false">
|
||||
|
||||
|
@ -158,7 +158,7 @@ The one entry point file in this example is the application's root file, `src/ma
|
|||
|
||||
Webpack inspects that file and traverses its `import` dependencies recursively.
|
||||
|
||||
Webpack探查那个文件,并且递归遍历它的`import`依赖。
|
||||
Webpack 探查那个文件,并且递归遍历它的 `import` 依赖。
|
||||
|
||||
<code-example path="webpack/src/app/app.component.ts" region="component" title="src/main.ts" linenums="false">
|
||||
|
||||
|
@ -167,12 +167,12 @@ Webpack探查那个文件,并且递归遍历它的`import`依赖。
|
|||
It sees that you're importing `@angular/core` so it adds that to its dependency list for potential inclusion in the bundle.
|
||||
It opens the `@angular/core` file and follows _its_ network of `import` statements until it has built the complete dependency graph from `main.ts` down.
|
||||
|
||||
这里,Webpack看到我们正在导入`@angular/core`,于是就这个文件加入到它的依赖列表里,为(有可能)把该文件打进包中做准备。
|
||||
它打开`@angular/core`并追踪由_该文件的_`import`语句构成的网络,直到构建出从`main.ts`往下的整个依赖图谱。
|
||||
这里,Webpack 看到我们正在导入 `@angular/core`,于是就这个文件加入到它的依赖列表里,为(有可能)把该文件打进包中做准备。
|
||||
它打开 `@angular/core` 并追踪由_该文件的_`import` 语句构成的网络,直到构建出从 `main.ts` 往下的整个依赖图谱。
|
||||
|
||||
Then it **outputs** these files to the `app.js` _bundle file_ designated in configuration:
|
||||
|
||||
然后它把这些文件**输出**到当前配置所指定的_包文件_`app.js`中:
|
||||
然后它把这些文件**输出**到当前配置所指定的_包文件_`app.js` 中:
|
||||
|
||||
<code-example name="webpack.config.js (single output)" language="javascript">
|
||||
|
||||
|
@ -185,8 +185,8 @@ Then it **outputs** these files to the `app.js` _bundle file_ designated in conf
|
|||
This `app.js` output bundle is a single JavaScript file that contains the application source and its dependencies.
|
||||
You'll load it later with a `<script>` tag in the `index.html`.
|
||||
|
||||
这个`app.js`输出包是个单一的JavaScript文件,它包含程序的源码及其所有依赖。
|
||||
后面我们将在`index.html`中用`<script>`标签来加载它。
|
||||
这个 `app.js` 输出包是个单一的 JavaScript 文件,它包含程序的源码及其所有依赖。
|
||||
后面我们将在 `index.html` 中用 `<script>` 标签来加载它。
|
||||
|
||||
{@a multiple-bundles}
|
||||
|
||||
|
@ -201,7 +201,7 @@ It's preferable to separate the volatile application app code from comparatively
|
|||
|
||||
Change the configuration so that it has two entry points, `main.ts` and `vendor.ts`:
|
||||
|
||||
所以要修改配置,以获得两个入口点:`main.ts`和`vendor.ts`:
|
||||
所以要修改配置,以获得两个入口点:`main.ts` 和 `vendor.ts`:
|
||||
|
||||
<code-example language="javascript">
|
||||
|
||||
|
@ -220,21 +220,21 @@ Webpack constructs two separate dependency graphs
|
|||
and emits *two* bundle files, one called `app.js` containing only the application code and
|
||||
another called `vendor.js` with all the vendor dependencies.
|
||||
|
||||
Webpack会构造出两个独立的依赖图谱,并产出*两个*包文件:一个叫做`app.js`,它只包含我们的应用代码;另一个叫做`vendor.js`,它包含所有的提供商依赖。
|
||||
Webpack 会构造出两个独立的依赖图谱,并产出*两个*包文件:一个叫做 `app.js`,它只包含我们的应用代码;另一个叫做 `vendor.js`,它包含所有的提供商依赖。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
The `[name]` in the output name is a *placeholder* that a Webpack plugin replaces with the entry names,
|
||||
`app` and `vendor`. Plugins are [covered later](guide/webpack#commons-chunk-plugin) in the guide.
|
||||
|
||||
在输出文件名中出现的`[name]`是一个Webpack的*占位符*,它将被一个Webpack插件替换为入口点的名字,分别是`app`和`vendor`。插件在本章的[稍后部分](guide/webpack#commons-chunk-plugin)讲解。
|
||||
在输出文件名中出现的 `[name]` 是一个 Webpack 的*占位符*,它将被一个 Webpack 插件替换为入口点的名字,分别是 `app` 和 `vendor`。插件在本章的[稍后部分](guide/webpack#commons-chunk-plugin)讲解。
|
||||
|
||||
</div>
|
||||
|
||||
To tell Webpack what belongs in the vendor bundle,
|
||||
add a `vendor.ts` file that only imports the application's third-party modules:
|
||||
|
||||
要想告诉Webpack哪些文件属于vendor包,可以添加一个`vendor.ts`文件,它只导入该应用的第三方模块:
|
||||
要想告诉 Webpack 哪些文件属于 vendor 包,可以添加一个 `vendor.ts` 文件,它只导入该应用的第三方模块:
|
||||
|
||||
<code-example path="webpack/src/vendor.ts" title="src/vendor.ts" linenums="false">
|
||||
|
||||
|
@ -251,10 +251,10 @@ Webpack _itself_ only understands JavaScript files.
|
|||
Teach it to transform non-JavaScript file into their JavaScript equivalents with *loaders*.
|
||||
Configure loaders for TypeScript and CSS as follows.
|
||||
|
||||
Webpack可以打包任何类型的文件:JavaScript、TypeScript、CSS、SASS、LESS、图片、HTML以及字体文件等等。
|
||||
但Webpack*本身*只认识JavaScript文件。
|
||||
我们要通过*加载器*来告诉它如何把这些文件处理成JavaScript文件。
|
||||
在这里,我们为TypeScript和CSS文件配置了加载器。
|
||||
Webpack 可以打包任何类型的文件:JavaScript、TypeScript、CSS、SASS、LESS、图片、HTML 以及字体文件等等。
|
||||
但 Webpack*本身*只认识 JavaScript 文件。
|
||||
我们要通过*加载器*来告诉它如何把这些文件处理成 JavaScript 文件。
|
||||
在这里,我们为 TypeScript 和 CSS 文件配置了加载器。
|
||||
|
||||
<code-example language="javascript">
|
||||
|
||||
|
@ -274,7 +274,7 @@ Webpack可以打包任何类型的文件:JavaScript、TypeScript、CSS、SASS
|
|||
When Webpack encounters `import` statements like the following,
|
||||
it applies the `test` RegEx patterns.
|
||||
|
||||
当Webpack遇到如下所示的`import`语句时,它就会调用正则表达式的`test`方法。
|
||||
当 Webpack 遇到如下所示的 `import` 语句时,它就会调用正则表达式的 `test` 方法。
|
||||
|
||||
<code-example language="typescript">
|
||||
|
||||
|
@ -286,12 +286,12 @@ it applies the `test` RegEx patterns.
|
|||
|
||||
When a pattern matches the filename, Webpack processes the file with the associated loader.
|
||||
|
||||
如果一个模式匹配上文件名,Webpack就用它所关联的加载器处理这个文件。
|
||||
如果一个模式匹配上文件名,Webpack 就用它所关联的加载器处理这个文件。
|
||||
|
||||
The first `import` file matches the `.ts` pattern so Webpack processes it with the `awesome-typescript-loader`.
|
||||
The imported file doesn't match the second pattern so its loader is ignored.
|
||||
|
||||
第一个`import`文件匹配上了`.ts`模式,于是Webpack就用`awesome-typescript-loader`加载器处理它。
|
||||
第一个 `import` 文件匹配上了 `.ts` 模式,于是 Webpack 就用 `awesome-typescript-loader` 加载器处理它。
|
||||
导入的文件没有匹配上第二个模式,于是它的加载器就被忽略了。
|
||||
|
||||
The second `import` matches the second `.css` pattern for which you have *two* loaders chained by the (!) character.
|
||||
|
@ -299,9 +299,9 @@ Webpack applies chained loaders *right to left*. So it applies
|
|||
the `css` loader first to flatten CSS `@import` and `url(...)` statements.
|
||||
Then it applies the `style` loader to append the css inside `<style>` elements on the page.
|
||||
|
||||
第二个`import`匹配上了第二个`.css`模式,它有两个用叹号字符(`!`)串联起来的加载器。
|
||||
Webpack会*从右到左*逐个应用串联的加载器,于是它先应用了`css`加载器(用来平面化CSS的`@import`和`url(...)`语句),
|
||||
然后应用了`style`加载器(用来把css追加到页面上的*<style>*元素中)。
|
||||
第二个 `import` 匹配上了第二个 `.css` 模式,它有两个用叹号字符(`!`)串联起来的加载器。
|
||||
Webpack 会*从右到左*逐个应用串联的加载器,于是它先应用了 `css` 加载器(用来平面化 CSS 的 `@import` 和 `url(...)` 语句),
|
||||
然后应用了 `style` 加载器(用来把 css 追加到页面上的*<style>*元素中)。
|
||||
|
||||
{@a plugins}
|
||||
|
||||
|
@ -312,8 +312,8 @@ Webpack会*从右到左*逐个应用串联的加载器,于是它先应用了`c
|
|||
Webpack has a build pipeline with well-defined phases.
|
||||
Tap into that pipeline with plugins such as the `uglify` minification plugin:
|
||||
|
||||
Webpack有一条构建流水线,它被划分成多个经过精心定义的阶段(phase)。
|
||||
我们可以把插件(比如`uglify`代码最小化插件)挂到流水线上:
|
||||
Webpack 有一条构建流水线,它被划分成多个经过精心定义的阶段(phase)。
|
||||
我们可以把插件(比如 `uglify` 代码最小化插件)挂到流水线上:
|
||||
|
||||
<code-example language="javascript">
|
||||
|
||||
|
@ -327,11 +327,11 @@ Webpack有一条构建流水线,它被划分成多个经过精心定义的阶
|
|||
|
||||
## Configuring Webpack
|
||||
|
||||
## 配置Webpack
|
||||
## 配置 Webpack
|
||||
|
||||
After that brief orientation, you are ready to build your own Webpack configuration for Angular apps.
|
||||
|
||||
经过简短的培训之后,我们准备为Angular应用构建一份自己的Webpack配置了。
|
||||
经过简短的培训之后,我们准备为 Angular 应用构建一份自己的 Webpack 配置了。
|
||||
|
||||
Begin by setting up the development environment.
|
||||
|
||||
|
@ -382,12 +382,12 @@ Many of these files should be familiar from other Angular documentation guides,
|
|||
especially the [Typescript configuration](guide/typescript-configuration) and
|
||||
[npm packages](guide/npm-packages) guides.
|
||||
|
||||
这些文件很多都很眼熟,它们在其他文档里已经出现过,特别是[_TypeScript配置_](guide/typescript-configuration)和[_npm包_](guide/npm-packages)这两章里。
|
||||
这些文件很多都很眼熟,它们在其他文档里已经出现过,特别是[_TypeScript 配置_](guide/typescript-configuration)和[_npm 包_](guide/npm-packages)这两章里。
|
||||
|
||||
Webpack, the plugins, and the loaders are also installed as packages.
|
||||
They are listed in the updated `packages.json`.
|
||||
|
||||
Webpack,包括它的插件以及加载器,也是以npm包的形式安装的,它们也列在了修改后的 package.json 中。
|
||||
Webpack,包括它的插件以及加载器,也是以 npm 包的形式安装的,它们也列在了修改后的 package.json 中。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -410,12 +410,12 @@ Open a terminal window and install the npm packages.
|
|||
You'll need polyfills to run an Angular application in most browsers as explained
|
||||
in the [Browser Support](guide/browser-support) guide.
|
||||
|
||||
我们在[_浏览器支持_](guide/browser-support)章节里解释过,Angular应用要能在大多数的浏览器里运行,它还需要一些polyfills。
|
||||
我们在[_浏览器支持_](guide/browser-support)章节里解释过,Angular 应用要能在大多数的浏览器里运行,它还需要一些 polyfills。
|
||||
|
||||
Polyfills should be bundled separately from the application and vendor bundles.
|
||||
Add a `polyfills.ts` like this one to the `src/` folder.
|
||||
|
||||
Polyfills最好跟应用代码和vendor代码区分开来单独打包,所以我们需要在`src/`文件夹里添加一个`polyfills.ts`文件,代码如下:
|
||||
Polyfills 最好跟应用代码和 vendor 代码区分开来单独打包,所以我们需要在 `src/` 文件夹里添加一个 `polyfills.ts` 文件,代码如下:
|
||||
|
||||
<code-example path="webpack/src/polyfills.ts" title="src/polyfills.ts" linenums="false">
|
||||
|
||||
|
@ -431,14 +431,14 @@ Polyfills最好跟应用代码和vendor代码区分开来单独打包,所以
|
|||
|
||||
Load `zone.js` early within `polyfills.ts`, immediately after the other ES6 and metadata shims.
|
||||
|
||||
`polyfills.ts`文件里,`zone.js`库须尽早引入,紧跟在ES6 shims和metadata shims之后。
|
||||
`polyfills.ts` 文件里,`zone.js` 库须尽早引入,紧跟在 ES6 shims 和 metadata shims 之后。
|
||||
|
||||
</div>
|
||||
|
||||
Because this bundle file will load first, `polyfills.ts` is also a good place to configure the browser environment
|
||||
for production or development.
|
||||
|
||||
由于这个包最先加载,所以`polyfills.ts`非常适合用来配置浏览器环境,如生产环境配置或是开发环境。
|
||||
由于这个包最先加载,所以 `polyfills.ts` 非常适合用来配置浏览器环境,如生产环境配置或是开发环境。
|
||||
|
||||
{@a common-configuration}
|
||||
|
||||
|
@ -453,7 +453,7 @@ All three have a lot of configuration in common.
|
|||
|
||||
Gather the common configuration in a file called `webpack.common.js`.
|
||||
|
||||
我们可以把这些通用的配置收归到一个文件,命名为`webpack.common.js`。
|
||||
我们可以把这些通用的配置收归到一个文件,命名为 `webpack.common.js`。
|
||||
|
||||
<code-example path="webpack/config/webpack.common.js" title="config/webpack.common.js" linenums="false">
|
||||
|
||||
|
@ -463,16 +463,16 @@ Gather the common configuration in a file called `webpack.common.js`.
|
|||
|
||||
### Inside _webpack.common.js_
|
||||
|
||||
### webpack.common.js解读
|
||||
### webpack.common.js 解读
|
||||
|
||||
Webpack is a NodeJS-based tool that reads configuration from a JavaScript commonjs module file.
|
||||
|
||||
Webpack是基于NodeJS的一个工具,它能够从一个*commonjs*规范的JavaScript模块文件里读取配置。
|
||||
Webpack 是基于 NodeJS 的一个工具,它能够从一个*commonjs*规范的 JavaScript 模块文件里读取配置。
|
||||
|
||||
The configuration imports dependencies with `require` statements
|
||||
and exports several objects as properties of a `module.exports` object.
|
||||
|
||||
这个配置文件是通过`require`语句导入依赖,然后将多个对象作为`module.exports`对象的属性导出。
|
||||
这个配置文件是通过 `require` 语句导入依赖,然后将多个对象作为 `module.exports` 对象的属性导出。
|
||||
|
||||
* [`entry`](guide/webpack#common-entries)—the entry-point files that define the bundles.
|
||||
|
||||
|
@ -484,7 +484,7 @@ and exports several objects as properties of a `module.exports` object.
|
|||
|
||||
* [`module.rules`](guide/webpack#common-rules)— `module` is an object with `rules` for deciding how files are loaded.
|
||||
|
||||
[`module.rules`](guide/webpack#common-rules) - `module`是一个对象,里面的`rules`属性用来决定文件如何加载。
|
||||
[`module.rules`](guide/webpack#common-rules) - `module` 是一个对象,里面的 `rules` 属性用来决定文件如何加载。
|
||||
|
||||
* [`plugins`](guide/webpack#common-plugins)—creates instances of the plugins.
|
||||
|
||||
|
@ -506,15 +506,15 @@ The first export is the `entry` object:
|
|||
|
||||
This `entry` object defines the three bundles:
|
||||
|
||||
`entry`对象定义了三个包:
|
||||
`entry` 对象定义了三个包:
|
||||
|
||||
* `polyfills`—the polyfills needed to run Angular applications in most modern browsers.
|
||||
|
||||
`polyfills` - 使得Angular应用能够运行在大多数的现代浏览器。
|
||||
`polyfills` - 使得 Angular 应用能够运行在大多数的现代浏览器。
|
||||
|
||||
* `vendor`—the third-party dependencies such as Angular, lodash, and bootstrap.css.
|
||||
|
||||
`vendor` - 第三方依赖,如Angular、lodash和bootstrap.css。
|
||||
`vendor` - 第三方依赖,如 Angular、lodash 和 bootstrap.css。
|
||||
|
||||
* `app`—the application code.
|
||||
|
||||
|
@ -529,7 +529,7 @@ This `entry` object defines the three bundles:
|
|||
The app will `import` dozens if not hundreds of JavaScript and TypeScript files.
|
||||
You could write `import` statements with explicit extensions like this example:
|
||||
|
||||
如果你的应用程序只须`import`几十个JavaScript或TypeScript文件,而不是几百个,你可以在`import`语句里完整写上扩展名,如:
|
||||
如果你的应用程序只须 `import` 几十个 JavaScript 或 TypeScript 文件,而不是几百个,你可以在 `import` 语句里完整写上扩展名,如:
|
||||
|
||||
<code-example language="typescript">
|
||||
|
||||
|
@ -541,7 +541,7 @@ But most `import` statements don't mention the extension at all.
|
|||
Tell Webpack to resolve extension-less file requests by looking for matching files with
|
||||
`.ts` extension or `.js` extension (for regular JavaScript files and pre-compiled TypeScript files).
|
||||
|
||||
但实际上大部分`import`语句都不带扩展名,我们可以告诉Webpack,在查找这些没有扩展名的文件时,自动加上`.ts`或者`.js`扩展名来匹配。
|
||||
但实际上大部分 `import` 语句都不带扩展名,我们可以告诉 Webpack,在查找这些没有扩展名的文件时,自动加上 `.ts` 或者 `.js` 扩展名来匹配。
|
||||
|
||||
<code-example path="webpack/config/webpack.common.js" region="resolve" title="config/webpack.common.js" linenums="false">
|
||||
|
||||
|
@ -552,7 +552,7 @@ Tell Webpack to resolve extension-less file requests by looking for matching fil
|
|||
If Webpack should resolve extension-less files for styles and HTML,
|
||||
add `.css` and `.html` to the list.
|
||||
|
||||
如果我们希望Webapck也能解析不带扩展名的样式和HTML文件,在列表里追加`.css`和`.html`即可。
|
||||
如果我们希望 Webapck 也能解析不带扩展名的样式和 HTML 文件,在列表里追加 `.css` 和 `.html` 即可。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -564,7 +564,7 @@ add `.css` and `.html` to the list.
|
|||
|
||||
Rules tell Webpack which loaders to use for each file, or module:
|
||||
|
||||
Rules用来告诉Webpack加载不同文件或模块时该用哪个加载器。
|
||||
Rules 用来告诉 Webpack 加载不同文件或模块时该用哪个加载器。
|
||||
|
||||
<code-example path="webpack/config/webpack.common.js" region="loaders" title="config/webpack.common.js" linenums="false">
|
||||
|
||||
|
@ -572,11 +572,11 @@ Rules用来告诉Webpack加载不同文件或模块时该用哪个加载器。
|
|||
|
||||
* `awesome-typescript-loader`—a loader to transpile the Typescript code to ES5, guided by the `tsconfig.json` file.
|
||||
|
||||
`awesome-typescript-loader` - 一个用于把TypeScript代码转译成ES5的加载器,它会由`tsconfig.json`文件提供指导
|
||||
`awesome-typescript-loader` - 一个用于把 TypeScript 代码转译成 ES5 的加载器,它会由 `tsconfig.json` 文件提供指导
|
||||
|
||||
* `angular2-template-loader`—loads angular components' template and styles.
|
||||
|
||||
`angular2-template-loader` - 用于加载Angular组件的模板和样式
|
||||
`angular2-template-loader` - 用于加载 Angular 组件的模板和样式
|
||||
|
||||
* `html-loader`—for component templates.
|
||||
|
||||
|
@ -589,7 +589,7 @@ Rules用来告诉Webpack加载不同文件或模块时该用哪个加载器。
|
|||
* CSS—the first pattern matches application-wide styles; the second handles
|
||||
component-scoped styles (the ones specified in a component's `styleUrls` metadata property).
|
||||
|
||||
CSS - 第一个模式匹配应用级样式,第二个模式匹配组件局部样式(就是在组件元数据的`styleUrls`属性中指定的那些)。
|
||||
CSS - 第一个模式匹配应用级样式,第二个模式匹配组件局部样式(就是在组件元数据的 `styleUrls` 属性中指定的那些)。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
|
@ -597,14 +597,14 @@ The first pattern is for the application-wide styles. It excludes `.css` files w
|
|||
where the component-scoped styles sit. The `ExtractTextPlugin` (described below) applies the `style` and `css`
|
||||
loaders to these files.
|
||||
|
||||
第一个模式是给全局样式使用的,它排除了`/src/app`目录下的`.css`文件,因为那里放着我们的组件局部样式。
|
||||
它只包含了那些位于`/src/app`及其上级目录的`.css`文件,那里是应用级样式。
|
||||
`ExtractTextPlugin`(后面会讲到)使用`style`和`css`加载器来处理这些文件。
|
||||
第一个模式是给全局样式使用的,它排除了 `/src/app` 目录下的 `.css` 文件,因为那里放着我们的组件局部样式。
|
||||
它只包含了那些位于 `/src/app` 及其上级目录的 `.css` 文件,那里是应用级样式。
|
||||
`ExtractTextPlugin`(后面会讲到)使用 `style` 和 `css` 加载器来处理这些文件。
|
||||
|
||||
The second pattern filters for component-scoped styles and loads them as strings via the `raw-loader`,
|
||||
which is what Angular expects to do with styles specified in a `styleUrls` metadata property.
|
||||
|
||||
第二个模式过滤器是给组件局部样式的,并通过`raw`加载器把它们加载成字符串 —— 那是Angular期望通过元数据的`styleUrls`属性来指定样式的形式。
|
||||
第二个模式过滤器是给组件局部样式的,并通过 `raw` 加载器把它们加载成字符串 —— 那是 Angular 期望通过元数据的 `styleUrls` 属性来指定样式的形式。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -638,15 +638,15 @@ Finally, create instances of three plugins:
|
|||
|
||||
The `app.js` bundle should contain only application code. All vendor code belongs in the `vendor.js` bundle.
|
||||
|
||||
`app.js`包应该只包含应用代码。所有第三方代码都应该放进`vendor.js`包中。
|
||||
`app.js` 包应该只包含应用代码。所有第三方代码都应该放进 `vendor.js` 包中。
|
||||
|
||||
Of course the application code imports vendor code.
|
||||
On its own, Webpack is not smart enough to keep the vendor code out of the `app.js` bundle.
|
||||
The `CommonsChunkPlugin` does that job.
|
||||
|
||||
当然,应用代码中还是要`imports`第三方代码。
|
||||
Webpack还没有智能到自动把提供商代码排除在`app.js`包之外的程度。
|
||||
`CommonsChunkPlugin`插件能完成此工作。
|
||||
当然,应用代码中还是要 `imports` 第三方代码。
|
||||
Webpack 还没有智能到自动把提供商代码排除在 `app.js` 包之外的程度。
|
||||
`CommonsChunkPlugin` 插件能完成此工作。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
|
@ -654,9 +654,9 @@ The `CommonsChunkPlugin` identifies the hierarchy among three _chunks_: `app` ->
|
|||
Where Webpack finds that `app` has shared dependencies with `vendor`, it removes them from `app`.
|
||||
It would remove `polyfills` from `vendor` if they shared dependencies, which they don't.
|
||||
|
||||
`CommonsChunkPlugin`标记出了三个_块_之间的等级体系:`app` -> `vendor` -> `polyfills`。
|
||||
当Webpack发现`app`与`vendor`有共享依赖时,就把它们从`app`中移除。
|
||||
在`vendor`和`polyfills`之间有共享依赖时也同样如此(虽然它们没啥可共享的)。
|
||||
`CommonsChunkPlugin` 标记出了三个_块_之间的等级体系:`app` -> `vendor` -> `polyfills`。
|
||||
当 Webpack 发现 `app` 与 `vendor` 有共享依赖时,就把它们从 `app` 中移除。
|
||||
在 `vendor` 和 `polyfills` 之间有共享依赖时也同样如此(虽然它们没啥可共享的)。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -670,9 +670,9 @@ Webpack generates a number of js and CSS files.
|
|||
You _could_ insert them into the `index.html` _manually_. That would be tedious and error-prone.
|
||||
Webpack can inject those scripts and links for you with the `HtmlWebpackPlugin`.
|
||||
|
||||
Webpack生成了一些js和css文件。
|
||||
虽然我们_可以手动_把它们插入到`index.html`中,但那样既枯燥又容易出错。
|
||||
Webpack可以通过`HtmlWebpackPlugin`自动为我们注入那些`script`和`link`标签。
|
||||
Webpack 生成了一些 js 和 css 文件。
|
||||
虽然我们_可以手动_把它们插入到 `index.html` 中,但那样既枯燥又容易出错。
|
||||
Webpack 可以通过 `HtmlWebpackPlugin` 自动为我们注入那些 `script` 和 `link` 标签。
|
||||
|
||||
{@a environment-configuration}
|
||||
|
||||
|
@ -684,8 +684,8 @@ The `webpack.common.js` configuration file does most of the heavy lifting.
|
|||
Create separate, environment-specific configuration files that build on `webpack.common`
|
||||
by merging into it the peculiarities particular to the target environments.
|
||||
|
||||
`webpack.common.js`配置做了大部分繁重的工作。
|
||||
通过合并它们特有的配置,我们可以基于`webpack.common`为目标环境创建独立的、环境相关的配置文件。
|
||||
`webpack.common.js` 配置做了大部分繁重的工作。
|
||||
通过合并它们特有的配置,我们可以基于 `webpack.common` 为目标环境创建独立的、环境相关的配置文件。
|
||||
|
||||
These files tend to be short and simple.
|
||||
|
||||
|
@ -699,7 +699,7 @@ These files tend to be short and simple.
|
|||
|
||||
Here is the `webpack.dev.js` development configuration file.
|
||||
|
||||
下面是开发环境的而配置文件`webpack.dev.js`:
|
||||
下面是开发环境的而配置文件 `webpack.dev.js`:
|
||||
|
||||
<code-example path="webpack/config/webpack.dev.js" title="config/webpack.dev.js" linenums="false">
|
||||
|
||||
|
@ -707,27 +707,27 @@ Here is the `webpack.dev.js` development configuration file.
|
|||
|
||||
The development build relies on the Webpack development server, configured near the bottom of the file.
|
||||
|
||||
开发环境下的构建依赖于Webpack的开发服务器,我们在靠近文件底部的地方配置了它。
|
||||
开发环境下的构建依赖于 Webpack 的开发服务器,我们在靠近文件底部的地方配置了它。
|
||||
|
||||
Although you tell Webpack to put output bundles in the `dist` folder,
|
||||
the dev server keeps all bundles in memory; it doesn't write them to disk.
|
||||
You won't find any files in the `dist` folder, at least not any generated from *this development build*.
|
||||
|
||||
虽然我们告诉Webpack把输出包放到`dist`目录,但实际上开发服务器把这些包都放在了内存里,而不会把它们写到硬盘中。
|
||||
所以在`dist`目录下是找不到任何文件的(至少现在这个开发环境下构建时没有)。
|
||||
虽然我们告诉 Webpack 把输出包放到 `dist` 目录,但实际上开发服务器把这些包都放在了内存里,而不会把它们写到硬盘中。
|
||||
所以在 `dist` 目录下是找不到任何文件的(至少现在这个开发环境下构建时没有)。
|
||||
|
||||
The `HtmlWebpackPlugin`, added in `webpack.common.js`, uses the `publicPath` and the `filename` settings to generate
|
||||
appropriate `<script>` and `<link>` tags into the `index.html`.
|
||||
|
||||
`HtmlWebpackPlugin`(由`webpack.common.js`引入)插件使用了*`publicPath`*和*`filename`*设置,
|
||||
来向`index.html`中插入适当的<script>和<link>标签。
|
||||
`HtmlWebpackPlugin`(由 `webpack.common.js` 引入)插件使用了*`publicPath`*和*`filename`*设置,
|
||||
来向 `index.html` 中插入适当的<script>和<link>标签。
|
||||
|
||||
The CSS styles are buried inside the Javascript bundles by default. The `ExtractTextPlugin` extracts them into
|
||||
external `.css` files that the `HtmlWebpackPlugin` inscribes as `<link>` tags into the `index.html`.
|
||||
|
||||
默认情况下,我们这些CSS样式会被埋没在JavaScript包中。`ExtractTextPlugin`会把它们提取成外部`.css`文件,
|
||||
这样`HtmlWebpackPlugin`插件就会转而把一个<link>标签写进`index.html`了。Refer to the [Webpack documentation](https://webpack.github.io/docs/) for details on these and
|
||||
other configuration options in this file.要了解本文件中这些以及其它配置项的详情,请参阅[Webpack文档](https://webpack.github.io/docs/)。
|
||||
默认情况下,我们这些 CSS 样式会被埋没在 JavaScript 包中。`ExtractTextPlugin` 会把它们提取成外部 `.css` 文件,
|
||||
这样 `HtmlWebpackPlugin` 插件就会转而把一个<link>标签写进 `index.html` 了。Refer to the [Webpack documentation](https://webpack.github.io/docs/) for details on these and
|
||||
other configuration options in this file.要了解本文件中这些以及其它配置项的详情,请参阅[Webpack 文档](https://webpack.github.io/docs/)。
|
||||
|
||||
Refer to the [Webpack documentation](https://webpack.github.io/docs/) for details on these and
|
||||
other configuration options in this file.
|
||||
|
@ -766,13 +766,13 @@ You won't deploy the artifacts needed only in development.
|
|||
|
||||
Put the production output bundle files in the `dist` folder.
|
||||
|
||||
把产品环境的输出包放在`dist`目录下。
|
||||
把产品环境的输出包放在 `dist` 目录下。
|
||||
|
||||
Webpack generates file names with cache-busting hash.
|
||||
Thanks to the `HtmlWebpackPlugin`, you don't have to update the `index.html` file when the hash changes.
|
||||
|
||||
Webpack生成的文件名中带有“缓存无效哈希(cache-busting hash)”。
|
||||
感谢`HtmlWebpackPlugin`插件,当这些哈希值变化时,我们不用去更新`index.html`了。
|
||||
Webpack 生成的文件名中带有“缓存无效哈希(cache-busting hash)”。
|
||||
感谢 `HtmlWebpackPlugin` 插件,当这些哈希值变化时,我们不用去更新 `index.html` 了。
|
||||
|
||||
There are additional plugins:
|
||||
|
||||
|
@ -788,7 +788,7 @@ There are additional plugins:
|
|||
|
||||
* *`ExtractTextPlugin`—extracts embedded css as external files, adding cache-busting hash to the filename.
|
||||
|
||||
*`ExtractTextPlugin`* - 把内嵌的css抽取成外部文件,并为其文件名添加“缓存无效哈希”。
|
||||
*`ExtractTextPlugin`* - 把内嵌的 css 抽取成外部文件,并为其文件名添加“缓存无效哈希”。
|
||||
|
||||
* *`DefinePlugin`—use to define environment variables that you can reference within the application.
|
||||
|
||||
|
@ -800,7 +800,7 @@ There are additional plugins:
|
|||
|
||||
Thanks to the `DefinePlugin` and the `ENV` variable defined at top, you can enable Angular production mode like this:
|
||||
|
||||
感谢*DefinePlugin*和顶部定义的`ENV`变量,我们就可以像这样启用Angular的产品模式了:
|
||||
感谢*DefinePlugin*和顶部定义的 `ENV` 变量,我们就可以像这样启用 Angular 的产品模式了:
|
||||
|
||||
<code-example path="webpack/src/main.ts" region="enable-prod" title="src/main.ts" linenums="false">
|
||||
|
||||
|
@ -829,12 +829,12 @@ you'll use the `null` loader for those CSS files.
|
|||
|
||||
我们并不需要使用很多配置项来运行单元测试。
|
||||
也不需要在开发环境和产品环境下引入的那些加载器和插件。
|
||||
如果有可能拖慢执行速度,甚至都不需要在单元测试中加载和处理应用全局样式文件,所以我们用一个`null`加载器来处理所有CSS。
|
||||
如果有可能拖慢执行速度,甚至都不需要在单元测试中加载和处理应用全局样式文件,所以我们用一个 `null` 加载器来处理所有 CSS。
|
||||
|
||||
You could merge the test configuration into the `webpack.common` configuration and override the parts you don't want or need.
|
||||
But it might be simpler to start over with a completely fresh configuration.
|
||||
|
||||
我们可以把测试环境的配置合并到`webpack.common`配置中,并且改写不想要或不需要的部分。
|
||||
我们可以把测试环境的配置合并到 `webpack.common` 配置中,并且改写不想要或不需要的部分。
|
||||
但是从一个全新的配置开始可能更简单。
|
||||
|
||||
<code-example path="webpack/config/webpack.test.js" title="config/webpack.test.js" linenums="false">
|
||||
|
@ -843,7 +843,7 @@ But it might be simpler to start over with a completely fresh configuration.
|
|||
|
||||
Reconfigure [Karma](https://karma-runner.github.io/1.0/index.html) to use Webpack to run the tests:
|
||||
|
||||
重新配置[Karma](https://karma-runner.github.io/1.0/index.html),让它使用webpack来运行这些测试:
|
||||
重新配置[Karma](https://karma-runner.github.io/1.0/index.html),让它使用 webpack 来运行这些测试:
|
||||
|
||||
<code-example path="webpack/config/karma.conf.js" title="config/karma.conf.js" linenums="false">
|
||||
|
||||
|
@ -852,13 +852,13 @@ Reconfigure [Karma](https://karma-runner.github.io/1.0/index.html) to use Webpac
|
|||
You don't precompile the TypeScript; Webpack transpiles the Typescript files on the fly, in memory, and feeds the emitted JS directly to Karma.
|
||||
There are no temporary files on disk.
|
||||
|
||||
我们不用预编译TypeScript,Webpack随时在内存中转译我们的TypeScript文件,并且把产出的JS直接反馈给Karma。
|
||||
我们不用预编译 TypeScript,Webpack 随时在内存中转译我们的 TypeScript 文件,并且把产出的 JS 直接反馈给 Karma。
|
||||
硬盘上没有任何临时文件。
|
||||
|
||||
The `karma-test-shim` tells Karma what files to pre-load and
|
||||
primes the Angular test framework with test versions of the providers that every app expects to be pre-loaded.
|
||||
|
||||
`karma-test-shim`告诉Karma哪些文件需要预加载,首要的是:带有“测试版提供商”的Angular测试框架是每个应用都希望预加载的。
|
||||
`karma-test-shim` 告诉 Karma 哪些文件需要预加载,首要的是:带有“测试版提供商”的 Angular 测试框架是每个应用都希望预加载的。
|
||||
|
||||
<code-example path="webpack/config/karma-test-shim.js" title="config/karma-test-shim.js" linenums="false">
|
||||
|
||||
|
@ -870,9 +870,9 @@ Each spec file imports all—and only—the application source code that
|
|||
Webpack loads just _those_ specific application files and ignores the other files that you aren't testing.
|
||||
|
||||
注意,我们_并没有_明确加载这些应用代码。
|
||||
只是告诉Webpack查找并加载我们的测试文件(文件名以`.spec.ts`结尾)。
|
||||
只是告诉 Webpack 查找并加载我们的测试文件(文件名以 `.spec.ts` 结尾)。
|
||||
每个规约(spec)文件都导入了所有(也只有)它测试所需的应用源码。
|
||||
Webpack只加载_那些_特定的应用文件,而忽略所有其它我们不会测试到的。
|
||||
Webpack 只加载_那些_特定的应用文件,而忽略所有其它我们不会测试到的。
|
||||
|
||||
Grab the app code at the end of this guide and try:
|
||||
|
||||
|
@ -893,7 +893,7 @@ Grab the app code at the end of this guide and try:
|
|||
Here is the source code for a small application that bundles with the
|
||||
Webpack techniques covered in this guide.
|
||||
|
||||
这里是一个小型应用的全部源码,我们可以用本章中学到的Webpack技术打包它们。
|
||||
这里是一个小型应用的全部源码,我们可以用本章中学到的 Webpack 技术打包它们。
|
||||
|
||||
<code-tabs>
|
||||
|
||||
|
@ -941,16 +941,16 @@ The <code>app.component.html</code> displays this downloadable Angular logo
|
|||
Create a folder called `images` under the project's `assets` folder, then right-click (Cmd+click on Mac)
|
||||
on the image and download it to that folder.
|
||||
|
||||
<code>app.component.html</code>显示了这个可下载的Angular Logo
|
||||
<code>app.component.html</code>显示了这个可下载的 Angular Logo
|
||||
<a href="assets/images/logos/angular/angular.png" target="_blank">
|
||||
<img src="assets/images/logos/angular/angular.png" height="40px" title="download Angular logo"></a>。
|
||||
在项目的`assets`目录下创建一个名叫`images`的文件夹,然后右键点击(Mac上是Cmd+点击)本图片,并把它下载到`images`文件夹中。
|
||||
在项目的 `assets` 目录下创建一个名叫 `images` 的文件夹,然后右键点击(Mac 上是 Cmd+点击)本图片,并把它下载到 `images` 文件夹中。
|
||||
|
||||
{@a bundle-ts}
|
||||
|
||||
Here again are the TypeScript entry-point files that define the `polyfills` and `vendor` bundles.
|
||||
|
||||
这里又是TypeScript的入口点文件,它定义了`polyfills`和`vendor`这两个包。
|
||||
这里又是 TypeScript 的入口点文件,它定义了 `polyfills` 和 `vendor` 这两个包。
|
||||
|
||||
<code-tabs>
|
||||
|
||||
|
@ -973,27 +973,27 @@ Here again are the TypeScript entry-point files that define the `polyfills` and
|
|||
* There are no `<script>` or `<link>` tags in the `index.html`.
|
||||
The `HtmlWebpackPlugin` inserts them dynamically at runtime.
|
||||
|
||||
在`index.html`中没有<script>或<link>标签。
|
||||
`HtmlWebpackPlugin`会在运行时动态插入它们。
|
||||
在 `index.html` 中没有<script>或<link>标签。
|
||||
`HtmlWebpackPlugin` 会在运行时动态插入它们。
|
||||
|
||||
* The `AppComponent` in `app.component.ts` imports the application-wide css with a simple `import` statement.
|
||||
|
||||
`app.component.ts`中的`AppComponent`类简单的用一个`import`语句导入了应用级css。
|
||||
`app.component.ts` 中的 `AppComponent` 类简单的用一个 `import` 语句导入了应用级 css。
|
||||
|
||||
* The `AppComponent` itself has its own html template and css file. WebPack loads them with calls to `require()`.
|
||||
Webpack stashes those component-scoped files in the `app.js` bundle too.
|
||||
You don't see those calls in the source code;
|
||||
they're added behind the scenes by the `angular2-template-loader` plug-in.
|
||||
|
||||
`AppComponent`组件本身有它自己的HTML模板和CSS文件。Webpack通过调用`require()`方法加载它们。Webpack还把那些组件内部的文件打包进了`app.js`中。
|
||||
我们在自己的源码中看不到这些调用,这些工作是由幕后的`angular2-template-loader`插件完成的。
|
||||
`AppComponent` 组件本身有它自己的 HTML 模板和 CSS 文件。Webpack 通过调用 `require()` 方法加载它们。Webpack 还把那些组件内部的文件打包进了 `app.js` 中。
|
||||
我们在自己的源码中看不到这些调用,这些工作是由幕后的 `angular2-template-loader` 插件完成的。
|
||||
|
||||
* The `vendor.ts` consists of vendor dependency `import` statements that drive the `vendor.js` bundle.
|
||||
The application imports these modules too; they'd be duplicated in the `app.js` bundle
|
||||
if the `CommonsChunkPlugin` hadn't detected the overlap and removed them from `app.js`.
|
||||
|
||||
`vendor.ts`由`import`提供商依赖的语句组成,它最终决定了`vender.js`的内容。
|
||||
本应用也导入这些模块,如果没有`CommonsChunkPlugin`插件检测出这种重叠,并且把它们从`app.js`中移除,它们就会同时出现在`app.js`包中。
|
||||
`vendor.ts` 由 `import` 提供商依赖的语句组成,它最终决定了 `vender.js` 的内容。
|
||||
本应用也导入这些模块,如果没有 `CommonsChunkPlugin` 插件检测出这种重叠,并且把它们从 `app.js` 中移除,它们就会同时出现在 `app.js` 包中。
|
||||
|
||||
{@a conclusion}
|
||||
|
||||
|
@ -1004,11 +1004,11 @@ if the `CommonsChunkPlugin` hadn't detected the overlap and removed them from `a
|
|||
You've learned just enough Webpack to configurate development, test and production builds
|
||||
for a small Angular application.
|
||||
|
||||
我们学到了刚好够用来在开发、测试、产品环境下构建一个小型Angular应用的Webpack配置知识。
|
||||
我们学到了刚好够用来在开发、测试、产品环境下构建一个小型 Angular 应用的 Webpack 配置知识。
|
||||
|
||||
_You could always do more_. Search the web for expert advice and expand your Webpack knowledge.
|
||||
|
||||
_但我们还能做得更多_。搜索互联网来获得专家的建议,并扩展你对Webpack的认识。
|
||||
_但我们还能做得更多_。搜索互联网来获得专家的建议,并扩展你对 Webpack 的认识。
|
||||
|
||||
[Back to top](guide/webpack#top)
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ using [types](https://www.typescriptlang.org/docs/handbook/classes.html "TypeScr
|
|||
and using [decorators](https://www.typescriptlang.org/docs/handbook/decorators.html "Decorators") for metadata.
|
||||
|
||||
本文档假设你已经熟悉了 [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript "Learn JavaScript") 和来自 [最新标准](https://babeljs.io/learn-es2015/ "Latest JavaScript standards") 的一些知识,比如 [类](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes "ES2015 Classes") 和 [模块](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import "ES2015 Modules")。
|
||||
下列代码范例都是用最新版本的JavaScript写的,利用 [类型](https://www.typescriptlang.org/docs/handbook/classes.html "TypeScript Types") 实现依赖注入,并使用[装饰器](https://www.typescriptlang.org/docs/handbook/decorators.html "Decorators")来提供元数据。
|
||||
下列代码范例都是用最新版本的 JavaScript 写的,利用 [类型](https://www.typescriptlang.org/docs/handbook/classes.html "TypeScript Types") 实现依赖注入,并使用[装饰器](https://www.typescriptlang.org/docs/handbook/decorators.html "Decorators")来提供元数据。
|
||||
|
||||
## Feedback
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
本文档的两位译者汪志成和叶志敏是多年的好友。这次利用业余时间联手翻译,就是因为看好 Angular 的前景,希望帮助大家在这项技术上能跟国外同步前进。
|
||||
|
||||
### 汪志成(雪狼)
|
||||
《AngularJS深度剖析与最佳实践》的作者之一,ThoughtWorks 高级咨询师,现任 GDE( Google 开发者专家)。崇尚“简单、专业、分享”。他从1998年开始做商业软件开发,拥有超过19年的从业经验,至今仍热衷于编程。
|
||||
《AngularJS 深度剖析与最佳实践》的作者之一,ThoughtWorks 高级咨询师,现任 GDE( Google 开发者专家)。崇尚“简单、专业、分享”。他从 1998 年开始做商业软件开发,拥有超过 19 年的从业经验,至今仍热衷于编程。
|
||||
|
||||
虽然一直在做编程工作,不过他最热衷的却是国学,特别是儒学与诗词。孟子曰:“得天下英才而教育之,三乐也”,愿践行之。
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
|||
早期翻译软件《东方快车》的产品经理,至今已在英国留学和生活了十年。目前他正在用 Angular 与 .net core 开发一套针对英国医疗保健服务行业的 ERP 系统。
|
||||
|
||||
### 杨林
|
||||
北京师范大学珠海分校教师,博士,研究方向是软件工程、信息管理系统。喜爱编程,有近20年的软件开发经验。目前正在使用
|
||||
北京师范大学珠海分校教师,博士,研究方向是软件工程、信息管理系统。喜爱编程,有近 20 年的软件开发经验。目前正在使用
|
||||
Angular 和 Grails 开发高校[教务管理系统](http://www.github.com/jwgl)。
|
||||
|
||||
## 感恩
|
||||
|
@ -71,27 +71,27 @@ Angular 和 Grails 开发高校[教务管理系统](http://www.github.com/jwgl)
|
|||
- looding(来自 Github )
|
||||
- linyang4(来自 Github )
|
||||
- bluewaitor(来自 Github )
|
||||
- zhouchangsheng(来自Github)
|
||||
- wxchenxueqi(来自Github)
|
||||
- VelChen(来自Github)
|
||||
- vthinkxie(来自Github)
|
||||
- trotyl(来自Github)
|
||||
- jiabiao(来自Github)
|
||||
- perry2008084(来自Github)
|
||||
- fnpac(来自Github)
|
||||
- WittBulter(来自Github)
|
||||
- buzzerrookie(来自Github)
|
||||
- ananiy(来自Github)
|
||||
- zdouble(来自Github)
|
||||
- OuYancey(来自Github)
|
||||
- GenweiWu(来自Github)
|
||||
- dxyqqs(来自Github)
|
||||
- wkylin(来自Github)
|
||||
- rthel(来自Github)
|
||||
- nickChenyx(来自Github)
|
||||
- HNUHell(来自Github)
|
||||
- SkyStardust(来自Github)
|
||||
- Eve(来自Github)
|
||||
- zhouchangsheng(来自 Github)
|
||||
- wxchenxueqi(来自 Github)
|
||||
- VelChen(来自 Github)
|
||||
- vthinkxie(来自 Github)
|
||||
- trotyl(来自 Github)
|
||||
- jiabiao(来自 Github)
|
||||
- perry2008084(来自 Github)
|
||||
- fnpac(来自 Github)
|
||||
- WittBulter(来自 Github)
|
||||
- buzzerrookie(来自 Github)
|
||||
- ananiy(来自 Github)
|
||||
- zdouble(来自 Github)
|
||||
- OuYancey(来自 Github)
|
||||
- GenweiWu(来自 Github)
|
||||
- dxyqqs(来自 Github)
|
||||
- wkylin(来自 Github)
|
||||
- rthel(来自 Github)
|
||||
- nickChenyx(来自 Github)
|
||||
- HNUHell(来自 Github)
|
||||
- SkyStardust(来自 Github)
|
||||
- Eve(来自 Github)
|
||||
- 另外还有一些做好事不留名的活雷锋
|
||||
|
||||
想让你的名字也出现在这里吗?请提供[反馈、纠错](https://github.com/angular/angular-cn/issues)。
|
||||
|
@ -108,4 +108,4 @@ Angular 和 Grails 开发高校[教务管理系统](http://www.github.com/jwgl)
|
|||
|
||||
- **格茸扎西(破狼)**
|
||||
|
||||
AngularJS 中文社区系列 QQ 群的群主,从严清手里接下 QQ 群并长期维护。他还与译者之一的汪志成(雪狼)合著过一本书《 AngularJS 深度剖析与最佳实践》,这本书的成功让我们看到了中文社区对 Angular 的热情支持,最终激发了我们翻译 Angular 官网的行动。我们还共同完成了对国外新书 ng-book2(中译本《Angular权威教程》) 的翻译工作。
|
||||
AngularJS 中文社区系列 QQ 群的群主,从严清手里接下 QQ 群并长期维护。他还与译者之一的汪志成(雪狼)合著过一本书《 AngularJS 深度剖析与最佳实践》,这本书的成功让我们看到了中文社区对 Angular 的热情支持,最终激发了我们翻译 Angular 官网的行动。我们还共同完成了对国外新书 ng-book2(中译本《Angular 权威教程》) 的翻译工作。
|
||||
|
|
|
@ -6,11 +6,11 @@
|
|||
|
||||
Welcome to angular.cn!
|
||||
|
||||
欢迎光临angular.cn!
|
||||
欢迎光临 angular.cn!
|
||||
|
||||
This official site and the developer guides you will find here are the result of hard work and dedication by members of Angular's Chinese developer community. More than just a linguistic translation, this site was localized and updated by developers who use and know Angular, and understand the concepts as engineers. Led by friends Zhicheng WANG (Ralph), Zhimin YE (Rex) Lin YANG (todoubaba), united by a commitment to open source software and helping developers, the [angular.cn](/translations/cn/about) team is motivated by the desire to make Angular more accessible to the millions of Chinese-speaking developers worldwide.
|
||||
|
||||
这份官方网站和开发指南的中文版是中国的 Angular 开发者社区共同努力奉献的成果。他们来自深谙 Angular 设计理念的工程师,故此,这份中文版不仅是语言上的简单汉化。出于对“开源精神”和“共享精神”的执着与推崇,汪志成、叶志敏和杨林共同带领[angular.cn团队](/translations/cn/about)奋力工作,力争让全世界的中文开发者与Angular实现零距离的亲密接触。
|
||||
这份官方网站和开发指南的中文版是中国的 Angular 开发者社区共同努力奉献的成果。他们来自深谙 Angular 设计理念的工程师,故此,这份中文版不仅是语言上的简单汉化。出于对“开源精神”和“共享精神”的执着与推崇,汪志成、叶志敏和杨林共同带领[angular.cn 团队](/translations/cn/about)奋力工作,力争让全世界的中文开发者与 Angular 实现零距离的亲密接触。
|
||||
|
||||
This Chinese version of angular.io is also the first official release of Angular's developer content in any language other than English!
|
||||
|
||||
|
@ -22,7 +22,7 @@ As a champion of open technology, Google has invested a lot and will continue to
|
|||
|
||||
We are happy to see that Angular’s Chinese developer community has grown to its current large size, fueled by not only the passion for technologies among developers, but also by the desire to make this technology effective for real businesses. Many companies in China have already built their businesses based on Angular technology. We hope that the updated materials on this official site will continue to inspire and help putting this technology into more real world business services and applications in China. If your business already runs on Angular, we invite you to join our developer community here, and become involved in our effort in continuing improving and enhancing this technology. We welcome your comments and suggestions at any time. Please send your remarks to Google Developer Relations China team’s contact email at: ![email](generated/images/translations/cn/mail-dev-rel.gif).
|
||||
|
||||
看到中国的 Angular 开发社区已经如此繁荣,我们非常高兴。这不仅仅是出于开发者对技术的固有热情,更是因为我们希望“用 Angular 高效实现商业需求”的宏伟愿景。事实上,许多中国公司的业务早已基于 Angular 技术。我们希望通过对官网内容的持续更新,鼓励并协助大家把 Angular 更多的应用于现实世界中的业务服务与应用程序。如果您的业务大厦已经构建在 Angular 的基础之上,我们欢迎您加入中文社区,参与到我们持续增强和优化此项技术的努力中来。我们随时欢迎您的意见和建议,请发邮件到Google的技术推广部联系我们,我们的邮箱是![email](generated/images/translations/cn/mail-dev-rel.gif)。
|
||||
看到中国的 Angular 开发社区已经如此繁荣,我们非常高兴。这不仅仅是出于开发者对技术的固有热情,更是因为我们希望“用 Angular 高效实现商业需求”的宏伟愿景。事实上,许多中国公司的业务早已基于 Angular 技术。我们希望通过对官网内容的持续更新,鼓励并协助大家把 Angular 更多的应用于现实世界中的业务服务与应用程序。如果您的业务大厦已经构建在 Angular 的基础之上,我们欢迎您加入中文社区,参与到我们持续增强和优化此项技术的努力中来。我们随时欢迎您的意见和建议,请发邮件到 Google 的技术推广部联系我们,我们的邮箱是![email](generated/images/translations/cn/mail-dev-rel.gif)。
|
||||
|
||||
Angular succeeds because it is built by and for developers who come from many different backgrounds. We hope that these materials will help you to learn and understand Angular, and to contribute back to the framework in future. We are excited to see what you will build with Angular here in China, and how the framework itself will change as the result of your enthusiasm.
|
||||
|
||||
|
@ -30,7 +30,7 @@ Angular 的成功,是因为它由背景各异的开发者所创造,它为开
|
|||
|
||||
We also hope that through Angular.cn, you will discover more about the wide variety of web and mobile technologies from Google and the open source world, and how to leverage many Google platforms for your future business success.
|
||||
|
||||
通过angular.cn,我们希望广大的开发者们能继续发掘更多来自 Google 和开源世界的 Web 技术和移动技术,借助 Google 提供的平台登上业务成就的新高度。
|
||||
通过 angular.cn,我们希望广大的开发者们能继续发掘更多来自 Google 和开源世界的 Web 技术和移动技术,借助 Google 提供的平台登上业务成就的新高度。
|
||||
|
||||
We are happy to have you here. Welcome.
|
||||
|
||||
|
@ -38,7 +38,7 @@ We are happy to have you here. Welcome.
|
|||
|
||||
Naomi Black and Brad Green
|
||||
|
||||
Naomi Black与Brad Green
|
||||
Naomi Black 与 Brad Green
|
||||
|
||||
## 栾跃代表 Google 开发技术推广部的致辞
|
||||
|
||||
|
@ -46,15 +46,15 @@ Naomi Black与Brad Green
|
|||
|
||||
Hello to Developer Friends of the Angular.CN community!
|
||||
|
||||
angular.cn社区的开发者朋友们,大家好!
|
||||
angular.cn 社区的开发者朋友们,大家好!
|
||||
|
||||
On behalf of Google Developer Relations China team, we warmly welcome you here! We are very glad to see the partnership and collaboration with the Angular developer community in China, and we hope that through the partnership with the developer friends at the Angular.CN community, our collaborations will be increased in the future.
|
||||
|
||||
我谨代表谷歌公司开发技术推广部(Developer Relations)中国团队热烈欢迎你! 我们非常高兴和中国的Angular开发者社区在这里的合作,也希望通过这个合作和Angular.CN社区的开发者朋友们扩大未来更多的合作和分享。
|
||||
我谨代表谷歌公司开发技术推广部(Developer Relations)中国团队热烈欢迎你! 我们非常高兴和中国的 Angular 开发者社区在这里的合作,也希望通过这个合作和 Angular.CN 社区的开发者朋友们扩大未来更多的合作和分享。
|
||||
|
||||
This Chinese Angular website, represents a great idea and model for collaboration. It not only has the Angular resources and updates that are the results of Google investment, but also the results from many Chinese localizations done by the many volunteers here for the larger developer users out there. These localized resources from the efforts from these volunteers, will help more developers in China to learn and adopt Angular technologies. We very much appreciated these contributions and the efforts in sharing. It is this kind of spirit and practices that resulted in the vibrant Internet we have today. We salute to all these volunteers, and at Google we will continue our support to open source technologies and communities as we have been doing.
|
||||
|
||||
这个 Angular 中文网站的大量资源,体现了一个很好的合作模式和精神。它不仅有谷歌公司投资所推动的 Angular 技术的资源和更新,更是有众多中国的技术爱好者和开发者们通过自己的无私义务劳动为广大开发者们所做的技术资料的中文本地化翻译工作的成果。这些志愿者们辛勤劳动所带来的中文资源,将帮助更多的中国开发者们能够方便地学习和采纳Angular技术。我们非常赞赏这样的奉献精神和分享实践,正是这样的精神和实践才造成了互联网今天的兴旺发展。我们向所有的志愿者们致敬,谷歌公司也将一如既往地继续支持开源代码技术和社区的发展。
|
||||
这个 Angular 中文网站的大量资源,体现了一个很好的合作模式和精神。它不仅有谷歌公司投资所推动的 Angular 技术的资源和更新,更是有众多中国的技术爱好者和开发者们通过自己的无私义务劳动为广大开发者们所做的技术资料的中文本地化翻译工作的成果。这些志愿者们辛勤劳动所带来的中文资源,将帮助更多的中国开发者们能够方便地学习和采纳 Angular 技术。我们非常赞赏这样的奉献精神和分享实践,正是这样的精神和实践才造成了互联网今天的兴旺发展。我们向所有的志愿者们致敬,谷歌公司也将一如既往地继续支持开源代码技术和社区的发展。
|
||||
|
||||
Let us enjoy the process of innovating through this model of sharing and collaboration!
|
||||
|
||||
|
@ -76,7 +76,7 @@ Bill Luan, Greater China Regional Lead, Developer Relations, Google
|
|||
|
||||
## 授权方式
|
||||
|
||||
本文档遵循[“保持署名—非商用”创意共享4.0许可证(CC BY-NC 4.0)](http://creativecommons.org/licenses/by-nc/4.0/deed.zh)授权方式,你不用知会我们就可以转载,但必须保持署名(特别是:链接到 <https://angular.cn>,并且不得去掉本页入口链接,也不得修改本页内容),并且不得用于商业目的。如果需要进行任何商业推广,请接洽 Google 开发技术推广部![email](generated/images/translations/cn/mail-dev-rel.gif),我们将给出积极的回应。
|
||||
本文档遵循[“保持署名—非商用”创意共享 4.0 许可证(CC BY-NC 4.0)](http://creativecommons.org/licenses/by-nc/4.0/deed.zh)授权方式,你不用知会我们就可以转载,但必须保持署名(特别是:链接到 <https://angular.cn>,并且不得去掉本页入口链接,也不得修改本页内容),并且不得用于商业目的。如果需要进行任何商业推广,请接洽 Google 开发技术推广部![email](generated/images/translations/cn/mail-dev-rel.gif),我们将给出积极的回应。
|
||||
|
||||
本文档首发于 [Angular 中文网](https://angular.cn/)。如果你要进行转载,请自行同步,不过小心别 DDoS 了我们。
|
||||
|
||||
|
@ -88,4 +88,4 @@ Nice Angular 社区的简介请参见[这里](/translations/cn/nice-angular)。
|
|||
|
||||
## 工作预告
|
||||
|
||||
将来,Google 技术推广部还会有一系列线上和线下推广工作,如果您有意为这些活动贡献力量,请接洽Google 开发技术推广部![email](generated/images/translations/cn/mail-dev-rel.gif)。
|
||||
将来,Google 技术推广部还会有一系列线上和线下推广工作,如果您有意为这些活动贡献力量,请接洽 Google 开发技术推广部![email](generated/images/translations/cn/mail-dev-rel.gif)。
|
||||
|
|
|
@ -9,19 +9,19 @@
|
|||
官方网站:[Ant Design Of Angular](https://ng.ant.design)
|
||||
|
||||
|
||||
### 关于NG-ZORRO
|
||||
### 关于 NG-ZORRO
|
||||
|
||||
众所周知,Ant Design作为一门设计语言面世,经历过多年的迭代和积累,它对UI的设计思想已经成为一套事实标准,受到众多前端开发者及企业的追捧和喜爱,也是React开发者手中的神兵利器。今天,NG-ZORRO正式开源,希望它能够让Angular开发者也享受到Ant Design的优秀设计。
|
||||
众所周知,Ant Design 作为一门设计语言面世,经历过多年的迭代和积累,它对 UI 的设计思想已经成为一套事实标准,受到众多前端开发者及企业的追捧和喜爱,也是 React 开发者手中的神兵利器。今天,NG-ZORRO 正式开源,希望它能够让 Angular 开发者也享受到 Ant Design 的优秀设计。
|
||||
|
||||
作为Ant Design的Angular实现,NG-ZORRO不仅继承了Ant Design的独到思想和极致体验,同时也结合了Angular框架的优点和特性。目前第一版发布将支持Angular 4.0.0及以上版本,组件的数量现已覆盖Ant Design React版本的80%以上,组件的风格已与Ant Design最新版本保持同步,组件的接口也尽量保持了与Ant Design的React版本一致(由于Angular的某些特性区别,某些组件的使用方式可能有所改变)。
|
||||
作为 Ant Design 的 Angular 实现,NG-ZORRO 不仅继承了 Ant Design 的独到思想和极致体验,同时也结合了 Angular 框架的优点和特性。目前第一版发布将支持 Angular 4.0.0 及以上版本,组件的数量现已覆盖 Ant Design React 版本的 80%以上,组件的风格已与 Ant Design 最新版本保持同步,组件的接口也尽量保持了与 Ant Design 的 React 版本一致(由于 Angular 的某些特性区别,某些组件的使用方式可能有所改变)。
|
||||
|
||||
NG-ZORRO 致力于提供给 Angular 开发者愉悦的开发体验。
|
||||
|
||||
### 关于开发者
|
||||
|
||||
NG-ZORRO由阿里计算平台事业部、阿里云等不同部门的一些小伙伴在原业务组件的基础上共同构建而成,在这个过程中得到了蚂蚁金服Ant Design团队的很多帮助。在最后开源的准备中也得到了很多社区小伙伴的支持和PR,在这里感谢大家。
|
||||
NG-ZORRO 由阿里计算平台事业部、阿里云等不同部门的一些小伙伴在原业务组件的基础上共同构建而成,在这个过程中得到了蚂蚁金服 Ant Design 团队的很多帮助。在最后开源的准备中也得到了很多社区小伙伴的支持和 PR,在这里感谢大家。
|
||||
|
||||
欢迎各位社区开发者加入我们,共同开发和维护NG-ZORRO,期待您的帮助。
|
||||
欢迎各位社区开发者加入我们,共同开发和维护 NG-ZORRO,期待您的帮助。
|
||||
|
||||
### THANK YOU
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
# Nice Angular 社区简介
|
||||
|
||||
## Nice Angular社区:QQ群
|
||||
## Nice Angular 社区:QQ 群
|
||||
|
||||
- 278252889( Nice Angular社区,2000人已满)
|
||||
- 305739270( Nice Angular社区二群,2000人)
|
||||
- 207542263( Nice Angular社区三群,1000人)
|
||||
- 200242234( Angular 互助组,500人)
|
||||
- 110455272( Ionic 开发实践,500人)
|
||||
- 278252889( Nice Angular 社区,2000 人已满)
|
||||
- 305739270( Nice Angular 社区二群,2000 人)
|
||||
- 207542263( Nice Angular 社区三群,1000 人)
|
||||
- 200242234( Angular 互助组,500 人)
|
||||
- 110455272( Ionic 开发实践,500 人)
|
||||
|
||||
## Nice Angular社区:微信公众号
|
||||
## Nice Angular 社区:微信公众号
|
||||
|
||||
- shuang_lang_shuo(由破狼、雪狼等人维护)
|
||||
|
|
|
@ -154,7 +154,7 @@ Refactor the component's `hero` property to be of type `Hero`.
|
|||
Initialize it with an `id` of `1` and the name `Windstorm`.
|
||||
|
||||
把组件的 `hero` 属性的类型重构为 `Hero`。
|
||||
然后以`1`为 `id`、以 “Windstorm” 为名字初始化它。
|
||||
然后以 `1` 为 `id`、以 “Windstorm” 为名字初始化它。
|
||||
|
||||
The revised `HeroesComponent` class file should look like this:
|
||||
|
||||
|
@ -225,19 +225,19 @@ Angular 发布了一些内置管道,而且你还可以创建自己的管道。
|
|||
|
||||
Users should be able to edit the hero name in an `<input>` textbox.
|
||||
|
||||
用户应该能在一个`<input>`输入框中编辑英雄的名字。
|
||||
用户应该能在一个 `<input>` 输入框中编辑英雄的名字。
|
||||
|
||||
The textbox should both _display_ the hero's `name` property
|
||||
and _update_ that property as the user types.
|
||||
That means data flow from the component class _out to the screen_ and
|
||||
from the screen _back to the class_.
|
||||
|
||||
当用户输入时,这个输入框应该能同时*显示*和*修改*英雄的`name`属性。
|
||||
当用户输入时,这个输入框应该能同时*显示*和*修改*英雄的 `name` 属性。
|
||||
也就是说,数据流从组件类**流出到屏幕**,并且从屏幕**流回到组件类**。
|
||||
|
||||
To automate that data flow, setup a two-way data binding between the `<input>` form element and the `hero.name` property.
|
||||
|
||||
要想让这种数据流动自动化,就要在表单元素`<input>`和组件的`hero.name`属性之间建立双向数据绑定。
|
||||
要想让这种数据流动自动化,就要在表单元素 `<input>` 和组件的 `hero.name` 属性之间建立双向数据绑定。
|
||||
|
||||
### Two-way binding
|
||||
|
||||
|
@ -285,7 +285,7 @@ Although `ngModel` is a valid Angular directive, it isn't available by default.
|
|||
|
||||
It belongs to the optional `FormsModule` and you must _opt-in_ to using it.
|
||||
|
||||
它属于一个可选模块`FormsModule`,你必须自行添加此模块才能使用该指令。
|
||||
它属于一个可选模块 `FormsModule`,你必须自行添加此模块才能使用该指令。
|
||||
|
||||
## _AppModule_
|
||||
|
||||
|
@ -336,7 +336,7 @@ region="ng-imports">
|
|||
|
||||
When the browser refreshes, the app should work again. You can edit the hero's name and see the changes reflected immediately in the `<h2>` above the textbox.
|
||||
|
||||
刷新浏览器,应用又能正常工作了。你可以编辑英雄的名字,并且会看到这个改动立刻体现在这个输入框上方的`<h2>`中。
|
||||
刷新浏览器,应用又能正常工作了。你可以编辑英雄的名字,并且会看到这个改动立刻体现在这个输入框上方的 `<h2>` 中。
|
||||
|
||||
### Declare _HeroesComponent_
|
||||
|
||||
|
|
|
@ -215,7 +215,7 @@ and update the hero detail.
|
|||
|
||||
Add a click event binding to the `<li>` like this:
|
||||
|
||||
再往`<li>`元素上插入一句点击事件的绑定代码:
|
||||
再往 `<li>` 元素上插入一句点击事件的绑定代码:
|
||||
|
||||
<code-example path="toh-pt2/src/app/heroes/heroes.component.1.html" region="selectedHero-click" title="heroes.component.html (template excerpt)" linenums="false">
|
||||
|
||||
|
@ -307,7 +307,7 @@ When the app starts, the `selectedHero` is `undefined` _by design_.
|
|||
|
||||
Binding expressions in the template that refer to properties of `selectedHero` — expressions like `{{selectedHero.name}}` — _must fail_ because there is no selected hero.
|
||||
|
||||
但模板中的绑定表达式引用了 `selectedHero` 的属性(表达式为`{{selectedHero.name}}`),这必然会失败,因为你还没选过英雄呢。
|
||||
但模板中的绑定表达式引用了 `selectedHero` 的属性(表达式为 `{{selectedHero.name}}`),这必然会失败,因为你还没选过英雄呢。
|
||||
|
||||
#### The fix
|
||||
|
||||
|
@ -320,7 +320,7 @@ The component should only display the selected hero details if the `selectedHero
|
|||
Wrap the hero detail HTML in a `<div>`.
|
||||
Add Angular's `*ngIf` directive to the `<div>` and set it to `selectedHero`.
|
||||
|
||||
把显示英雄详情的 HTML 包裹在一个`<div>`中。
|
||||
把显示英雄详情的 HTML 包裹在一个 `<div>` 中。
|
||||
并且为这个 div 添加 Angular 的 `*ngIf` 指令,把它的值设置为 `selectedHero`。
|
||||
|
||||
<div class="alert is-important">
|
||||
|
|
|
@ -86,7 +86,7 @@ The `hero` property
|
|||
annotated with the `@Input()` decorator,
|
||||
because the _external_ `HeroesComponent` [will bind to it](#heroes-component-template) like this.
|
||||
|
||||
`hero` 属性[必须是一个带有`@Input()`装饰器的输入属性](guide/template-syntax#inputs-outputs "Input and Output properties"),因为*外部的* `HeroesComponent` 组件[将会绑定到它](#heroes-component-template)。就像这样:
|
||||
`hero` 属性[必须是一个带有 `@Input()` 装饰器的输入属性](guide/template-syntax#inputs-outputs "Input and Output properties"),因为*外部的* `HeroesComponent` 组件[将会绑定到它](#heroes-component-template)。就像这样:
|
||||
|
||||
<code-example path="toh-pt3/src/app/heroes/heroes.component.html" region="hero-detail-binding">
|
||||
|
||||
|
|
|
@ -139,7 +139,7 @@ You must _provide_ the `HeroService` in the _dependency injection system_
|
|||
before Angular can _inject_ it into the `HeroesComponent`,
|
||||
as you will do [below](#inject).
|
||||
|
||||
在要求 Angular 把`HeroService` 注入到 `HeroesComponent` 之前,你必须先把这个服务*提供给依赖注入系统*。[稍后](#inject)你就要这么做。
|
||||
在要求 Angular 把 `HeroService` 注入到 `HeroesComponent` 之前,你必须先把这个服务*提供给依赖注入系统*。[稍后](#inject)你就要这么做。
|
||||
|
||||
There are several ways to provide the `HeroService`:
|
||||
in the `HeroesComponent`, in the `AppComponent`, in the `AppModule`.
|
||||
|
@ -654,7 +654,7 @@ This template binds directly to the component's `messageService`.
|
|||
* An Angular [event binding](guide/template-syntax#event-binding) binds the button's click event
|
||||
to `MessageService.clear()`.
|
||||
|
||||
Angular 的[事件绑定](guide/template-syntax#event-binding)把按钮的`click`事件绑定到了`MessageService.clear()`。
|
||||
Angular 的[事件绑定](guide/template-syntax#event-binding)把按钮的 `click` 事件绑定到了 `MessageService.clear()`。
|
||||
|
||||
The messages will look better when you add the private CSS styles to `messages.component.css`
|
||||
as listed in one of the ["final code review"](#final-code-review) tabs below.
|
||||
|
|
|
@ -553,7 +553,7 @@ At this point, all application routes are in place.
|
|||
|
||||
### _DashboardComponent_ hero links
|
||||
|
||||
### `DashboardComponent`中的英雄链接
|
||||
### `DashboardComponent` 中的英雄链接
|
||||
|
||||
The `DashboardComponent` hero links do nothing at the moment.
|
||||
|
||||
|
@ -996,4 +996,4 @@ Here are the code files discussed on this page and your app should look like thi
|
|||
|
||||
* You shared the `HeroService` among multiple components.
|
||||
|
||||
在多个组件之间共享了`HeroService`服务。
|
||||
在多个组件之间共享了 `HeroService` 服务。
|
||||
|
|
|
@ -58,7 +58,7 @@ After installing the module, the app will make requests to and receive responses
|
|||
without knowing that the *In-memory Web API* is intercepting those requests,
|
||||
applying them to an in-memory data store, and returning simulated responses.
|
||||
|
||||
安装完这个模块之后,应用将会通过 `HttpClient` 来发起请求和接收响应,而不用在乎实际上是这个内存 Web API在拦截这些请求、操作一个内存数据库,并且给出仿真的响应。
|
||||
安装完这个模块之后,应用将会通过 `HttpClient` 来发起请求和接收响应,而不用在乎实际上是这个内存 Web API 在拦截这些请求、操作一个内存数据库,并且给出仿真的响应。
|
||||
|
||||
This facility is a great convenience for the tutorial.
|
||||
You won't have to set up a server to learn about `HttpClient`.
|
||||
|
@ -321,7 +321,7 @@ give it a `catchError()` operator.
|
|||
The `catchError()` operator intercepts an **`Observable` that failed**.
|
||||
It passes the error an _error handler_ that can do what it wants with the error.
|
||||
|
||||
`catchError()` 操作符会拦截**失败的`Observable`**。
|
||||
`catchError()` 操作符会拦截**失败的 `Observable`**。
|
||||
它把错误对象传给*错误处理器*,*错误处理器*会处理这个错误。
|
||||
|
||||
The following `handleError()` method reports the error and then returns an
|
||||
|
@ -386,7 +386,7 @@ Here is the final version of `getHeroes` with the `tap` that logs the operation.
|
|||
|
||||
### Get hero by id
|
||||
|
||||
### 通过id获取英雄
|
||||
### 通过 id 获取英雄
|
||||
|
||||
Most web APIs support a _get by id_ request in the form `api/hero/:id`
|
||||
(such as `api/hero/11`).
|
||||
|
@ -434,7 +434,7 @@ the server.
|
|||
At the end of the hero detail template, add a save button with a `click` event
|
||||
binding that invokes a new component method named `save()`.
|
||||
|
||||
在英雄详情模板的底部添加一个保存按钮,它绑定了一个`click`事件,事件绑定会调用组件中一个名叫`save()`的新方法:
|
||||
在英雄详情模板的底部添加一个保存按钮,它绑定了一个 `click` 事件,事件绑定会调用组件中一个名叫 `save()` 的新方法:
|
||||
|
||||
<code-example path="toh-pt6/src/app/hero-detail/hero-detail.component.html" region="save" title="src/app/hero-detail/hero-detail.component.html (save)"></code-example>
|
||||
|
||||
|
@ -453,7 +453,7 @@ The overall structure of the `updateHero()` method is similar to that of
|
|||
`getHeroes()`, but it uses `http.put()` to persist the changed hero
|
||||
on the server.
|
||||
|
||||
`updateHero()` 的总体结构和`getHeroes()` 很相似,但它会使用 `http.put()` 来把修改后的英雄保存到服务器上。
|
||||
`updateHero()` 的总体结构和 `getHeroes()` 很相似,但它会使用 `http.put()` 来把修改后的英雄保存到服务器上。
|
||||
|
||||
<code-example
|
||||
path="toh-pt6/src/app/hero.service.ts"
|
||||
|
@ -762,7 +762,7 @@ as listed in the [final code review](#herosearchcomponent) below.
|
|||
As the user types in the search box, a *keyup* event binding calls the component's `search()`
|
||||
method with the new search box value.
|
||||
|
||||
当用户在搜索框中输入时,一个 *keyup* 事件绑定会调用该组件的`search()`方法,并传入新的搜索框的值。
|
||||
当用户在搜索框中输入时,一个 *keyup* 事件绑定会调用该组件的 `search()` 方法,并传入新的搜索框的值。
|
||||
|
||||
{@a asyncpipe}
|
||||
|
||||
|
@ -1049,11 +1049,11 @@ You're at the end of your journey, and you've accomplished a lot.
|
|||
|
||||
* You refactored `HeroService` to load heroes from a web API.
|
||||
|
||||
你重构了`HeroService`,以通过 web API 来加载英雄数据。
|
||||
你重构了 `HeroService`,以通过 web API 来加载英雄数据。
|
||||
|
||||
* You extended `HeroService` to support `post()`, `put()`, and `delete()` methods.
|
||||
|
||||
你扩展了`HeroService`来支持 `post()`、`put()` 和 `delete()` 方法。
|
||||
你扩展了 `HeroService` 来支持 `post()`、`put()` 和 `delete()` 方法。
|
||||
|
||||
* You updated the components to allow adding, editing, and deleting of heroes.
|
||||
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import * as fs from 'fs';
|
||||
import { dirs } from '../dirs';
|
||||
import { listMarkdownFiles } from '../extractor';
|
||||
|
||||
export function addSpaces(sourceDir: string): void {
|
||||
const files = listMarkdownFiles(sourceDir);
|
||||
files.forEach(fileName => {
|
||||
console.log('adding spaces ...', fileName);
|
||||
const content = fs.readFileSync(fileName, 'utf8');
|
||||
const result = content
|
||||
.replace(/([\u4e00-\u9fa5])([a-zA-Z0-9`])/g, '$1 $2')
|
||||
.replace(/([a-zA-Z0-9`])([\u4e00-\u9fa5])/g, '$1 $2')
|
||||
;
|
||||
fs.writeFileSync(fileName, result, 'utf8');
|
||||
console.log('added spaces ', fileName);
|
||||
});
|
||||
}
|
||||
|
||||
addSpaces(dirs.content);
|
Loading…
Reference in New Issue