docs: 手动解决冲突
This commit is contained in:
parent
a9ac90d3df
commit
9a0d3e9633
|
@ -1,147 +1,262 @@
|
|||
# Introduction to Angular animations
|
||||
|
||||
# Angular 动画简介
|
||||
|
||||
Animation provides the illusion of motion: HTML elements change styling over time. Well-designed animations can make your application more fun and easier to use, but they aren't just cosmetic. Animations can improve your app and user experience in a number of ways:
|
||||
|
||||
动画用于提供运动的幻觉:HTML 元素随着时间改变样式。精心设计的动画可以让你的应用更有趣,更易用,但它们不仅仅是装饰性的。动画可以通过几种方式改善你的应用和用户体验:
|
||||
|
||||
* Without animations, web page transitions can seem abrupt and jarring.
|
||||
|
||||
没有动画,Web 页面的转场就会显得突兀、不协调。
|
||||
|
||||
* Motion greatly enhances the user experience, so animations give users a chance to detect the application's response to their actions.
|
||||
|
||||
运动能极大地提升用户体验,因此动画可以让用户察觉到应用对他们的操作做出了响应。
|
||||
|
||||
* Good animations intuitively call the user's attention to where it is needed.
|
||||
|
||||
良好的动画可以直观的把用户的注意力吸引到要留意的地方。
|
||||
|
||||
Typically, animations involve multiple style *transformations* over time. An HTML element can move, change color, grow or shrink, fade, or slide off the page. These changes can occur simultaneously or sequentially. You can control the timing of each transformation.
|
||||
|
||||
典型的动画会涉及多种随时间变化的转换。HTML 元素可以移动、变换颜色、增加或缩小、隐藏或从页面中滑出。
|
||||
这些变化可以同时发生或顺序发生。你可以控制每次转换的持续时间。
|
||||
|
||||
Angular's animation system is built on CSS functionality, which means you can animate any property that the browser considers animatable. This includes positions, sizes, transforms, colors, borders, and more. The W3C maintains a list of animatable properties on its [CSS Transitions](https://www.w3.org/TR/css-transitions-1/) page.
|
||||
|
||||
Angular 的动画系统是基于 CSS 功能构建的,这意味着你可以 "动" 浏览器认为可动的任何属性。包括位置、大小、变形、颜色、边框等。W3C 在它的 [CSS Transitions(转场)](https://www.w3.org/TR/css-transitions-1/) 页中维护了一个可动属性的列表。
|
||||
|
||||
## About this guide
|
||||
|
||||
## 关于本指南
|
||||
|
||||
This guide covers the basic Angular animation features to get you started on adding Angular animations to your project.
|
||||
|
||||
本指南覆盖了基本的 Angular 动画特性,让你能开始为你的项目添加 Angular 动画。
|
||||
|
||||
The features described in this guide — and the more advanced features described in the related Angular animations guides — are demonstrated in an example app available as a <live-example></live-example>.
|
||||
|
||||
本指南中描述的特性,以及相关的 Angular 动画章节中描述的更多高级特性,都在一个范例 <live-example></live-example> 中进行了演示。
|
||||
|
||||
#### Prerequisites
|
||||
|
||||
#### 前提条件
|
||||
|
||||
The guide assumes that you're familiar with building basic Angular apps, as described in the following sections:
|
||||
|
||||
本指南假设你已经能熟练构建基本的 Angular 应用,也就是下列章节中所讲的那些:
|
||||
|
||||
* [Tutorial](tutorial)
|
||||
|
||||
[教程](tutorial)
|
||||
|
||||
* [Architecture Overview](guide/architecture)
|
||||
|
||||
[架构概览](guide/architecture)
|
||||
|
||||
## Getting started
|
||||
|
||||
## 快速上手
|
||||
|
||||
The main Angular modules for animations are `@angular/animations` and `@angular/platform-browser`. When you create a new project using the CLI, these dependencies are automatically added to your project.
|
||||
|
||||
Angular 主要的动画模块是 `@angular/animations` 和 `@angular/platform-browser`。当你使用 CLI 创建新项目时,这些依赖会自动添加到你的项目中。
|
||||
|
||||
To get started with adding Angular animations to your project, import the animation-specific modules along with standard Angular functionality.
|
||||
|
||||
为了把 Angular 动画添加到你的项目中,把这些与动画相关的模块和标准的 Angular 功能一起导入进来。
|
||||
|
||||
### Step 1: Enabling the animations module
|
||||
|
||||
### 步骤一:启用动画模块
|
||||
|
||||
Import `BrowserAnimationsModule`, which introduces the animation capabilities into your Angular root application module.
|
||||
|
||||
导入 `BrowserAnimationsModule`,它能把动画能力引入应用的根模块中。
|
||||
|
||||
<code-example path="animations/src/app/app.module.1.ts" header="src/app/app.module.ts" language="typescript" linenums="false">
|
||||
</code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
**Note:** When you use the CLI to create your app, the root application module `app.module.ts` is placed in the `src/app` folder.
|
||||
|
||||
**注意:**当你使用 CLI 创建应用时,应用的根模块 `app.module.ts` 位于 `src/app` 目录下。
|
||||
|
||||
</div>
|
||||
|
||||
### Step 2: Importing animation functions into component files
|
||||
|
||||
### 步骤二:把动画功能导入组件文件中
|
||||
|
||||
If you plan to use specific animation functions in component files, import those functions from `@angular/animations`.
|
||||
|
||||
如果你准备在组件文件中使用特定的动画函数,请从 `@angular/animations` 中导入这些函数。
|
||||
|
||||
<code-example path="animations/src/app/app.component.ts" header="src/app/app.component.ts" region="imports" language="typescript">
|
||||
</code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
**Note:** See a [summary of available animation functions](guide/animations#animation-api-summary) at the end of this guide.
|
||||
|
||||
**注意:**参见本章末尾的[可用动画函数汇总表](guide/animations#animation-api-summary)。
|
||||
|
||||
</div>
|
||||
|
||||
### Step 3: Adding the animation metadata property
|
||||
|
||||
### 步骤三:添加动画的元数据属性
|
||||
|
||||
In the component file, add a metadata property called `animations:` within the `@Component()` decorator. You put the trigger that defines an animation within the `animations` metadata property.
|
||||
|
||||
在组件的 `@Component()` 装饰器中,添加一个名叫 `animations:` 的元数据属性。
|
||||
你可以把用来定义动画的触发器放进 `animations` 元数据属性中。
|
||||
|
||||
<code-example path="animations/src/app/app.component.ts" header="src/app/app.component.ts" region="decorator" language="typescript">
|
||||
</code-example>
|
||||
|
||||
## Animating a simple transition
|
||||
|
||||
## 简单转场动画
|
||||
|
||||
Let's animate a simple transition that changes a single HTML element from one state to another. For example, you can specify that a button displays either **Open** or **Closed** based on the user's last action. When the button is in the `open` state, it's visible and yellow. When it's the `closed` state, it's transparent and green.
|
||||
|
||||
我们来做一个简单的转场动作,它把单个 HTML 元素从一个状态变成另一个状态。
|
||||
比如,你可以指定按钮根据用户的最后一个动作显示成**Open**或**Closed**状态。当按钮处于 `open` 状态时,它是可见的,并且是黄色的。当它处于 `closed` 状态时,它是透明的,并且是绿色的。
|
||||
|
||||
In HTML, these attributes are set using ordinary CSS styles such as color and opacity. In Angular, use the `style()` function to specify a set of CSS styles for use with animations. You can collect a set of styles in an animation state, and give the state a name, such as `open` or `closed`.
|
||||
|
||||
在 HTML 中,这些属性都使用普通的 CSS 样式,比如颜色(color)和透明度(opacity)。在 Angular 中,使用 `style()` 函数来指定一组用作动画的 CSS 样式。
|
||||
你可以为动画状态指定一组样式,并为该状态指定一个名字,比如 `open` 或 `closed`。
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/animations/open-closed.png" alt="open and closed states">
|
||||
</figure>
|
||||
|
||||
### Animation state and styles
|
||||
|
||||
### 动画状态和样式
|
||||
|
||||
Use Angular's `state()` function to define different states to call at the end of each transition. This function takes two arguments: a unique name like `open` or `closed` and a `style()` function.
|
||||
|
||||
使用 Angular 的 `state()` 函数来定义不同的状态,供每次转场结束时调用。该函数接受两个参数:一个唯一的名字,比如 `open` 或 `closed` 和一个 `style()` 函数。
|
||||
|
||||
Use the `style()` function to define a set of styles to associate with a given state name. Note that the style attributes must be in [*camelCase*](guide/glossary#case-conventions).
|
||||
|
||||
使用 `style()` 函数来定义一组与指定的状态名相关的样式。注意,样式的属性必须是[*小驼峰*](guide/glossary#case-conventions) 格式的。
|
||||
|
||||
Let's see how Angular's `state()` function works with the `style()` function to set CSS style attributes. In this code snippet, multiple style attributes are set at the same time for the state. In the `open` state, the button has a height of 200 pixels, an opacity of 1, and a background color of yellow.
|
||||
|
||||
我们来看看 Angular 的 `state()` 函数如何与 `style()` 函数联用,来设置 CSS 样式的属性。
|
||||
在下面的代码片段中,该状态的多个样式属性都是同时设置的。在 `open` 状态中,该按钮的高度是 200 像素,透明度是 1,背景色是黄色。
|
||||
|
||||
<code-example path="animations/src/app/open-close.component.ts" header="src/app/open-close.component.ts" region="state1" language="typescript">
|
||||
</code-example>
|
||||
|
||||
In the `closed` state, shown below, the button has a height of 100 pixels, an opacity of 0.5, and a background color of green.
|
||||
|
||||
在 `closed` 状态中,按钮的高度是 100 像素,透明度是 0.5,背景色是绿色。
|
||||
|
||||
<code-example path="animations/src/app/open-close.component.ts" header="src/app/open-close.component.ts" region="state2" language="typescript">
|
||||
</code-example>
|
||||
|
||||
### Transitions and timing
|
||||
|
||||
### 转场与时序
|
||||
|
||||
In Angular, you can set multiple styles without any animation. However, without further refinement, the button instantly transforms with no fade, no shrinkage, or other visible indicator that a change is occurring.
|
||||
|
||||
在 Angular 中,你可以设置多个样式而不必用动画。不过,如果没有进一步细化,按钮的转换会立即完成 —— 没有渐隐、没有收缩,也没有其它的可视化效果来指出正在发生变化。
|
||||
|
||||
To make the change less abrupt, we need to define an animation *transition* to specify the changes that occur between one state and another over a period of time. The `transition()` function accepts two arguments: the first argument accepts an expression that defines the direction between two transition states, and the second argument accepts an `animate()` function.
|
||||
|
||||
要让这些变化不那么突兀,我们需要定义一个动画*转场*来要求这些状态之间的变化在一段时间内发生。`transition()` 接受两个参数:第一个参数接受一个表达式,它定义两个转场状态之间的方向;第二个参数接受一个 `animate()` 函数。
|
||||
|
||||
Use the `animate()` function to define the length, delay, and easing of a transition, and to designate the style function for defining styles while transitions are taking place. You can also use the `animate()` function to define the `keyframes()` function for multi-step animations. These definitions are placed in the second argument of the `animate()` function.
|
||||
|
||||
使用 `animate()` 函数来定义长度、延迟和缓动效果,并指定一个样式函数,以定义转场过程中的样式。
|
||||
你还可以使用 `animate()` 函数来为多步动画定义 `keyframes()` 函数。这些定义放在 `animate()` 函数的第二个参数中。
|
||||
|
||||
#### Animation metadata: duration, delay, and easing
|
||||
|
||||
#### 动画元数据:持续时间、延迟和缓动效果
|
||||
|
||||
The `animate()` function (second argument of the transition function) accepts the `timings` and `styles` input parameters.
|
||||
|
||||
`animate()` 函数(作为转场函数的第二个参数)可以接受 `timings` 和 `styles` 参数。
|
||||
|
||||
The `timings` parameter takes a string defined in three parts.
|
||||
|
||||
`timings` 参数接受一个由三部分组成的字符串。
|
||||
|
||||
>`animate ('duration delay easing')`
|
||||
|
||||
The first part, `duration`, is required. The duration can be expressed in milliseconds as a simple number without quotes, or in seconds with quotes and a time specifier. For example, a duration of a tenth of a second can be expressed as follows:
|
||||
|
||||
第一部分 `duration`(持续时间)是必须的。这个持续时间可以表示成一个不带引号的纯数字(表示毫秒),或一个带引号的有单位的时间(表示秒数)。比如,0.1 秒的持续时间有如下表示方式:
|
||||
|
||||
* As a plain number, in milliseconds: `100`
|
||||
|
||||
作为纯数字,毫秒为单位:`100`
|
||||
|
||||
* In a string, as milliseconds: `'100ms'`
|
||||
|
||||
作为字符串,毫秒为单位:`'100ms'`
|
||||
|
||||
* In a string, as seconds: `'0.1s'`
|
||||
|
||||
作为字符串,秒为单位:`'0.1s'`
|
||||
|
||||
The second argument, `delay`, has the same syntax as `duration`. For example:
|
||||
|
||||
第二个参数 `delay` 的语法和 `duration` 一样。比如:
|
||||
|
||||
* Wait for 100ms and then run for 200ms: `'0.2s 100ms'`
|
||||
|
||||
等待 100 毫秒,然后运行 200 毫秒表示为:`'0.2s 100ms'`
|
||||
|
||||
The third argument, `easing`, controls how the animation [accelerates and decelerates](http://easings.net/) during its runtime. For example, `ease-in` causes the animation to begin slowly, and to pick up speed as it progresses.
|
||||
|
||||
第三个参数 `easing` 控制动画在运行期间如何进行[加速和减速](http://easings.net/)。比如 `ease-in` 表示动画开始时很慢,然后逐渐加速。
|
||||
|
||||
* Wait for 100ms, run for 200ms. Use a deceleration curve to start out fast and slowly decelerate to a resting point: `'0.2s 100ms ease-out'`
|
||||
|
||||
等待 100 毫秒,运行 200 毫秒。按照减速曲线运动,快速启动并逐渐减速,直到静止:`'0.2s 100ms ease-out'`
|
||||
|
||||
* Run for 200ms, with no delay. Use a standard curve to start slow, accelerate in the middle, and then decelerate slowly at the end: `'0.2s ease-in-out'`
|
||||
|
||||
运行 200 毫秒,不等待。按照标准曲线运动,开始很慢,中间加速,最后逐渐减速:`'0.2s ease-in-out'`
|
||||
|
||||
* Start immediately, run for 200ms. Use a acceleration curve to start slow and end at full velocity: `'0.2s ease-in'`
|
||||
|
||||
立即开始,运行 200 毫秒。按照加速曲线运动,开始很慢,最后达到全速:`'0.2s ease-in'`
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
**Note:** See the Angular Material Design website's topic on [Natural easing curves](https://material.io/design/motion/speed.html#easing) for general information on easing curves.
|
||||
|
||||
**注意:**要了解缓动曲线的更多信息,请参阅 Material Design 网站下的[自然缓动曲线](https://material.io/design/motion/speed.html#easing)主题。
|
||||
|
||||
</div>
|
||||
|
||||
This example provides a state transition from `open` to `closed` with a one second transition between states.
|
||||
|
||||
下面的例子提供了一个从 `open` 到 `closed` 的持续一秒的状态转场。
|
||||
|
||||
<code-example path="animations/src/app/open-close.component.ts" header="src/app/open-close.component.ts" language="typescript"
|
||||
region="transition1">
|
||||
</code-example>
|
||||
|
||||
In the code snippet above, the `=>` operator indicates unidirectional transitions, and `<=>` is bidirectional. Within the transition, `animate()` specifies how long the transition takes. In this case, the state change from `open` to `closed` takes one second, expressed here as `1s`.
|
||||
|
||||
在上面的代码片段中,`=>` 操作符表示单向转场,而 `<=>` 表示双向转场。在转场过程中,`animate()` 指定了转场需要花费的时间。在这里,从 `open` 到 `closed` 状态的转换要花费 1 秒中,表示成 `1s`。
|
||||
|
||||
This example adds a state transition from the `closed` state to the `open` state with a 0.5 second transition animation arc.
|
||||
|
||||
下面的例子添加了一个从 `closed` 到 `open` 的状态转场,转场动画持续 0.5 秒。
|
||||
|
||||
<code-example path="animations/src/app/open-close.component.ts" header="src/app/open-close.component.ts" language="typescript"
|
||||
region="transition2">
|
||||
</code-example>
|
||||
|
@ -150,23 +265,42 @@ region="transition2">
|
|||
|
||||
**Note:** Some additional notes on using styles within `state` and `transition` functions.
|
||||
|
||||
**注意:**在 `state` 和 `transition` 函数中使用样式时有一些需要注意的地方。
|
||||
|
||||
* Use `state()` to define styles that are applied at the end of each transition, they persist after the animation has completed.
|
||||
|
||||
请用 `state()` 来定义那些在每个转场结束时样式,这些样式在动画结束时会保留。
|
||||
|
||||
* Use `transition()` to define intermediate styles, which create the illusion of motion during the animation.
|
||||
|
||||
使用 `transition()` 来定义那些中间样式,以便在动画过程中产生运动的错觉。
|
||||
|
||||
* When animations are disabled, `transition()` styles can be skipped, but `state()` styles can't.
|
||||
|
||||
当禁用了动画时,也会忽略 `transition()` 中的样式,但 `state()` 中的样式不会。
|
||||
|
||||
* You can include multiple state pairs within the same `transition()` argument:<br/> `transition( 'on => off, off => void' )`.
|
||||
|
||||
你可以在同一个 `transition()` 参数中包含多个状态对:<br/>`transition( 'on => off, off => void' )`。
|
||||
|
||||
</div>
|
||||
|
||||
### Triggering the animation
|
||||
|
||||
### 触发动画
|
||||
|
||||
An animation requires a *trigger*, so that it knows when to start. The `trigger()` function collects the states and transitions, and gives the animation a name, so that you can attach it to the triggering element in the HTML template.
|
||||
|
||||
动画需要*触发器*,以便知道该在何时开始。`trigger()` 函数会把一些状态和转场组合在一起,并为这个动画命名,这样你就可以在 HTML 模板中把它附加到想要触发动画的元素上了。
|
||||
|
||||
The `trigger()` function describes the property name to watch for changes. When a change occurs, the trigger initiates the actions included in its definition. These actions can be transitions or other functions, as we'll see later on.
|
||||
|
||||
`trigger()` 函数描述了监听变化时要使用的触发器名称。当这个触发器名称所绑定的值发生了变化时,触发器就会启动它所定义的操作。这些操作可能是转场,也可能是其它功能,我们稍后就会看到。
|
||||
|
||||
In this example, we'll name the trigger `openClose`, and attach it to the `button` element. The trigger describes the open and closed states, and the timings for the two transitions.
|
||||
|
||||
在这个例子中,我们将把该触发器命名为 `openClose`,并把它附加到 `button` 元素上。该触发器描述了 `open` 和 `closed` 两个状态,以及两个转场效果的时序。
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/animations/triggering-the-animation.png" alt="triggering the animation">
|
||||
</figure>
|
||||
|
@ -174,46 +308,71 @@ In this example, we'll name the trigger `openClose`, and attach it to the `butto
|
|||
<div class="alert is-helpful">
|
||||
|
||||
**Note:** Within each `trigger()` function call, an element can only be in one state at any given time. However, it's possible for multiple triggers to be active at once.
|
||||
|
||||
**注意:**在每个 `trigger()` 函数调用中,元素在任意时刻只能处于其中的一个状态。但是,元素可以在同一时刻激活多个触发器。
|
||||
|
||||
</div>
|
||||
|
||||
### Defining animations and attaching them to the HTML template
|
||||
|
||||
### 定义动画,并把它们附加到 HTML 模板中
|
||||
|
||||
Animations are defined in the metadata of the component that controls the HTML element to be animated. Put the code that defines your animations under the `animations:` property within the `@Component()` decorator.
|
||||
|
||||
这些控制 HTML 元素如何运动的动画是在组件的元数据中定义的。请在 `@Component()` 装饰器的 `animations:` 属性下用代码定义你要用的动画。
|
||||
|
||||
<code-example path="animations/src/app/open-close.component.ts" header="src/app/open-close.component.ts" language="typescript"
|
||||
region="component" linenums="false">
|
||||
</code-example>
|
||||
|
||||
When you've defined an animation trigger for a component, you can attach it to an element in that component's template by wrapping the trigger name in brackets and preceding it with an `@` symbol. Then, you can bind the trigger to a template expression using standard Angular property binding syntax as shown below, where `triggerName` is the name of the trigger, and `expression` evaluates to a defined animation state.
|
||||
|
||||
为组件定义好这些动画触发器之后,你可以给触发器名称加上 `@` 前缀并包在方括号里,来把它附加到组件模板中的元素上。然后,你可以使用如下所示的标准属性绑定语法,来把这个触发器绑定到模板表达式上。这里的 `triggerName` 就是触发器的名称,而 `expression` 的求值结果是前面定义过的动画状态之一。
|
||||
|
||||
```
|
||||
<div [@triggerName]="expression">...</div>;
|
||||
```
|
||||
|
||||
The animation is executed or triggered when the expression value changes to a new state.
|
||||
|
||||
当该表达式的值变成了新的状态时,动画就会执行或者叫触发。
|
||||
|
||||
The following code snippet binds the trigger to the value of the `isOpen` property.
|
||||
|
||||
下列代码片段把该触发器绑定到了 `isOpen` 属性的值上。
|
||||
|
||||
<code-example path="animations/src/app/open-close.component.1.html" header="src/app/open-close.component.html"
|
||||
region="compare">
|
||||
</code-example>
|
||||
|
||||
In this example, when the `isOpen` expression evaluates to a defined state of `open` or `closed`, it notifies the trigger `openClose` of a state change. Then it's up to the `openClose` code to handle the state change and kick off a state change animation.
|
||||
|
||||
在这个例子中,当 `isOpen` 表达式求值为一个已定义状态 `open` 或 `closed` 时,就会通知 `openClose` 触发器说状态变化了。然后,就由 `openClose` 中的代码来处理状态变更,并启动状态变更动画。
|
||||
|
||||
For elements entering or leaving a page (inserted or removed from the DOM), you can make the animations conditional. For example, use `*ngIf` with the animation trigger in the HTML template.
|
||||
|
||||
对于那些进入或离开页面的元素(插入到 DOM 中或从中移除),你可以让动画变成有条件的。例如,在 HTML 模板中可以和 `*ngIf` 一起使用动画触发器。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
**Note:** In the component file, set the trigger that defines the animations as the value of the `animations:` property in the `@Component()` decorator.
|
||||
|
||||
**注意:**在组件文件中,要把用来定义动画的触发器设置为 `@Component()` 装饰器的 `animations:` 属性的值。
|
||||
|
||||
In the HTML template file, use the trigger name to attach the defined animations to the HTML element to be animated.
|
||||
|
||||
在 HTML 模板文件中,使用这个触发器的名称来把所定义的这些动画附加到想要添加动画的 HTML 元素上。
|
||||
|
||||
</div>
|
||||
|
||||
### Code review
|
||||
|
||||
### 代码回顾
|
||||
|
||||
Here are the code files discussed in the transition example.
|
||||
|
||||
下面是转场动画范例中讨论过的代码文件。
|
||||
|
||||
<code-tabs>
|
||||
|
||||
<code-pane header="src/app/open-close.component.ts" path="animations/src/app/open-close.component.ts" language="typescript"
|
||||
|
@ -231,104 +390,219 @@ region="trigger">
|
|||
|
||||
### Summary
|
||||
|
||||
### 小节
|
||||
|
||||
You learned to add animation to a simple transition between two states, using `style()` and `state()` along with `animate()` for the timing.
|
||||
|
||||
你已经学会了如何在两个状态之间添加简单的转场动画,只要使用 `style()` 和 `state()`,并使用 `animate()` 来定义时序就可以了。
|
||||
|
||||
You can learn about more advanced features in Angular animations under the Animation section, beginning with advanced techniques in [transition and triggers](guide/transition-and-triggers).
|
||||
|
||||
你还可以到 "动画" 组下学习更多高级特性,不妨先从[转场与触发器](guide/transition-and-triggers)中讲述的高级技巧开始。
|
||||
|
||||
{@a animation-api-summary}
|
||||
## Animations API summary
|
||||
|
||||
## 动画 API 小节
|
||||
|
||||
The functional API provided by the `@angular/animations` module provides a domain-specific language (DSL) for creating and controlling animations in Angular applications. See the [API reference](api/animations) for a complete listing and syntax details of the core functions and related data structures.
|
||||
|
||||
`@angular/animations` 模块提供的这些功能性 API 提供了一种领域特定语言(DSL),用于在 Angular 应用中创建和控制动画效果。到 [API 参考手册](api/animations)中查看完整的列表以及这些核心功能、相关数据结构的详细语法。
|
||||
|
||||
<table>
|
||||
|
||||
<tr>
|
||||
<th style="vertical-align: top">
|
||||
|
||||
Function name
|
||||
|
||||
函数名
|
||||
|
||||
</th>
|
||||
|
||||
<th style="vertical-align: top">
|
||||
|
||||
What it does
|
||||
|
||||
用途
|
||||
|
||||
</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>trigger()</code></td>
|
||||
<td>Kicks off the animation and serves as a container for all other animation function calls. HTML template binds to <code>triggerName</code>. Use the first argument to declare a unique trigger name. Uses array syntax.</td>
|
||||
<td>
|
||||
|
||||
Kicks off the animation and serves as a container for all other animation function calls. HTML template binds to <code>triggerName</code>. Use the first argument to declare a unique trigger name. Uses array syntax.
|
||||
|
||||
开始动画,并充当所有其它动画函数的容器。HTML 模板可以绑定到 <code>triggerName</code>。使用第一个参数来声明唯一的触发器名称。要使用数组语法。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>style()</code></td>
|
||||
<td>Defines one or more CSS styles to use in animations. Controls the visual appearance of HTML elements during animations. Uses object syntax.</td>
|
||||
<td>
|
||||
|
||||
Defines one or more CSS styles to use in animations. Controls the visual appearance of HTML elements during animations. Uses object syntax.
|
||||
|
||||
定义一个或多个要用于动画中的 CSS 样式。用于在动画期间控制 HTML 元素的视觉外观。要使用对象语法。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>state()</code></td>
|
||||
<td>Creates a named set of CSS styles that should be applied on successful transition to a given state. The state can then be referenced by name within other animation functions.</td>
|
||||
<td>
|
||||
|
||||
Creates a named set of CSS styles that should be applied on successful transition to a given state. The state can then be referenced by name within other animation functions.
|
||||
|
||||
创建一组有名字的 CSS 样式,它会在成功转换到指定的状态时应用到元素上。该状态可以在其它动画函数中通过名字进行引用。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>animate()</code></td>
|
||||
<td>Specifies the timing information for a transition. Optional values for <code>delay</code> and <code>easing</code>. Can contain <code>style()</code> calls within.</td>
|
||||
<td>
|
||||
|
||||
Specifies the timing information for a transition. Optional values for <code>delay</code> and <code>easing</code>. Can contain <code>style()</code> calls within.
|
||||
|
||||
指定转场的时序信息。<code>delay</code> 和 <code>easing</code> 是可选值。其中可以包含 <code>style()</code> 调用。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>transition()</code></td>
|
||||
<td>Defines the animation sequence between two named states. Uses array syntax.</td>
|
||||
<td>
|
||||
|
||||
Defines the animation sequence between two named states. Uses array syntax.
|
||||
|
||||
定义两个命名状态之间的动画序列。使用数组语法。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>keyframes()</code></td>
|
||||
<td>Allows a sequential change between styles within a specified time interval. Use within <code>animate()</code>. Can include multiple <code>style()</code> calls within each <code>keyframe()</code>. Uses array syntax.</td>
|
||||
<td>
|
||||
|
||||
Allows a sequential change between styles within a specified time interval. Use within <code>animate()</code>. Can include multiple <code>style()</code> calls within each <code>keyframe()</code>. Uses array syntax.
|
||||
|
||||
允许以特定的时间间隔对样式进行顺序更改。用于 <code>animate()</code> 中。每个 <code>keyframe()</code> 中都可以包含多个 <code>style()</code> 调用。使用数组语法。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>group()</code></td>
|
||||
<td>Specifies a group of animation steps (<em>inner animations</em>) to be run in parallel. Animation continues only after all inner animation steps have completed. Used within <code>sequence()</code> or <code>transition().</code></td>
|
||||
<td>
|
||||
|
||||
Specifies a group of animation steps (<em>inner animations</em>) to be run in parallel. Animation continues only after all inner animation steps have completed. Used within <code>sequence()</code> or <code>transition().</code>
|
||||
|
||||
指定要并行运行的一组动画步骤(<em>内部动画</em>)。
|
||||
该动画只有当所有内部动画步骤都完成之后才会继续。用于 <code>sequence()</code> 或 <code>transition()</code> 中。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>query()</code></td>
|
||||
<td>Use to find one or more inner HTML elements within the current element. </td>
|
||||
<td>
|
||||
|
||||
Use to find one or more inner HTML elements within the current element.
|
||||
|
||||
用于找出当前元素中的一个或多个内部 HTML 元素。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>sequence()</code></td>
|
||||
<td>Specifies a list of animation steps that are run sequentially, one by one.</td>
|
||||
<td>
|
||||
|
||||
Specifies a list of animation steps that are run sequentially, one by one.
|
||||
|
||||
指定一个动画步骤列表,它们会逐个顺序执行。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>stagger()</code></td>
|
||||
<td>Staggers the starting time for animations for multiple elements.</td>
|
||||
<td>
|
||||
|
||||
Staggers the starting time for animations for multiple elements.
|
||||
|
||||
交错安排多元素动画的开始时间。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>animation()</code></td>
|
||||
<td>Produces a reusable animation that can be invoked from elsewhere. Used together with <code>useAnimation()</code>.</td>
|
||||
<td>
|
||||
|
||||
Produces a reusable animation that can be invoked from elsewhere. Used together with <code>useAnimation()</code>.
|
||||
|
||||
生成可在其它地方调用的可重用动画。与 <code>useAnimation()</code> 一起使用。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>useAnimation()</code></td>
|
||||
<td>Activates a reusable animation. Used with <code>animation()</code>.</td>
|
||||
<td>
|
||||
|
||||
Activates a reusable animation. Used with <code>animation()</code>.
|
||||
|
||||
激活一个可复用动画。和 <code>animation()</code> 一起使用。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>animateChild()</code></td>
|
||||
<td>Allows animations on child components to be run within the same timeframe as the parent.</td>
|
||||
<td>
|
||||
|
||||
Allows animations on child components to be run within the same timeframe as the parent.
|
||||
|
||||
允许子组件上的动画和父组件在同一个时间范围(timeframe)内执行。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
## More on Angular animations
|
||||
|
||||
## 关于 Angular 动画的更多知识
|
||||
|
||||
You may also be interested in the following:
|
||||
|
||||
你可能还对下列内容感兴趣:
|
||||
|
||||
* [Transition and triggers](guide/transition-and-triggers)
|
||||
|
||||
[转场与触发器](guide/transition-and-triggers)
|
||||
|
||||
* [Complex animation sequences](guide/complex-animation-sequences)
|
||||
|
||||
[复杂动画序列](guide/complex-animation-sequences)
|
||||
|
||||
* [Reusable animations](guide/reusable-animations)
|
||||
|
||||
[可复用动画](guide/reusable-animations)
|
||||
|
||||
* [Route transition animations](guide/route-animations)
|
||||
|
||||
[路由转场动画](guide/route-animations)
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
Check out this full animation [demo](http://animationsftw.in/#/) with accompanying [presentation](https://www.youtube.com/watch?v=JhNo3Wvj6UQ&feature=youtu.be&t=2h47m53s), shown at the AngularConnect conference in November 2017.
|
||||
|
||||
到这个 [Demo](http://animationsftw.in/#/) 中查看 2017 年 11 月的 AngularConnect 大会上完整的动画及其[演示](https://www.youtube.com/watch?v=JhNo3Wvj6UQ&feature=youtu.be&t=2h47m53s)。
|
||||
|
||||
</div>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -61,15 +61,15 @@ In addition to containing or pointing to the template, the `@Component` metadata
|
|||
|
||||
除了包含或指向模板之外,`@Component` 的元数据还会配置要如何在 HTML 中引用该组件,以及该组件需要哪些服务等等。
|
||||
|
||||
Here's an example of basic metadata for `HeroListComponent`.
|
||||
Here's an example of basic metadata for `HeroListComponent`.
|
||||
|
||||
下面的例子中就是 `HeroListComponent` 的基础元数据:
|
||||
下面的例子中就是 `HeroListComponent` 的基础元数据:
|
||||
|
||||
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" header="src/app/hero-list.component.ts (metadata)" region="metadata"></code-example>
|
||||
|
||||
This example shows some of the most useful `@Component` configuration options:
|
||||
|
||||
这个例子展示了一些最常用的 `@Component` 配置选项:
|
||||
这个例子展示了一些最常用的 `@Component` 配置选项:
|
||||
|
||||
* `selector`: A CSS selector that tells Angular to create and insert an instance of this component wherever it finds the corresponding tag in template 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.
|
||||
|
@ -85,7 +85,7 @@ Angular inserts an instance of the `HeroListComponent` view between those tags.
|
|||
|
||||
* `providers`: An array of [providers](guide/glossary#provider) for services that the component requires. In the example, this tells Angular how to provide the `HeroService` instance that the component's constructor uses to get the list of heroes to display.
|
||||
|
||||
`providers` 是当前组件所需的**依赖注入提供商**的一个数组。在这个例子中,它告诉 Angular 该如何提供一个 `HeroService` 实例,以获取要显示的英雄列表。
|
||||
`providers`:当前组件所需的服务[提供商](guide/glossary#provider)的一个数组。在这个例子中,它告诉 Angular 该如何提供一个 `HeroService` 实例,以获取要显示的英雄列表。
|
||||
|
||||
## Templates and views
|
||||
|
||||
|
@ -142,7 +142,7 @@ This template uses typical HTML elements like `<h2>` and `<p>`, and also includ
|
|||
Notice how custom components like this mix seamlessly with native HTML in the same layouts.
|
||||
|
||||
模板中的 `<app-hero-detail>` 标签是一个代表新组件 `HeroDetailComponent` 的元素。
|
||||
`HeroDetailComponent`(代码略)是 `HeroListComponent` 的一个子组件,它定义了英雄详情视图。
|
||||
`HeroDetailComponent`(代码略)定义了 `HeroListComponent` 的英雄详情子视图。
|
||||
注意观察像这样的自定义组件是如何与原生 HTML 元素无缝的混合在一起的。
|
||||
|
||||
### Data binding
|
||||
|
@ -222,16 +222,16 @@ Data binding plays an important role in communication between a template and its
|
|||
|
||||
### 管道
|
||||
|
||||
Angular pipes let you declare display-value transformations in your template HTML. A class with the `@Pipe` decorator defines a function that transforms input values to output values for display in a view.
|
||||
Angular pipes let you declare display-value transformations in your template HTML. A class with the `@Pipe` decorator defines a function that transforms input values to output values for display in a view.
|
||||
|
||||
Angular 的管道可以让你在模板中声明显示值的转换逻辑。
|
||||
带有 `@Pipe` 装饰器的类中会定义一个转换函数,用来把输入值转换成供视图显示用的输出值。
|
||||
|
||||
Angular defines various pipes, such as the [date](https://angular.io/api/common/DatePipe) pipe and [currency](https://angular.io/api/common/CurrencyPipe) pipe; for a complete list, see the [Pipes API list](https://angular.io/api?type=pipe). You can also define new pipes.
|
||||
Angular defines various pipes, such as the [date](https://angular.io/api/common/DatePipe) pipe and [currency](https://angular.io/api/common/CurrencyPipe) pipe; for a complete list, see the [Pipes API list](https://angular.io/api?type=pipe). You can also define new pipes.
|
||||
|
||||
Angular 自带了很多管道,比如 [date](https://angular.cn/api/common/DatePipe) 管道和 [currency](https://angular.cno/api/common/CurrencyPipe) 管道,完整的列表参见 [Pipes API 列表](https://angular.cn/api?type=pipe)。你也可以自己定义一些新管道。
|
||||
|
||||
To specify a value transformation in an HTML template, use the [pipe operator (|)](https://angular.io/guide/template-syntax#pipe).
|
||||
To specify a value transformation in an HTML template, use the [pipe operator (|)](https://angular.io/guide/template-syntax#pipe).
|
||||
|
||||
要在 HTML 模板中指定值的转换方式,请使用 [管道操作符 (|)](https://angular.cn/guide/template-syntax#pipe)。
|
||||
|
||||
|
@ -266,14 +266,14 @@ You can chain pipes, sending the output of one pipe function to be transformed b
|
|||
Angular templates are *dynamic*. When Angular renders them, it transforms the DOM according to the instructions given by *directives*. A directive is a class with a `@Directive()` decorator.
|
||||
|
||||
Angular 的模板是*动态的*。当 Angular 渲染它们的时候,会根据*指令*给出的指示对 DOM 进行转换。
|
||||
指令就是一个带有 `@Directive` 装饰器的类。
|
||||
指令就是一个带有 `@Directive()` 装饰器的类。
|
||||
|
||||
A component is technically a directive.
|
||||
However, components are so distinctive and central to Angular applications that Angular
|
||||
defines the `@Component()` decorator, which extends the `@Directive()` decorator with
|
||||
template-oriented features.
|
||||
|
||||
组件从技术角度上说就是一个指令,但是由于组件对 Angular 应用来说非常独特、非常重要,因此 Angular 专门定义了 `@Component` 装饰器,它使用一些面向模板的特性扩展了 `@Directive` 装饰器。
|
||||
组件从技术角度上说就是一个指令,但是由于组件对 Angular 应用来说非常独特、非常重要,因此 Angular 专门定义了 `@Component()` 装饰器,它使用一些面向模板的特性扩展了 `@Directive()` 装饰器。
|
||||
|
||||
In addition to components, there are two other kinds of directives: *structural* and *attribute*.
|
||||
Angular defines a number of directives of both kinds, and you can define your own using the `@Directive()` decorator.
|
||||
|
@ -283,7 +283,7 @@ Angular 本身定义了一系列这两种类型的指令,你也可以使用 `@
|
|||
|
||||
Just as for components, the metadata for a directive associates the decorated class with a `selector` element that you use to insert it into HTML. In templates, directives typically appear within an element tag as attributes, either by name or as the target of an assignment or a binding.
|
||||
|
||||
像组件一样,指令的元数据把指令类和一个 `selector` 关联起来,`selector` 用来把该指令插入到 HTML 中。
|
||||
像组件一样,指令的元数据把它所装饰的指令类和一个 `selector` 关联起来,`selector` 用来把该指令插入到 HTML 中。
|
||||
在模板中,指令通常作为属性出现在元素标签上,可能仅仅作为名字出现,也可能作为赋值目标或绑定目标出现。
|
||||
|
||||
#### Structural directives
|
||||
|
@ -293,7 +293,7 @@ Just as for components, the metadata for a directive associates the decorated cl
|
|||
*Structural directives* alter layout by adding, removing, and replacing elements in the DOM.
|
||||
The example template uses two built-in structural directives to add application logic to how the view is rendered.
|
||||
|
||||
结构型指令通过添加、移除或替换 DOM 元素来修改布局。
|
||||
*结构型指令*通过添加、移除或替换 DOM 元素来修改布局。
|
||||
这个范例模板使用了两个内置的结构型指令来为要渲染的视图添加程序逻辑:
|
||||
|
||||
<code-example path="architecture/src/app/hero-list.component.1.html" linenums="false" header="src/app/hero-list.component.html (structural)" region="structural"></code-example>
|
||||
|
|
|
@ -22,7 +22,7 @@ While a small application might have only one NgModule, most apps have many more
|
|||
|
||||
An NgModule is defined by a class decorated with `@NgModule()`. The `@NgModule()` decorator is a function that takes a single metadata object, whose properties describe the module. The most important properties are as follows.
|
||||
|
||||
NgModule 是一个带有 `@NgModule` 装饰器的类。`@NgModule` 装饰器是一个函数,它接受一个元数据对象,该对象的属性用来描述这个模块。其中最重要的属性如下。
|
||||
NgModule 是一个带有 `@NgModule()` 装饰器的类。`@NgModule()` 装饰器是一个函数,它接受一个元数据对象,该对象的属性用来描述这个模块。其中最重要的属性如下。
|
||||
|
||||
* `declarations`: The [components](guide/architecture-components), *directives*, and *pipes* that belong to this NgModule.
|
||||
|
||||
|
@ -55,7 +55,7 @@ Here's a simple root NgModule definition.
|
|||
|
||||
The `export` property of `AppComponent` is included here for illustration; it isn't actually necessary in this example. A root NgModule has no reason to *export* anything because other modules don't need to *import* the root NgModule.
|
||||
|
||||
把 `AppComponent` 放到 `exports` 中只是为了演示导出的语法,这在本例子中实际上是没必要的。
|
||||
把 `AppComponent` 放到 `exports` 中是为了演示导出的语法,这在本例子中实际上是没必要的。
|
||||
根模块没有任何理由*导出*任何东西,因为其它模块永远不需要*导入*根模块。
|
||||
|
||||
</div>
|
||||
|
@ -99,9 +99,10 @@ When you create a component, it's associated directly with a single view, called
|
|||
树中的视图可以嵌套到任意深度。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
**Note:** The hierarchical structure of views is a key factor in the way Angular detects and responds to changes in the DOM and app data.
|
||||
**Note:** The hierarchical structure of views is a key factor in the way Angular detects and responds to changes in the DOM and app data.
|
||||
|
||||
**注意:** 视图的这种层次结构是 Angular 在 DOM 和应用数据中检测与响应变更时的关键因素。
|
||||
|
||||
视图的这种层次结构是 Angular 在 DOM 和应用数据中检测与响应变更时的关键因素。
|
||||
</div>
|
||||
|
||||
## NgModules and JavaScript modules
|
||||
|
@ -140,7 +141,7 @@ JavaScript 中,每个*文件*是一个模块,文件中定义的所有对象
|
|||
|
||||
Angular loads as a collection of JavaScript modules. You can think of them as library modules. Each Angular library name begins with the `@angular` prefix. Install them with the `npm` package manager and import parts of them with JavaScript `import` statements.
|
||||
|
||||
Angular 自带了一组 JavaScript 模块,你可以把它们看成库模块。每个 Angular 库的名称都带有 `@angular` 前缀。
|
||||
Angular 会作为一组 JavaScript 模块进行加载,你可以把它们看成库模块。每个 Angular 库的名称都带有 `@angular` 前缀。
|
||||
使用 `npm` 包管理器安装它们,并使用 JavaScript 的 `import` 语句导入其中的各个部分。
|
||||
|
||||
<br class="clear">
|
||||
|
|
|
@ -37,8 +37,7 @@ Here are some key features.
|
|||
* [Service Workers](guide/service-worker-intro): Use a service worker to reduce dependency on the network
|
||||
significantly improving the user experience.
|
||||
|
||||
[Service Worker](guide/service-worker-intro):Service Worker 是一个运行在浏览器中并为应用管理缓存的脚本。
|
||||
Service Worker 的功能类似于网络代理。它们会拦截发出的 HTTP 请求,如果存在已缓存的响应,则直接返回它。通过使用 Service Worker 来减轻对网络的依赖,你可以显著提升用户体验。
|
||||
[Service Worker](guide/service-worker-intro):借助 Service Worker 来减轻对网络的依赖,你可以显著提升用户体验。
|
||||
|
||||
## Domain-specific libraries
|
||||
|
||||
|
@ -84,11 +83,11 @@ without deep knowledge of animation techniques or CSS.
|
|||
|
||||
* [Workspace and File Structure](guide/file-structure): Understand the structure of Angular workspace and project folders.
|
||||
|
||||
[搭建本地开发环境](guide/setup):学习如何搭建用来开发《快速起步》的新项目。
|
||||
[工作空间与文件结构](guide/file-structure):理解 Angular 工作空间与项目文件夹的结构。
|
||||
|
||||
* [npm Packages](guide/npm-packages): The Angular Framework, Angular CLI, and components used by Angular applications are packaged as [npm](https://docs.npmjs.com/) packages and distributed via the npm registry. The Angular CLI creates a default `package.json` file, which specifies a starter set of packages that work well together and jointly support many common application scenarios.
|
||||
|
||||
[安装](guide/npm-packages):[Angular CLI](https://cli.angular.io/) 应用和 Angular 本身依赖于一些由库提供的特性和功能,这些库都是以 [npm](https://docs.npmjs.com/) 包的形式发布的。
|
||||
[npm 包](guide/npm-packages):Angular 框架、CLI 和应用中使用的组件都是用 [npm](https://docs.npmjs.com/) 打包的,并通过 npm 注册服务器进行发布。Angular CLI 会创建一个默认的 `package.json` 文件,它会指定一组初始的包,它们可以一起使用,共同支持很多常见的应用场景。
|
||||
|
||||
* [TypeScript configuration](guide/typescript-configuration): TypeScript is the primary language for Angular application development.
|
||||
|
||||
|
@ -100,7 +99,7 @@ without deep knowledge of animation techniques or CSS.
|
|||
|
||||
* [Building and Serving](guide/build): Learn to define different build and proxy server configurations for your project, such as development, staging, and production.
|
||||
|
||||
[浏览器支持](guide/browser-support):学习如何让你的应用能和各种浏览器兼容。
|
||||
[构建与启动开发服务器](guide/build):学习为项目定义不同的构建和代理服务器设置的配置方式,比如开发、预生产和生产。
|
||||
|
||||
* [Deployment](guide/deployment): Learn techniques for deploying your Angular application to a remote server.
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ By separating a component's view-related functionality from other kinds of proce
|
|||
you can make your component classes lean and efficient.
|
||||
|
||||
Angular 把组件和服务区分开,以提高模块性和复用性。
|
||||
通过把组件中和视图有关的功能与其他类型的处理分离开,你可以让组件类更加精简、高效。
|
||||
通过把组件中和视图有关的功能与其他类型的处理分离开,你可以让组件类更加精简、高效。
|
||||
|
||||
Ideally, a component's job is to enable the user experience and nothing more.
|
||||
A component should present properties and methods for data binding,
|
||||
|
@ -19,7 +19,7 @@ in order to mediate between the view (rendered by the template)
|
|||
and the application logic (which often includes some notion of a *model*).
|
||||
|
||||
理想情况下,组件的工作只管用户体验,而不用顾及其它。
|
||||
它应该提供用于数据绑定的属性和方法,以便作为视图(由模板渲染)和应用逻辑(通常包含一些模型的概念)的中介者。
|
||||
它应该提供用于数据绑定的属性和方法,以便作为视图(由模板渲染)和应用逻辑(通常包含一些*模型*的概念)的中介者。
|
||||
|
||||
A component can delegate certain tasks to services, such as fetching data from the server,
|
||||
validating user input, or logging directly to the console.
|
||||
|
@ -62,26 +62,23 @@ Services can depend on other services. For example, here's a `HeroService` that
|
|||
DI is wired into the Angular framework and used everywhere to provide new components with the services or other things they need.
|
||||
Components consume services; that is, you can *inject* a service into a component, giving the component access to that service class.
|
||||
|
||||
DI 被融入 Angular 框架中,用于在任何地方给新建的组件提供服务或所需的其它东西。
|
||||
组件是服务的消费者,也就是说,你可以把一个服务*注入*到组件中,让组件类得以访问该服务类。
|
||||
|
||||
To define a class as a service in Angular, use the `@Injectable()` decorator to provide the metadata that allows Angular to inject it into a component as a *dependency*.
|
||||
Similarly, use the `@Injectable()` decorator to indicate that a component or other class (such as another service, a pipe, or an NgModule) *has* a dependency.
|
||||
|
||||
在 Angular 中,要把一个类定义为服务,就要用 `@Injectable` 装饰器来提供元数据,以便让 Angular 可以把它作为*依赖*注入到组件中。
|
||||
同样,也要使用 `@Injectable` 装饰器来表明一个组件或其它类(比如另一个服务、管道或 NgModule)*拥有*一个依赖。
|
||||
依赖并不必然是服务,它也可能是函数或值等等。
|
||||
在 Angular 中,要把一个类定义为服务,就要用 `@Injectable()` 装饰器来提供元数据,以便让 Angular 可以把它作为*依赖*注入到组件中。
|
||||
同样,也要使用 `@Injectable()` 装饰器来表明一个组件或其它类(比如另一个服务、管道或 NgModule)*拥有*一个依赖。
|
||||
|
||||
* The *injector* is the main mechanism. Angular creates an application-wide injector for you during the bootstrap process, and additional injectors as needed. You don't have to create injectors.
|
||||
|
||||
*注入器*是主要的机制。你不用自己创建 Angular 注入器。Angular 会在启动过程中为你创建全应用级注入器。
|
||||
*注入器*是主要的机制。你不用自己创建 Angular 注入器。Angular 会在启动过程中为你创建全应用级注入器以及所需的其它注入器。你不用自己创建注入器。
|
||||
|
||||
* An injector creates dependencies, and maintains a *container* of dependency instances that it reuses if possible.
|
||||
|
||||
该注入器会创建依赖、维护一个*容器*来管理这些依赖,并尽可能复用它们。
|
||||
|
||||
同样,也要使用 `@Injectable` 装饰器来表明一个组件或其它类(比如另一个服务、管道或 NgModule)*拥有*一个依赖。
|
||||
依赖并不必然是服务,它也可能是函数或值等等。
|
||||
|
||||
* A *provider* is an object that tell an injector how to obtain or create a dependency.
|
||||
|
||||
*提供商*是一个对象,用来告诉注入器应该如何获取或创建依赖。
|
||||
|
@ -134,11 +131,11 @@ or you can register providers with specific modules or components.
|
|||
You register providers in the metadata of the service (in the `@Injectable()` decorator),
|
||||
or in the `@NgModule()` or `@Component()` metadata
|
||||
|
||||
对于要用到的任何服务,你必须至少注册一个*提供商*。服务可以注册自己的提供商,这样可以让自己到处可用。或者,你也可以为特定的模块或组件注册提供商。要注册提供商,就要在服务的 `@Injectable` 装饰器中提供它的元数据,或者在`@NgModule` 或 `@Component` 的元数据中。
|
||||
对于要用到的任何服务,你必须至少注册一个*提供商*。服务可以在自己的元数据中把自己注册为提供商,这样可以让自己随处可用。或者,你也可以为特定的模块或组件注册提供商。要注册提供商,就要在服务的 `@Injectable()` 装饰器中提供它的元数据,或者在`@NgModule()` 或 `@Component()` 的元数据中。
|
||||
|
||||
* By default, the Angular CLI command [`ng generate service`](cli/generate) registers a provider with the root injector for your service by including provider metadata in the `@Injectable()` decorator. The tutorial uses this method to register the provider of HeroService class definition.
|
||||
|
||||
默认情况下,Angular CLI 的 `ng generate service` 命令会在 `@Injectable` 装饰器中提供元数据,把它注册到根注入器中。本教程就用这种方法注册了 HeroService 的提供商:
|
||||
默认情况下,Angular CLI 的 [`ng generate service`](cli/generate) 命令会在 `@Injectable()` 装饰器中提供元数据来把它注册到根注入器中。本教程就用这种方法注册了 HeroService 的提供商:
|
||||
|
||||
```
|
||||
@Injectable({
|
||||
|
@ -155,7 +152,7 @@ or in the `@NgModule()` or `@Component()` metadata
|
|||
|
||||
* When you register a provider with a [specific NgModule](guide/architecture-modules), the same instance of a service is available to all components in that NgModule. To register at this level, use the `providers` property of the `@NgModule()` decorator,
|
||||
|
||||
当你使用[特定的 NgModule](guide/architecture-modules) 注册提供商时,该服务的同一个实例将会对该 NgModule 中的所有组件可用。要想在这一层注册,请用 `@NgModule` 装饰器中的 `providers` 属性:
|
||||
当你使用[特定的 NgModule](guide/architecture-modules) 注册提供商时,该服务的同一个实例将会对该 NgModule 中的所有组件可用。要想在这一层注册,请用 `@NgModule()` 装饰器中的 `providers` 属性:
|
||||
|
||||
```
|
||||
@NgModule({
|
||||
|
@ -172,7 +169,7 @@ service with each new instance of that component.
|
|||
At the component level, register a service provider in the `providers` property of the `@Component()` metadata.
|
||||
|
||||
当你在组件级注册提供商时,你会为该组件的每一个新实例提供该服务的一个新实例。
|
||||
要在组件级注册,就要在 `@Component` 元数据的 `providers` 属性中注册服务提供商。
|
||||
要在组件级注册,就要在 `@Component()` 元数据的 `providers` 属性中注册服务提供商。
|
||||
|
||||
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" header="src/app/hero-list.component.ts (component providers)" region="providers"></code-example>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ Angular is a platform and framework for building client applications in HTML and
|
|||
Angular is written in TypeScript. It implements core and optional functionality as a set of TypeScript libraries that you import into your apps.
|
||||
|
||||
Angular 是一个用 HTML 和 TypeScript 构建客户端应用的平台与框架。
|
||||
Angular 本身使用 TypeScript 写成的。它将核心功能和可选功能作为一组 TypeScript 库进行实现,你可以把它们导入你的应用中。
|
||||
Angular 本身就是用 TypeScript 写成的。它将核心功能和可选功能作为一组 TypeScript 库进行实现,你可以把它们导入你的应用中。
|
||||
|
||||
The basic building blocks of an Angular application are *NgModules*, which provide a compilation context for *components*. NgModules collect related code into functional sets; an Angular app is defined by a set of NgModules. An app always has at least a *root module* that enables bootstrapping, and typically has many more *feature modules*.
|
||||
|
||||
|
@ -86,7 +86,7 @@ Every Angular application has at least one component, the *root component* that
|
|||
|
||||
The `@Component()` decorator identifies the class immediately below it as a component, and provides the template and related component-specific metadata.
|
||||
|
||||
`@Component` 装饰器表明紧随它的那个类是一个组件,并提供模板和该组件专属的元数据。
|
||||
`@Component()` 装饰器表明紧随它的那个类是一个组件,并提供模板和该组件专属的元数据。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
|
@ -110,6 +110,7 @@ There are two types of data binding:
|
|||
|
||||
模板会把 HTML 和 Angular 的标记(markup)组合起来,这些标记可以在 HTML 元素显示出来之前修改它们。
|
||||
模板中的*指令*会提供程序逻辑,而*绑定标记*会把你应用中的数据和 DOM 连接在一起。
|
||||
有两种类型的数据绑定:
|
||||
|
||||
* *Event binding* lets your app respond to user input in the target environment by updating your application data.
|
||||
|
||||
|
@ -148,7 +149,7 @@ Angular 为一些通用的转换提供了预定义管道,你还可以定义自
|
|||
For data or logic that isn't associated with a specific view, and that you want to share across components, you create a *service* class. A service class definition is immediately preceded by the `@Injectable()` decorator. The decorator provides the metadata that allows your service to be *injected* into client components as a dependency.
|
||||
|
||||
对于与特定视图无关并希望跨组件共享的数据或逻辑,可以创建*服务*类。
|
||||
服务类的定义通常紧跟在 “@Injectable” 装饰器之后。该装饰器提供的元数据可以让你的服务作为依赖*被注入到*客户组件中。
|
||||
服务类的定义通常紧跟在 “@Injectable()” 装饰器之后。该装饰器提供的元数据可以让你的服务作为依赖*被注入到*客户组件中。
|
||||
|
||||
*Dependency injection* (DI) lets you keep your component classes lean and efficient. They don't fetch data from the server, validate user input, or log directly to the console; they delegate such tasks to services.
|
||||
|
||||
|
@ -291,5 +292,5 @@ Each of these subjects is introduced in more detail in the following pages.
|
|||
When you're familiar with these fundamental building blocks, you can explore them in more detail in the documentation. To learn about more tools and techniques that are available to help you build and deploy Angular applications, see [Next steps: tools and techniques](guide/architecture-next-steps).
|
||||
|
||||
当你熟悉了这些基础构造块之后,就可以在本文档中进一步查看它们的详情了。
|
||||
要学习能帮你构建和发布应用的更多工具和技巧,参见[后续步骤](guide/architecture-next-steps)。
|
||||
要学习能帮你构建和发布应用的更多工具和技巧,参见[后续步骤:工具与技巧](guide/architecture-next-steps)。
|
||||
</div>
|
||||
|
|
|
@ -80,7 +80,7 @@ when the user hovers over that element. You can apply it like this:
|
|||
|
||||
Create the directive class file in a terminal window with the CLI command [`ng generate directive`](cli/generate).
|
||||
|
||||
在命令行窗口下用 CLI 命令创建指令类文件。
|
||||
在命令行窗口下用 CLI 命令 [`ng generate directive`](cli/generate) 创建指令类文件。
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
ng generate directive highlight
|
||||
|
|
|
@ -27,7 +27,7 @@ NgModule 用于描述应用的各个部分如何组织在一起。
|
|||
|
||||
If you use the [Angular CLI](cli) to generate an app, the default `AppModule` is as follows:
|
||||
|
||||
如果你使用 CLI 来生成一个应用,其默认的 `AppModule` 是这样的:
|
||||
如果你使用 [Angular CLI](cli) 来生成一个应用,其默认的 `AppModule` 是这样的:
|
||||
|
||||
```typescript
|
||||
|
||||
|
@ -87,7 +87,7 @@ into the `index.html` host web page.
|
|||
The default application created by the Angular CLI only has one component, `AppComponent`, so it
|
||||
is in both the `declarations` and the `bootstrap` arrays.
|
||||
|
||||
默认的 CLI 应用只有一个组件 `AppComponent`,所以它会同时出现在 `declarations` 和 `bootstrap` 数组中。
|
||||
CLI 创建的默认应用只有一个组件 `AppComponent`,所以它会同时出现在 `declarations` 和 `bootstrap` 数组中。
|
||||
|
||||
{@a declarations}
|
||||
|
||||
|
@ -223,7 +223,7 @@ A component template can reference another component, directive,
|
|||
or pipe when the referenced class is declared in this module or
|
||||
the class was imported from another module.
|
||||
|
||||
列表中的模块导出了本模块中的各个组件模板中所引用的各个组件、指令或管道。在这个例子中,当前组件是 `AppComponent`,它引用了导出自 `BrowserModule`、`FormsModule` 或 `HttpModule` 的组件、指令或管道。
|
||||
列表中的模块导出了本模块中的各个组件模板中所引用的各个组件、指令或管道。在这个例子中,当前组件是 `AppComponent`,它引用了导出自 `BrowserModule`、`FormsModule` 或 `HttpClientModule` 的组件、指令或管道。
|
||||
总之,组件的模板中可以引用在当前模块中声明的或从其它模块中导入的组件、指令、管道。
|
||||
|
||||
{@a bootstrap-array}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
# Dependency Injection in Action
|
||||
|
||||
# 依赖注入实战
|
||||
|
||||
This section explores many of the features of dependency injection (DI) in Angular.
|
||||
|
||||
本节将会涉及 Angular 依赖注入(DI)的很多特性。
|
||||
|
@ -15,25 +17,26 @@ of the code in this cookbook.
|
|||
|
||||
## Nested service dependencies
|
||||
|
||||
## *@Injectable*和嵌套服务依赖
|
||||
## 嵌套的服务依赖
|
||||
|
||||
The _consumer_ of an injected service doesn't need to know how to create that service.
|
||||
It's the job of the DI framework to create and cache dependencies. The consumer just
|
||||
needs to let the DI framework know which dependencies it needs.
|
||||
|
||||
这些被注入服务的消费者不需要知道如何创建这个服务,它也不应该在乎。新建和缓存这个服务是依赖注入器的工作。
|
||||
这些被注入服务的消费者不需要知道如何创建这个服务。新建和缓存这个服务是依赖注入器的工作。消费者只要让依赖注入框架知道它需要哪些依赖项就可以了。
|
||||
|
||||
Sometimes a service depends on other services, which may depend on yet other services.
|
||||
The dependency injection framework resolves these nested dependencies in the correct order.
|
||||
At each step, the consumer of dependencies declares what it requires in its
|
||||
constructor, and lets the framework provide them.
|
||||
|
||||
有时候一个服务依赖其它服务...而其它服务可能依赖另外的更多服务。按正确的顺序解析这些嵌套依赖也是框架的工作。
|
||||
有时候一个服务依赖其它服务...而其它服务可能依赖另外的更多服务。
|
||||
依赖注入框架会负责正确的顺序解析这些嵌套的依赖项。
|
||||
在每一步,依赖的使用者只要在它的构造函数里简单声明它需要什么,框架就会完成所有剩下的事情。
|
||||
|
||||
The following example shows that `AppComponent` declares its dependence on `LoggerService` and `UserContext`.
|
||||
|
||||
下面的例子往 `AppComponent` 里注入的 `LoggerService` 和 `UserContext`。
|
||||
下面的例子往 `AppComponent` 里声明它依赖 `LoggerService` 和 `UserContext`。
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/app.component.ts" region="ctor" header="src/app/app.component.ts" linenums="false">
|
||||
|
||||
|
@ -42,7 +45,7 @@ The following example shows that `AppComponent` declares its dependence on `Logg
|
|||
`UserContext` in turn depends on both `LoggerService` and
|
||||
`UserService`, another service that gathers information about a particular user.
|
||||
|
||||
`UserContext` 有两个依赖 `LoggerService`(再一次)和负责获取特定用户信息的 `UserService`。
|
||||
`UserContext` 转而依赖 `LoggerService` 和 `UserService`(这个服务用来收集特定用户信息)。
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/user-context.service.ts" region="injectables" header="user-context.service.ts (injection)" linenums="false">
|
||||
|
||||
|
@ -51,9 +54,9 @@ The following example shows that `AppComponent` declares its dependence on `Logg
|
|||
When Angular creates `AppComponent`, the DI framework creates an instance of `LoggerService` and starts to create `UserContextService`.
|
||||
`UserContextService` also needs `LoggerService`, which the framework already has, so the framework can provide the same instance. `UserContextService` also needs `UserService`, which the framework has yet to create. `UserService` has no further dependencies, so the framework can simply use `new` to instantiate the class and provide the instance to the `UserContextService` constructor.
|
||||
|
||||
当 Angular 新建 `AppComponent` 时,依赖注入框架先创建一个 `LoggerService` 的实例,然后创建 `UserContextService` 实例。
|
||||
`UserContextService` 需要框架已经创建好的 `LoggerService` 实例和尚未创建的 `UserService` 实例。
|
||||
`UserService` 没有其它依赖,所以依赖注入框架可以直接 `new` 一个实例。
|
||||
当 Angular 新建 `AppComponent` 时,依赖注入框架会先创建一个 `LoggerService` 的实例,然后创建 `UserContextService` 实例。
|
||||
`UserContextService` 也需要框架刚刚创建的这个 `LoggerService` 实例,这样框架才能为它提供同一个实例。`UserContextService` 还需要框架创建过的 `UserService`。
|
||||
`UserService` 没有其它依赖,所以依赖注入框架可以直接 `new` 出该类的一个实例,并把它提供给 `UserContextService` 的构造函数。
|
||||
|
||||
The parent `AppComponent` doesn't need to know about the dependencies of dependencies.
|
||||
Declare what's needed in the constructor (in this case `LoggerService` and `UserContextService`)
|
||||
|
@ -74,6 +77,8 @@ When all dependencies are in place, `AppComponent` displays the user information
|
|||
|
||||
## Limit service scope to a component subtree
|
||||
|
||||
## 把服务的范围限制到某个组件的子树下
|
||||
|
||||
An Angular application has multiple injectors, arranged in a tree hierarchy that parallels the component tree.
|
||||
Each injector creates a singleton instance of a dependency.
|
||||
That same instance is injected wherever that injector provides that service.
|
||||
|
@ -99,8 +104,7 @@ This example shows how to make a different instance of `HeroService` available t
|
|||
by adding it to the `providers` array of the `@Component()` decorator of the sub-component.
|
||||
|
||||
通过*在组件树的子级根组件*中提供服务,可以把一个被注入服务的作用域局限在应用程序结构中的某个*分支*中。
|
||||
这个例子中展示了为子组件和根组件 `AppComponent` 提供服务的相似之处,它们的语法是相同的。
|
||||
这里通过列入 `providers` 数组,在 `HeroesBaseComponent` 中提供了 `HeroService`:
|
||||
这个例子中展示了如何通过把服务添加到子组件 `@Component()` 装饰器的 `providers` 数组中,来为 `HeroesBaseComponent` 提供另一个 `HeroService` 实例:
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/sorted-heroes.component.ts" region="injection" header="src/app/sorted-heroes.component.ts (HeroesBaseComponent excerpt)">
|
||||
|
||||
|
@ -114,7 +118,7 @@ that is visible only to that component and its children, if any.
|
|||
You could also provide `HeroService` to a different component elsewhere in the application.
|
||||
That would result in a different instance of the service, living in a different injector.
|
||||
|
||||
也可以在应用程序别处的*不同的*组件里提供 `HeroService`。这样就会导致在*不同*注入器中存在该服务的*不同*实例。
|
||||
也可以在应用程序别处的另一个组件里提供 `HeroService`。这样就会导致在另一个注入器中存在该服务的另一个实例。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
|
@ -132,11 +136,11 @@ Each of these components has its own `HeroService` instance managing its own ind
|
|||
|
||||
## Multiple service instances (sandboxing)
|
||||
|
||||
## 多个服务实例(sandboxing)
|
||||
## 多个服务实例(沙箱式隔离)
|
||||
|
||||
Sometimes you want multiple instances of a service at *the same level* of the component hierarchy.
|
||||
|
||||
在*同一个级别的组件树*里,有时需要一个服务的多个实例。
|
||||
在组件树的*同一个级别*上,有时需要一个服务的多个实例。
|
||||
|
||||
A good example is a service that holds state for its companion component instance.
|
||||
You need a separate instance of the service for each component.
|
||||
|
@ -210,36 +214,61 @@ By default, the DI framework searches for a provider in the injector hierarchy,
|
|||
starting at the component's local injector of the component, and if necessary bubbling up
|
||||
through the injector tree until it reaches the root injector.
|
||||
|
||||
当类需要某个依赖项时,该依赖项就会作为参数添加到类的构造函数中。
|
||||
当 Angular 需要实例化该类时,就会调用 DI 框架来提供该依赖。
|
||||
默认情况下,DI 框架会在注入器树中查找一个提供商,从该组件的局部注入器开始,如果需要,则沿着注入器树向上冒泡,直到根注入器。
|
||||
|
||||
* The first injector configured with a provider supplies the dependency (a service instance or value) to the constructor.
|
||||
|
||||
第一个配置了该提供商的注入器就会把依赖(服务实例或值)提供给这个构造函数。
|
||||
|
||||
* If no provider is found in the root injector, the DI framework returns null to the constructor.
|
||||
|
||||
如果在根注入器中也没有找到提供商,则 DI 框架将会给构造函数返回一个 null。
|
||||
|
||||
There are a number of options for modifying the default search behavior, using _parameter decorators_
|
||||
on the service-valued parameters of a class constructor.
|
||||
|
||||
通过在类的构造函数中对服务参数使用*参数装饰器*,可以提供一些选项来修改默认的搜索行为。
|
||||
|
||||
{@a optional}
|
||||
|
||||
### Make a dependency `@Optional` and limit search with `@Host`
|
||||
|
||||
### 用 `@Optional` 来让依赖是可选的,以及使用 `@Host` 来限定搜索方式
|
||||
|
||||
Dependencies can be registered at any level in the component hierarchy.
|
||||
When a component requests a dependency, Angular starts with that component's injector
|
||||
and walks up the injector tree until it finds the first suitable provider.
|
||||
Angular throws an error if it can't find the dependency during that walk.
|
||||
|
||||
依赖可以注册在组件树的任何层级上。
|
||||
当组件请求某个依赖时,Angular 会从该组件的注入器找起,沿着注入器树向上,直到找到了第一个满足要求的提供商。如果没找到依赖,Angular 就会抛出一个错误。
|
||||
|
||||
In some cases, you need to limit the search or accommodate a missing dependency.
|
||||
You can modify Angular's search behavior with the `@Host` and `@Optional` qualifying
|
||||
decorators on a service-valued parameter of the component's constructor.
|
||||
|
||||
某些情况下,你需要限制搜索,或容忍依赖项的缺失。
|
||||
你可以使用组件构造函数参数上的 `@Host` 和 `@Optional` 这两个限定装饰器来修改 Angular 的搜索行为。
|
||||
|
||||
* The `@Optional` property decorator tells Angular to return null when it can't find the dependency.
|
||||
|
||||
`@Optional` 属性装饰器告诉 Angular 当找不到依赖时就返回 null。
|
||||
|
||||
* The `@Host` property decorator stops the upward search at the *host component*.
|
||||
The host component is typically the component requesting the dependency.
|
||||
However, when this component is projected into a *parent* component,
|
||||
that parent component becomes the host. The following example covers this second case.
|
||||
|
||||
`@Host` 属性装饰器会禁止在*宿主组件*上搜索。宿主组件通常就是请求该依赖的那个组件。
|
||||
不过,当该组件投影进某个*父*组件时,那个父组件就会变成宿主。下面的例子中介绍了第二种情况。
|
||||
|
||||
These decorators can be used individually or together, as shown in the example.
|
||||
This `HeroBiosAndContactsComponent` is a revision of `HeroBiosComponent` which you looked at [above](guide/dependency-injection-in-action#hero-bios-component).
|
||||
|
||||
如下例所示,这些装饰器可以独立使用,也可以同时使用。这个`HeroBiosAndContactsComponent` 是你[以前](guide/dependency-injection-in-action#hero-bios-component)见过的那个 `HeroBiosComponent` 的修改版。
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="hero-bios-and-contacts" header="src/app/hero-bios.component.ts (HeroBiosAndContactsComponent)">
|
||||
|
||||
</code-example>
|
||||
|
@ -265,7 +294,7 @@ placing it in the `<ng-content>` slot of the `HeroBioComponent` template.
|
|||
|
||||
The result is shown below, with the hero's telephone number from `HeroContactComponent` projected above the hero description.
|
||||
|
||||
从 `HeroContactComponent` 获得的英雄电话号码,被投影到上面的英雄描述里,就像这样:
|
||||
从 `HeroContactComponent` 获得的英雄电话号码,被投影到上面的英雄描述里,结果如下:
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/dependency-injection-in-action/hero-bio-and-content.png" alt="bio and contact">
|
||||
|
@ -274,12 +303,16 @@ The result is shown below, with the hero's telephone number from `HeroContactCom
|
|||
|
||||
Here's `HeroContactComponent`, which demonstrates the qualifying decorators.
|
||||
|
||||
这里的 `HeroContactComponent` 演示了限定型装饰器。
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-contact.component.ts" region="component" header="src/app/hero-contact.component.ts">
|
||||
|
||||
</code-example>
|
||||
|
||||
Focus on the constructor parameters.
|
||||
|
||||
注意构造函数的参数。
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-contact.component.ts" region="ctor-params" header="src/app/hero-contact.component.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
|
@ -289,20 +322,20 @@ you get a reference to the cache service from the parent `HeroBioComponent`.
|
|||
Angular throws an error if the parent lacks that service, even if a component higher
|
||||
in the component tree includes it.
|
||||
|
||||
`@Host()` 函数是 `heroCache` 属性的装饰器,确保从其父组件 `HeroBioComponent` 得到一个缓存服务。如果该父组件不存在这个服务,Angular 就会抛出错误,即使组件树里的再上级有某个组件拥有这个服务,Angular 也会抛出错误。
|
||||
`@Host()` 函数是构造函数属性 `heroCache` 的装饰器,确保从其父组件 `HeroBioComponent` 得到一个缓存服务。如果该父组件不存在这个服务,Angular 就会抛出错误,即使组件树里的再上级有某个组件拥有这个服务,Angular 也会抛出错误。
|
||||
|
||||
A second `@Host()` function decorates the `loggerService` constructor property.
|
||||
The only `LoggerService` instance in the app is provided at the `AppComponent` level.
|
||||
The host `HeroBioComponent` doesn't have its own `LoggerService` provider.
|
||||
|
||||
另一个 `@Host()` 函数是属性 `loggerService` 的装饰器。
|
||||
另一个 `@Host()` 函数是构造函数属性 `loggerService` 的装饰器。
|
||||
在本应用程序中只有一个在 `AppComponent` 级提供的 `LoggerService` 实例。
|
||||
该宿主 `HeroBioComponent` 没有自己的 `LoggerService` 提供商。
|
||||
|
||||
Angular throws an error if you haven't also decorated the property with `@Optional()`.
|
||||
When the property is marked as optional, Angular sets `loggerService` to null and the rest of the component adapts.
|
||||
|
||||
如果没有同时使用 `@Optional()` 装饰器的话,Angular 就会抛出错误。多亏了 `@Optional()`,Angular 把 `loggerService` 设置为 null,并继续执行组件而不会抛出错误。
|
||||
如果没有同时使用 `@Optional()` 装饰器的话,Angular 就会抛出错误。当该属性带有 `@Optional()` 标记时,Angular 就会把 `loggerService` 设置为 null,并继续执行组件而不会抛出错误。
|
||||
|
||||
Here's `HeroBiosAndContactsComponent` in action.
|
||||
|
||||
|
@ -317,7 +350,7 @@ until it finds the logger at the `AppComponent` level.
|
|||
The logger logic kicks in and the hero display updates
|
||||
with the "!!!" marker to indicate that the logger was found.
|
||||
|
||||
如果注释掉 `@Host()` 装饰器,Angular 就会沿着注入器树往上走,直到在 `AppComponent` 中找到该日志服务。日志服务的逻辑加入进来,更新了英雄的显示信息,这表明确实找到了日志服务。
|
||||
如果注释掉 `@Host()` 装饰器,Angular 就会沿着注入器树往上走,直到在 `AppComponent` 中找到该日志服务。日志服务的逻辑加了进来,所显示的英雄信息增加了 "!!!" 标记,这表明确实找到了日志服务。
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/dependency-injection-in-action/hero-bio-contact-no-host.png" alt="Without @Host">
|
||||
|
@ -327,35 +360,52 @@ If you restore the `@Host()` decorator and comment out `@Optional`,
|
|||
the app throws an exception when it cannot find the required logger at the host component level.
|
||||
`EXCEPTION: No provider for LoggerService! (HeroContactComponent -> LoggerService)`
|
||||
|
||||
如果你恢复了 `@Host()` 装饰器,并且注释掉 `@Optional` 装饰器,应用就会抛出一个错误,因为它在宿主组件这一层找不到所需的 `Logger`。`EXCEPTION: No provider for LoggerService! (HeroContactComponent -> LoggerService)`
|
||||
|
||||
### Supply a custom provider with `@Inject`
|
||||
|
||||
### 使用 `@Inject` 指定自定义提供商
|
||||
|
||||
Using a custom provider allows you to provide a concrete implementation for implicit dependencies, such as built-in browser APIs. The following example uses an `InjectionToken` to provide the [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) browser API as a dependency in the `BrowserStorageService`.
|
||||
|
||||
自定义提供商让你可以为隐式依赖提供一个具体的实现,比如内置浏览器 API。下面的例子使用 `InjectionToken` 来提供 [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage),将其作为 `BrowserStorageService` 的依赖项。
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/storage.service.ts" header="src/app/storage.service.ts">
|
||||
|
||||
</code-example>
|
||||
|
||||
The `factory` function returns the `localStorage` property that is attached to the browser window object. The `Inject` decorator is a constructor parameter used to specify a custom provider of a dependency. This custom provider can now be overridden during testing with a mock API of `localStorage` instead of interactive with real browser APIs.
|
||||
|
||||
`factory` 函数返回 window 对象上的 `localStorage` 属性。`Inject` 装饰器修饰一个构造函数参数,用于为某个依赖提供自定义提供商。现在,就可以在测试期间使用 `localStorage` 的 Mock API 来覆盖这个提供商了,而不必与真实的浏览器 API 进行交互。
|
||||
|
||||
### Modify the provider search with `@Self` and `@SkipSelf`
|
||||
|
||||
### 使用 `@Self` 和 `@SkipSelf` 来修改提供商的搜索方式
|
||||
|
||||
Providers can also be scoped by injector through constructor parameter decorators. The following example overrides the `BROWSER_STORAGE` token in the `Component` class `providers` with the `sessionStorage` browser API. The same `BrowserStorageService` is injected twice in the constructor, decorated with `@Self` and `@SkipSelf` to define which injector handles the provider dependency.
|
||||
|
||||
注入器也可以通过构造函数的参数装饰器来指定范围。下面的例子就在 `Component` 类的 `providers` 中使用浏览器的 `sessionStorage` API 覆盖了 `BROWSER_STORAGE` 令牌。同一个 `BrowserStorageService` 在构造函数中使用 `@Self` 和 `@SkipSelf` 装饰器注入了两次,来分别指定由哪个注入器来提供依赖。
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/storage.component.ts" header="src/app/storage.component.ts">
|
||||
|
||||
</code-example>
|
||||
|
||||
Using the `@Self` decorator, the injector only looks at the component's injector for its providers. The `@SkipSelf` decorator allows you to skip the local injector and look up in the hierarchy to find a provider that satisfies this dependency. The `sessionStorageService` instance interacts with the `BrowserStorageService` using the `sessionStorage` browser API, while the `localStorageService` skips the local injector and uses the root `BrowserStorageService` that uses the `localStorage` browswer API.
|
||||
|
||||
使用 `@Self` 装饰器时,注入器只在该组件的注入器中查找提供商。`@SkipSelf` 装饰器可以让你跳过局部注入器,并在注入器树中向上查找,以发现哪个提供商满足该依赖。
|
||||
`sessionStorageService` 实例使用浏览器的 `sessionStorage` 来跟 `BrowserStorageService` 打交道,而 `localStorageService` 跳过了局部注入器,使用根注入器提供的 `BrowserStorageService`,它使用浏览器的 `localStorage` API。
|
||||
|
||||
{@a component-element}
|
||||
|
||||
## Inject the component's DOM element
|
||||
|
||||
## 注入组件的 DOM 元素
|
||||
|
||||
Although developers strive to avoid it, many visual effects and third-party tools, such as jQuery,
|
||||
require DOM access.
|
||||
As a result, you might need to access a component's DOM element.
|
||||
|
||||
偶尔,可能需要访问一个组件对应的 DOM 元素。尽量避免这样做,但还是有很多视觉效果和第三方工具(比如 jQuery)需要访问 DOM。
|
||||
即便开发者极力避免,仍然会有很多视觉效果和第三方工具 (比如 jQuery) 需要访问 DOM。这会让你不得不访问组件所在的 DOM 元素。
|
||||
|
||||
To illustrate, here's a simplified version of `HighlightDirective` from
|
||||
the [Attribute Directives](guide/attribute-directives) page.
|
||||
|
@ -369,7 +419,7 @@ the [Attribute Directives](guide/attribute-directives) page.
|
|||
The directive sets the background to a highlight color when the user mouses over the
|
||||
DOM element to which the directive is applied.
|
||||
|
||||
当用户把鼠标移到 DOM 元素上时,指令将该元素的背景设置为一个高亮颜色。
|
||||
当用户把鼠标移到 DOM 元素上时,指令将指令所在的元素的背景设置为一个高亮颜色。
|
||||
|
||||
Angular sets the constructor's `el` parameter to the injected `ElementRef`.
|
||||
(An `ElementRef` is a wrapper around a DOM element,
|
||||
|
@ -403,13 +453,21 @@ The following image shows the effect of mousing over the `<hero-bios-and-contact
|
|||
|
||||
This section demonstrates how to write providers that deliver dependent services.
|
||||
|
||||
本节会示范如何编写提供商来交付被依赖的服务。
|
||||
|
||||
In order to get a service from a dependency injector, you have to give it a [token](guide/glossary#token).
|
||||
Angular usually handles this transaction by specifying a constructor parameter and its type.
|
||||
The parameter type serves as the injector lookup token.
|
||||
Angular passes this token to the injector and assigns the result to the parameter.
|
||||
|
||||
为了从依赖注入器中获取服务,你必须传给它一个[令牌](guide/glossary#token)。
|
||||
Angular 通常会通过指定构造函数参数以及参数的类型来处理它。
|
||||
参数的类型可以用作注入器的查阅令牌。
|
||||
Angular 会把该令牌传给注入器,并把它的结果赋给相应的参数。
|
||||
|
||||
The following is a typical example.
|
||||
|
||||
下面是一个典型的例子。
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="ctor" header="src/app/hero-bios.component.ts (component constructor injection)" linenums="false">
|
||||
|
||||
|
@ -418,14 +476,14 @@ The following is a typical example.
|
|||
Angular asks the injector for the service associated with `LoggerService`
|
||||
and assigns the returned value to the `logger` parameter.
|
||||
|
||||
Angular 会要求注入器提供与 `LoggerService` 相关的服务,并把返回的值赋给 `logger` 参数。
|
||||
|
||||
If the injector has already cached an instance of the service associated with the token,
|
||||
it provides that instance.
|
||||
If it doesn't, it needs to make one using the provider associated with the token.
|
||||
|
||||
注入器从哪得到的依赖?
|
||||
它可能在自己内部容器里已经有该依赖了。
|
||||
如果它没有,也能在***提供商***的帮助下新建一个。
|
||||
*提供商*就是一个用于交付服务的配方,它被关联到一个令牌。
|
||||
如果注入器已经缓存了与该令牌相关的服务实例,那么它就会直接提供此实例。
|
||||
如果它没有,它就要使用与该令牌相关的提供商来创建一个。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
|
@ -442,18 +500,24 @@ A new injector has no providers.
|
|||
Angular initializes the injectors it creates with a set of preferred providers.
|
||||
You have to configure providers for your own app-specific dependencies.
|
||||
|
||||
新的注入器没有提供商。
|
||||
Angular 会使用一组首选提供商来初始化它本身的注入器。
|
||||
你必须为自己应用程序特有的依赖项来配置提供商。
|
||||
|
||||
{@a defining-providers}
|
||||
|
||||
### Defining providers
|
||||
|
||||
### 定义提供商
|
||||
|
||||
A dependency can't always be created by the default method of instantiating a class.
|
||||
You learned about some other methods in [Dependency Providers](guide/dependency-injection-providers).
|
||||
The following `HeroOfTheMonthComponent` example demonstrates many of the alternatives and why you need them.
|
||||
It's visually simple: a few properties and the logs produced by a logger.
|
||||
|
||||
用于实例化类的默认方法不一定总适合用来创建依赖。你可以到[依赖提供商](guide/dependency-injection-providers)部分查看其它方法。
|
||||
`HeroOfTheMonthComponent` 例子示范了一些替代方案,展示了为什么需要它们。
|
||||
它看起来很简单:一些属性和一个日志输出。
|
||||
它看起来很简单:一些属性和一些由 logger 生成的日志。
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/dependency-injection-in-action/hero-of-month.png" alt="Hero of the month">
|
||||
|
@ -462,7 +526,8 @@ It's visually simple: a few properties and the logs produced by a logger.
|
|||
The code behind it customizes how and where the DI framework provides dependencies.
|
||||
The use cases illustrate different ways to use the [*provide* object literal](guide/dependency-injection-providers#provide) to associate a definition object with a DI token.
|
||||
|
||||
这段代码的背后有很多值得深入思考的地方。
|
||||
它背后的代码定制了 DI 框架提供依赖项的方法和位置。
|
||||
这个例子阐明了通过[*提供*对象字面量](guide/dependency-injection-providers#provide)来把对象的定义和 DI 令牌关联起来的另一种方式。
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="hero-of-the-month" header="hero-of-the-month.component.ts">
|
||||
|
||||
|
@ -471,21 +536,25 @@ The use cases illustrate different ways to use the [*provide* object literal](gu
|
|||
The `providers` array shows how you might use the different provider-definition keys;
|
||||
`useValue`, `useClass`, `useExisting`, or `useFactory`.
|
||||
|
||||
`providers` 数组展示了你可以如何使用其它的键来定义提供商:`useValue`、`useClass`、`useExisting` 或 `useFactory`。
|
||||
|
||||
{@a usevalue}
|
||||
|
||||
#### Value providers: `useValue`
|
||||
|
||||
#### 值提供商:`useValue`
|
||||
|
||||
The `useValue` key lets you associate a fixed value with a DI token.
|
||||
Use this technique to provide *runtime configuration constants* such as website base addresses and feature flags.
|
||||
You can also use a value provider in a unit test to provide mock data in place of a production data service.
|
||||
|
||||
`useValue` 键让你可以为 DI 令牌关联一个固定的值。
|
||||
使用该技巧来进行*运行期常量设置*,比如网站的基础地址和功能标志等。
|
||||
你通常在单元测试中使用*值-提供商*,用一个假的或模仿的(服务)来取代一个生产环境的服务。
|
||||
你也可以在单元测试中使用*值提供商*,来用一个 Mock 数据来代替一个生产环境下的数据服务。
|
||||
|
||||
The `HeroOfTheMonthComponent` example has two value providers.
|
||||
|
||||
`HeroOfTheMonthComponent` 例子有两个*值-提供商*。
|
||||
第一个提供了一个 `Hero` 类的实例;第二个指定了一个字符串资源:
|
||||
`HeroOfTheMonthComponent` 例子中有两个*值-提供商*。
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="use-value" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" linenums="false">
|
||||
|
||||
|
@ -495,44 +564,56 @@ The `HeroOfTheMonthComponent` example has two value providers.
|
|||
requiring the injector to create a new instance with `new` or use its own cached instance.
|
||||
Here, the token is the class itself.
|
||||
|
||||
第一处提供了用于 `Hero` 令牌的 `Hero` 类的现有实例,而不是要求注入器使用 `new` 来创建一个新实例或使用它自己的缓存实例。这里令牌就是这个类本身。
|
||||
|
||||
* The second specifies a literal string resource to use for the `TITLE` token.
|
||||
The `TITLE` provider token is *not* a class, but is instead a
|
||||
special kind of provider lookup key called an [injection token](guide/dependency-injection-in-action#injection-token), represented by
|
||||
an `InjectionToken` instance.
|
||||
|
||||
第二处为 `TITLE` 令牌指定了一个字符串字面量资源。
|
||||
`TITLE` 提供商的令牌*不是一个类*,而是一个特别的提供商查询键,名叫[InjectionToken](guide/dependency-injection-in-action#injection-token),表示一个 `InjectionToken` 实例。
|
||||
|
||||
You can use an injection token for any kind of provider but it's particularly
|
||||
helpful when the dependency is a simple value like a string, a number, or a function.
|
||||
|
||||
`TITLE` 提供商的令牌*不是一个类*。它是一个特别类型的提供商查询键,名叫[InjectionToken](guide/dependency-injection-in-action#injection-token).
|
||||
你可以把 `InjectionToken` 用作任何类型的提供商的令牌,但是它在依赖是简单类型(比如字符串、数字、函数)时会特别有帮助。
|
||||
你可以把 `InjectionToken` 用作任何类型的提供商的令牌,但是当依赖是简单类型(比如字符串、数字、函数)时,它会特别有用。
|
||||
|
||||
The value of a *value provider* must be defined before you specify it here.
|
||||
The title string literal is immediately available.
|
||||
The `someHero` variable in this example was set earlier in the file as shown below.
|
||||
You can't use a variable whose value will be defined later.
|
||||
|
||||
一个*值-提供商*的值必须要*立即*定义。不能事后再定义它的值。很显然,标题字符串是立刻可用的。
|
||||
该例中的 `someHero` 变量是以前在下面这个文件中定义的:
|
||||
一个*值-提供商*的值必须在指定之前定义。
|
||||
比如标题字符串就是立即可用的。
|
||||
该例中的 `someHero` 变量是以前在如下的文件中定义的。
|
||||
你不能使用那些要等以后才能定义其值的变量。
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="some-hero" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts">
|
||||
|
||||
</code-example>
|
||||
|
||||
Other types of providers can create their values *lazily*; that is, when they're needed for injection.其它提供商只在需要注入它们的时候才创建并*惰性加载*它们的值。
|
||||
Other types of providers can create their values *lazily*; that is, when they're needed for injection.
|
||||
|
||||
其它类型的提供商都会*惰性创建*它们的值,也就是说只在需要注入它们的时候才创建。
|
||||
|
||||
{@a useclass}
|
||||
|
||||
#### Class providers: `useClass`
|
||||
|
||||
#### useClass - *类-提供商*
|
||||
#### 类提供商:`useClass`
|
||||
|
||||
The `useClass` provider key lets you create and return a new instance of the specified class.
|
||||
|
||||
`useClass` 提供的键让你可以创建并返回指定类的新实例。
|
||||
|
||||
You can use this type of provider to substitute an *alternative implementation*
|
||||
for a common or default class.
|
||||
The alternative implementation could, for example, implement a different strategy,
|
||||
extend the default class, or emulate the behavior of the real class in a test case.
|
||||
|
||||
你可以使用这类提供商来为公共类或默认类换上一个*替代实现*。比如,这个替代实现可以实现一种不同的策略来扩展默认类,或在测试环境中模拟真实类的行为。
|
||||
|
||||
The following code shows two examples in `HeroOfTheMonthComponent`.
|
||||
|
||||
请看下面 `HeroOfTheMonthComponent` 里的两个例子:
|
||||
|
@ -546,13 +627,13 @@ class to be created (`HeroService`) is also the provider's dependency injection
|
|||
The short form is generally preferred; this long form makes the details explicit.
|
||||
|
||||
第一个提供商是*展开了语法糖的*,是一个典型情况的展开。一般来说,被新建的类(`HeroService`)同时也是该提供商的注入令牌。
|
||||
这里用完整形态来编写它,来反衬更受欢迎的缩写形式。
|
||||
通常都选用缩写形式,完整形式可以让细节更明确。
|
||||
|
||||
The second provider substitutes `DateLoggerService` for `LoggerService`.
|
||||
`LoggerService` is already registered at the `AppComponent` level.
|
||||
When this child component requests `LoggerService`, it receives a `DateLoggerService` instance instead.
|
||||
|
||||
第二个提供商使用 `DateLoggerService` 来满足 `LoggerService`。该 `LoggerService` 在 `AppComponent` 级别已经被注册。当*这个组件*要求 `LoggerService` 的时候,它得到的却是 `DateLoggerService` 服务。
|
||||
第二个提供商使用 `DateLoggerService` 来满足 `LoggerService`。该 `LoggerService` 在 `AppComponent` 级别已经被注册。当*这个组件*要求 `LoggerService` 的时候,它得到的却是 `DateLoggerService` 服务的实例。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
|
@ -563,7 +644,7 @@ Components outside the tree continue to receive the original `LoggerService` ins
|
|||
|
||||
</div>
|
||||
|
||||
`DateLoggerService` inherits from `LoggerService`; it appends the current date/time to each message:
|
||||
`DateLoggerService` inherits from `LoggerService`; it appends the current date/time to each message:
|
||||
|
||||
`DateLoggerService` 从 `LoggerService` 继承;它把当前的日期/时间附加到每条信息上。
|
||||
|
||||
|
@ -575,10 +656,14 @@ Components outside the tree continue to receive the original `LoggerService` ins
|
|||
|
||||
#### Alias providers: `useExisting`
|
||||
|
||||
#### 别名提供商:`useExisting`
|
||||
|
||||
The `useExisting` provider key lets you map one token to another.
|
||||
In effect, the first token is an *alias* for the service associated with the second token,
|
||||
creating two ways to access the same service object.
|
||||
|
||||
`useExisting` 提供了一个键,让你可以把一个令牌映射成另一个令牌。实际上,第一个令牌就是第二个令牌所关联的服务的*别名*,这样就创建了访问同一个服务对象的两种途径。
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="use-existing" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts">
|
||||
|
||||
</code-example>
|
||||
|
@ -586,13 +671,13 @@ creating two ways to access the same service object.
|
|||
You can use this technique to narrow an API through an aliasing interface.
|
||||
The following example shows an alias introduced for that purpose.
|
||||
|
||||
通过使用别名接口来把一个 API 变窄,是*一个*很重要的该技巧的使用例子。下面的例子中使用别名就是为了这个目的。
|
||||
你可以使用别名接口来窄化 API。下面的例子中使用别名就是为了这个目的。
|
||||
|
||||
Imagine that `LoggerService` had a large API, much larger than the actual three methods and a property.
|
||||
You might want to shrink that API surface to just the members you actually need.
|
||||
In this example, the `MinimalLogger` [class-interface](#class-interface) reduces the API to two members:
|
||||
|
||||
想象一下如果 `LoggerService` 有个很大的 API 接口(虽然它其实只有三个方法,一个属性),通过使用 `MinimalLogger`[*类-接口*](guide/dependency-injection-in-action#class-interface)别名,就能成功的把这个 API 接口缩小到只暴露两个成员:
|
||||
想象 `LoggerService` 有个很大的 API 接口,远超过现有的三个方法和一个属性。你可能希望把 API 接口收窄到只有两个你确实需要的成员。在这个例子中,`MinimalLogger`[*类-接口*](guide/dependency-injection-in-action#class-interface),就这个 API 成功缩小到了只有两个成员:
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/minimal-logger.service.ts" header="src/app/minimal-logger.service.ts" linenums="false">
|
||||
|
||||
|
@ -600,7 +685,7 @@ In this example, the `MinimalLogger` [class-interface](#class-interface) reduces
|
|||
|
||||
The following example puts `MinimalLogger` to use in a simplified version of `HeroOfTheMonthComponent`.
|
||||
|
||||
现在,在一个简化版的 `HeroOfTheMonthComponent` 中使用它。
|
||||
下面的例子在一个简化版的 `HeroOfTheMonthComponent` 中使用 `MinimalLogger`。
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.1.ts" header="src/app/hero-of-the-month.component.ts (minimal version)" linenums="false">
|
||||
|
||||
|
@ -616,8 +701,7 @@ The `HeroOfTheMonthComponent` constructor's `logger` parameter is typed as `Mini
|
|||
|
||||
Behind the scenes, Angular sets the `logger` parameter to the full service registered under the `LoggingService` token, which happens to be the `DateLoggerService` instance that was [provided above](guide/dependency-injection-in-action#useclass).
|
||||
|
||||
实际上,Angular 确实想把 `logger` 参数设置为注入器里 `LoggerService` 的完整版本。只是在之前的提供商注册里使用了 `useClass`,
|
||||
所以该完整版本被 `DateLoggerService` 取代了。
|
||||
实际上,Angular 把 `logger` 参数设置为注入器里 `LoggerService` 令牌下注册的完整服务,该令牌恰好是[以前提供的那个](guide/dependency-injection-in-action#useclass) `DateLoggerService` 实例。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
|
@ -635,9 +719,13 @@ This is illustrated in the following image, which displays the logging date.
|
|||
|
||||
#### Factory providers: `useFactory`
|
||||
|
||||
#### 工厂提供商:`useFactory`
|
||||
|
||||
The `useFactory` provider key lets you create a dependency object by calling a factory function,
|
||||
as in the following example.
|
||||
|
||||
`useFactory` 提供了一个键,让你可以通过调用一个工厂函数来创建依赖实例,如下面的例子所示。
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="use-factory" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts">
|
||||
|
||||
</code-example>
|
||||
|
@ -647,6 +735,9 @@ that you provide as the value of the `useFactory` key.
|
|||
Notice that this form of provider has a third key, `deps`, which specifies
|
||||
dependencies for the `useFactory` function.
|
||||
|
||||
注入器通过调用你用 `useFactory` 键指定的工厂函数来提供该依赖的值。
|
||||
注意,提供商的这种形态还有第三个键 `deps`,它指定了供 `useFactory` 函数使用的那些依赖。
|
||||
|
||||
Use this technique to create a dependency object with a factory function
|
||||
whose inputs are a combination of *injected services* and *local state*.
|
||||
|
||||
|
@ -657,13 +748,17 @@ but can be other things as well.
|
|||
In this example, the dependency object is a string of the names of the runners up
|
||||
to the "Hero of the Month" contest.
|
||||
|
||||
这个依赖对象(由工厂函数返回的)通常是一个类实例,不过也可以是任何其它东西。
|
||||
在这个例子中,以来对象是一个表示 "月度英雄" 参赛者名称的字符串。
|
||||
|
||||
In the example, the local state is the number `2`, the number of runners up that the component should show.
|
||||
The state value is passed as an argument to `runnersUpFactory()`.
|
||||
The `runnersUpFactory()` returns the *provider factory function*, which can use both
|
||||
the passed-in state value and the injected services `Hero` and `HeroService`.
|
||||
|
||||
|
||||
`runnersUpFactory` 自身不是提供商工厂函数。真正的提供商工厂函数是 `runnersUpFactory` 返回的函数。
|
||||
在这个例子中,局部状态是数字 `2`,也就是组件应该显示的参赛者数量。
|
||||
该状态的值传给了 `runnersUpFactory()` 作为参数。
|
||||
`runnersUpFactory()` 返回了*提供商的工厂函数*,它可以使用传入的状态值和注入的服务 `Hero` 和 `HeroService`。
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/runners-up.ts" region="factory-synopsis" header="runners-up.ts (excerpt)" linenums="false">
|
||||
|
||||
|
@ -672,15 +767,22 @@ the passed-in state value and the injected services `Hero` and `HeroService`.
|
|||
The provider factory function (returned by `runnersUpFactory()`) returns the actual dependency object,
|
||||
the string of names.
|
||||
|
||||
由 `runnersUpFactory()` 返回的提供商的工厂函数返回了实际的依赖对象,也就是表示名字的字符串。
|
||||
|
||||
* The function takes a winning `Hero` and a `HeroService` as arguments.
|
||||
|
||||
这个返回的函数需要一个 `Hero` 和一个 `HeroService` 参数。
|
||||
这个返回的函数需要一个 `Hero` 和一个 `HeroService` 参数。
|
||||
|
||||
Angular supplies these arguments from injected values identified by
|
||||
the two *tokens* in the `deps` array.
|
||||
|
||||
Angular 根据 `deps` 数组中指定的两个*令牌*来获得这些注入参数。
|
||||
|
||||
* The function returns the string of names, which Angular than injects into
|
||||
the `runnersUp` parameter of `HeroOfTheMonthComponent`.
|
||||
|
||||
该函数返回名字的字符串,Angular 可以把它们注入到 `HeroOfTheMonthComponent` 的 `runnersUp` 参数中。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
The function retrieves candidate heroes from the `HeroService`,
|
||||
|
@ -688,15 +790,22 @@ takes `2` of them to be the runners-up, and returns their concatenated names.
|
|||
Look at the <live-example name="dependency-injection-in-action"></live-example>
|
||||
for the full source code.
|
||||
|
||||
该函数从 `HeroService` 中接受候选的英雄,从中取 `2` 个参加竞赛,并把他们的名字串接起来返回。
|
||||
参见 <live-example name="dependency-injection-in-action"></live-example> 查看完整源码。
|
||||
|
||||
</div>
|
||||
|
||||
{@a tokens}
|
||||
|
||||
## Provider token alternatives: class interface and 'InjectionToken'
|
||||
|
||||
## 提供替代令牌:类接口与 'InjectionToken'
|
||||
|
||||
Angular dependency injection is easiest when the provider token is a class
|
||||
that is also the type of the returned dependency object, or service.
|
||||
|
||||
当使用类作为令牌,同时也把它作为返回依赖对象或服务的类型时,Angular 依赖注入使用起来最容易。
|
||||
|
||||
However, a token doesn't have to be a class and even when it is a class,
|
||||
it doesn't have to be the same type as the returned object.
|
||||
That's the subject of the next section.
|
||||
|
@ -708,6 +817,7 @@ That's the subject of the next section.
|
|||
### Classinterface
|
||||
|
||||
### 类-接口
|
||||
|
||||
The previous *Hero of the Month* example used the `MinimalLogger` class
|
||||
as the token for a provider of `LoggerService`.
|
||||
|
||||
|
@ -728,7 +838,8 @@ as the token for a provider of `LoggerService`.
|
|||
An abstract class is usually a base class that you can extend.
|
||||
In this app, however there is no class that inherits from `MinimalLogger`.
|
||||
|
||||
你通常从一个抽象类继承。但这个应用中*并没有*类会继承 `MinimalLogger`。
|
||||
你通常从一个可扩展的抽象类继承。但这个应用中*并没有*类会继承 `MinimalLogger`。
|
||||
|
||||
The `LoggerService` and the `DateLoggerService`could have inherited from `MinimalLogger`,
|
||||
or they could have implemented it instead, in the manner of an interface.
|
||||
But they did neither.
|
||||
|
@ -741,17 +852,16 @@ But they did neither.
|
|||
|
||||
When you use a class this way, it's called a *class interface*.
|
||||
|
||||
As mentioned in [DI Providers](guide/dependency-injection-providers#interface-not-valid-token),
|
||||
an interface is not a valid DI token because it is a TypeScript artifact that doesn't exist at run time.
|
||||
Use this abstract class interface to get the strong typing of an interface,
|
||||
and also use it as a provider token in the way you would a normal class.
|
||||
当你通过这种方式使用类时,它称作*类接口*。
|
||||
|
||||
As mentioned in [DI Providers](guide/dependency-injection-providers#interface-not-valid-token), an interface is not a valid DI token because it is a TypeScript artifact that doesn't exist at run time. Use this abstract class interface to get the strong typing of an interface, and also use it as a provider token in the way you would a normal class.
|
||||
|
||||
这种用法的类叫做*类-接口*。它关键的好处是:提供了接口的强类型,能像正常类一样***把它当做提供商令牌使用***。
|
||||
就像 [DI 提供商](guide/dependency-injection-providers#interface-not-valid-token)中提到的那样,接口不是有效的 DI 令牌,因为它是 TypeScript 自己用的,在运行期间不存在。使用这种抽象类接口不但可以获得像接口一样的强类型,而且可以像普通类一样把它用作提供商令牌。
|
||||
|
||||
A class interface should define *only* the members that its consumers are allowed to call.
|
||||
Such a narrowing interface helps decouple the concrete class from its consumers.
|
||||
|
||||
***类-接口***应该*只*定义允许它的消费者调用的成员。窄的接口有助于解耦该类的具体实现和它的消费者。
|
||||
类接口应该*只*定义允许它的消费者调用的成员。窄的接口有助于解耦该类的具体实现和它的消费者。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
|
@ -759,6 +869,10 @@ Using a class as an interface gives you the characteristics of an interface in a
|
|||
To minimize memory cost, however, the class should have *no implementation*.
|
||||
The `MinimalLogger` transpiles to this unoptimized, pre-minified JavaScript for a constructor function.
|
||||
|
||||
用类作为接口可以让你获得真实 JavaScript 对象中的接口的特性。
|
||||
但是,为了最小化内存开销,该类应该是*没有实现*的。
|
||||
对于构造函数,`MinimalLogger` 会转译成未优化过的、预先最小化过的 JavaScript。
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/minimal-logger.service.ts" region="minimal-logger-transpiled" header="dependency-injection-in-action/src/app/minimal-logger.service.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
|
@ -766,7 +880,7 @@ The `MinimalLogger` transpiles to this unoptimized, pre-minified JavaScript for
|
|||
Notice that it doesn't have any members. It never grows no matter how many members you add to the class,
|
||||
as long as those members are typed but not implemented. Look again at the TypeScript `MinimalLogger` class to confirm that it has no implementation.
|
||||
|
||||
注意,***只要不实现它***,不管添加多少成员,它永远不会增长大小。
|
||||
注意,***只要不实现它***,不管添加多少成员,它永远不会增长大小,因为这些成员虽然是有类型的,但却没有实现。你可以再看看 TypeScript 的 `MinimalLogger` 类,确定一下它是没有实现的。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -775,7 +889,7 @@ as long as those members are typed but not implemented. Look again at the TypeSc
|
|||
|
||||
### 'InjectionToken' objects
|
||||
|
||||
### _InjectionToken_ 值
|
||||
### 'InjectionToken' 对象
|
||||
|
||||
Dependency objects can be simple values like dates, numbers and strings, or
|
||||
shapeless objects like arrays and functions.
|
||||
|
@ -850,12 +964,14 @@ and displays them in the order they arrive from the database.
|
|||
|
||||
### Keep constructors simple
|
||||
|
||||
### 让构造函数保持简单
|
||||
|
||||
Constructors should do little more than initialize variables.
|
||||
This rule makes the component safe to construct under test without fear that it will do something dramatic like talk to the server.
|
||||
That's why you call the `HeroService` from within the `ngOnInit` rather than the constructor.
|
||||
|
||||
***让构造函数保持简单。***它们只应该用来初始化变量。
|
||||
这条规则用于在测试环境中放心的构造组件,以免在构造它们时,无意做了一些非常戏剧化的动作(比如与服务器进行会话)。
|
||||
构造函数应该只用来初始化变量。
|
||||
这条规则让组件在测试环境中可以放心地构造组件,以免在构造它们时,无意中做出一些非常戏剧化的动作(比如与服务器进行会话)。
|
||||
这就是为什么你要在 `ngOnInit` 里面调用 `HeroService`,而不是在构造函数中。
|
||||
|
||||
</div>
|
||||
|
@ -922,13 +1038,15 @@ Angular 的 `forwardRef()` 函数建立一个*间接地*引用,Angular 可以
|
|||
|
||||
The *Parent Finder* sample is full of circular class references that are impossible to break.
|
||||
|
||||
这个关于*父查找器*的例子中全都是没办法打破的循环类引用。
|
||||
|
||||
You face this dilemma when a class makes *a reference to itself*
|
||||
as does `AlexComponent` in its `providers` array.
|
||||
The `providers` array is a property of the `@Component()` decorator function which must
|
||||
appear *above* the class definition.
|
||||
|
||||
当一个类*需要引用自身*的时候,你面临同样的困境,就像在 `AlexComponent` 的 `provdiers` 数组中遇到的困境一样。
|
||||
该 `providers` 数组是一个 `@Component` 装饰器函数的一个属性,它必须在类定义*之前*出现。
|
||||
该 `providers` 数组是一个 `@Component()` 装饰器函数的一个属性,它必须在类定义*之前*出现。
|
||||
|
||||
Break the circularity with `forwardRef`.
|
||||
|
||||
|
|
|
@ -1,23 +1,37 @@
|
|||
# Dependency Injection in Angular
|
||||
|
||||
# Angular 中的依赖注入
|
||||
|
||||
Dependency injection (DI), is an important application design pattern.
|
||||
Angular has its own DI framework, which is typically
|
||||
used in the design of Angular applications to increase their efficiency and modularity.
|
||||
|
||||
依赖注入(DI)是一种重要的应用设计模式。
|
||||
Angular 有自己的 DI 框架,在设计应用时通常会用到它,以提升它们的开发效率和模块化程度。
|
||||
|
||||
Dependencies are services or objects that a class needs to perform its function.
|
||||
DI is a coding pattern in which a class asks for dependencies from external sources rather than creating them itself.
|
||||
|
||||
依赖,是当类需要执行其功能时,所需要的服务或对象。
|
||||
DI 是一种编码模式,其中的类会从外部源中请求获取依赖,而不是自己创建它们。
|
||||
|
||||
In Angular, the DI framework provides declared dependencies to a class when that class is instantiated. This guide explains how DI works in Angular, and how you use it to make your apps flexible, efficient, and robust, as well as testable and maintainable.
|
||||
|
||||
在 Angular 中,DI 框架会在实例化该类时向其提供这个类所声明的依赖项。本指南介绍了 DI 在 Angular 中的工作原理,以及如何借助它来让你的应用更灵活、高效、健壮,以及可测试、可维护。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
You can run the <live-example></live-example> of the sample app that accompanies this guide.
|
||||
|
||||
你可以运行本章这个范例应用的<live-example></live-example>。
|
||||
|
||||
</div>
|
||||
|
||||
Start by reviewing this simplified version of the _heroes_ feature
|
||||
from the [The Tour of Heroes](tutorial/). This simple version doesn't use DI; we'll walk through converting it to do so.
|
||||
|
||||
我们先看一下[英雄指南](tutorial/)中*英雄管理*特性的简化版。这个简化版不使用 DI,我们将逐步把它转换成使用 DI 的。
|
||||
|
||||
<code-tabs>
|
||||
<code-pane header="src/app/heroes/heroes.component.ts" path="dependency-injection/src/app/heroes/heroes.component.1.ts" region="v1">
|
||||
</code-pane>
|
||||
|
@ -36,9 +50,14 @@ from the [The Tour of Heroes](tutorial/). This simple version doesn't use DI; we
|
|||
`HeroesComponent` is the top-level heroes component.
|
||||
Its only purpose is to display `HeroListComponent`, which displays a list of hero names.
|
||||
|
||||
`HeroesComponent` 是顶级英雄管理组件。
|
||||
它唯一的目的是显示 `HeroListComponent`,该组件会显示一个英雄名字的列表。
|
||||
|
||||
This version of the `HeroListComponent` gets heroes from the `HEROES` array, an in-memory collection
|
||||
defined in a separate `mock-heroes` file.
|
||||
|
||||
`HeroListComponent` 的这个版本从 `HEROES` 数组(它通过一个独立的 `mock-heroes` 文件定义了一个内存集合)中获取英雄。
|
||||
|
||||
<code-example header="src/app/heroes/hero-list.component.ts (class)" path="dependency-injection/src/app/heroes/hero-list.component.1.ts" region="class">
|
||||
</code-example>
|
||||
|
||||
|
@ -48,39 +67,62 @@ you have to change the implementation of `HeroesListComponent` and
|
|||
replace every use of the `HEROES` mock data.
|
||||
|
||||
|
||||
这种方法在原型阶段有用,但是不够健壮、不利于维护。
|
||||
一旦你想要测试该组件或想从远程服务器获得英雄列表,就不得不修改 `HeroesListComponent` 的实现,并且替换每一处使用了 `HEROES` 模拟数据的地方。
|
||||
|
||||
## Create and register an injectable service
|
||||
|
||||
## 创建和注册可注入的服务
|
||||
|
||||
The DI framework lets you supply data to a component from an injectable _service_ class, defined in its own file. To demonstrate, we'll create an injectable service class that provides a list of heroes, and register that class as a provider of that service.
|
||||
|
||||
DI 框架让你能从一个可注入的*服务*类(独立文件)中为组件提供数据。为了演示,我们还会创建一个用来提供英雄列表的、可注入的服务类,并把它注册为该服务的提供商。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
Having multiple classes in the same file can be confusing. We generally recommend that you define components and services in separate files.
|
||||
|
||||
在同一个文件中放多个类容易让人困惑。我们通常建议你在单独的文件中定义组件和服务。
|
||||
|
||||
If you do combine a component and service in the same file,
|
||||
it is important to define the service first, and then the component. If you define the component before the service, you get a run-time null reference error.
|
||||
|
||||
如果你把组件和服务都放在同一个文件中,请务必先定义服务,然后再定义组件。如果在服务之前定义组件,则会在运行时收到一个空引用错误。
|
||||
|
||||
It is possible to 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()` 方法来先定义组件,就像[这个博客](http://blog.thoughtram.io/angular/2015/09/03/forward-references-in-angular-2.html)中解释的那样。
|
||||
|
||||
You can also use forward references to break circular dependencies.
|
||||
See an example in the [DI Cookbook](guide/dependency-injection-in-action#forwardref).
|
||||
|
||||
你还可以使用前向引用来打破循环依赖,参见 [DI 一章](guide/dependency-injection-in-action#forwardref)中的例子。
|
||||
|
||||
</div>
|
||||
|
||||
### Create an injectable service class
|
||||
|
||||
### 创建可注入的服务类
|
||||
|
||||
The [Angular CLI](cli) can generate a new `HeroService` class in the `src/app/heroes` folder with this command.
|
||||
|
||||
[Angular CLI](cli) 可以用下列命令在 `src/app/heroes` 目录下生成一个新的 `HeroService` 类。
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
ng generate service heroes/hero
|
||||
</code-example>
|
||||
|
||||
The command creates the following `HeroService` skeleton.
|
||||
|
||||
下列命令会创建 `HeroService` 的骨架。
|
||||
|
||||
<code-example path="dependency-injection/src/app/heroes/hero.service.0.ts" header="src/app/heroes/hero.service.ts (CLI-generated)">
|
||||
</code-example>
|
||||
|
||||
The `@Injectable()` is an essential ingredient in every Angular service definition. The rest of the class has been written to expose a `getHeroes` method that returns the same mock data as before. (A real app would probably get its data asynchronously from a remote server, but we'll ignore that to focus on the mechanics of injecting the service.)
|
||||
|
||||
`@Injectable()` 是每个 Angular 服务定义中的基本要素。该类的其余部分导出了一个 `getHeroes` 方法,它会返回像以前一样的模拟数据。(真实的应用可能会从远程服务器中异步获取这些数据,不过这里我们先忽略它,专心实现服务的注入机制。)
|
||||
|
||||
<code-example path="dependency-injection/src/app/heroes/hero.service.3.ts" header="src/app/heroes/hero.service.ts">
|
||||
</code-example>
|
||||
|
||||
|
@ -90,20 +132,33 @@ The `@Injectable()` is an essential ingredient in every Angular service definiti
|
|||
|
||||
### Configure an injector with a service provider
|
||||
|
||||
### 用服务提供商配置注入器
|
||||
|
||||
The class we have created provides a service. The `@Injectable()` decorator marks it as a service
|
||||
that can be injected, but Angular can't actually inject it anywhere until you configure
|
||||
an Angular [dependency injector](guide/glossary#injector) with a [provider](guide/glossary#provider) of that service.
|
||||
|
||||
我们创建的类提供了一个服务。`@Injectable()` 装饰器把它标记为可供注入的服务,不过在你使用该服务的 [provider](guide/glossary#provider) 提供商配置好 Angular 的[依赖注入器](guide/glossary#injector)之前,Angular 实际上无法将其注入到任何位置。
|
||||
|
||||
The injector is responsible for creating service instances and injecting them into classes like `HeroListComponent`.
|
||||
You rarely create an Angular injector yourself. Angular creates injectors for you as it executes the app, starting with the _root injector_ that it creates during the [bootstrap process](guide/bootstrapping).
|
||||
|
||||
该注入器负责创建服务实例,并把它们注入到像 `HeroListComponent` 这样的类中。
|
||||
你很少需要自己创建 Angular 的注入器。Angular 会在执行应用时为你创建注入器,第一个注入器是*根注入器*,创建于[启动过程](guide/bootstrapping)中。
|
||||
|
||||
A provider tells an injector _how to create the service_.
|
||||
You must configure an injector with a provider before that injector can create a service (or provide any other kind of dependency).
|
||||
|
||||
提供商会告诉注入器*如何创建该服务*。
|
||||
要想让注入器能够创建服务(或提供其它类型的依赖),你必须使用某个提供商配置好注入器。
|
||||
|
||||
A provider can be the service class itself, so that the injector can use `new` to create an instance.
|
||||
You might also define more than one class to provide the same service in different ways,
|
||||
and configure different injectors with different providers.
|
||||
|
||||
提供商可以是服务类本身,因此注入器可以使用 `new` 来创建实例。
|
||||
你还可以定义多个类,以不同的方式提供同一个服务,并使用不同的提供商来配置不同的注入器。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
Injectors are inherited, which means that if a given injector can't resolve a dependency,
|
||||
|
@ -112,30 +167,54 @@ A component can get services from its own injector,
|
|||
from the injectors of its component ancestors,
|
||||
from the injector of its parent NgModule, or from the `root` injector.
|
||||
|
||||
注入器是可继承的,这意味着如果指定的注入器无法解析某个依赖,它就会请求父注入器来解析它。
|
||||
组件可以从它自己的注入器来获取服务、从其祖先组件的注入器中获取、从其父 NgModule 的注入器中获取,或从 `root` 注入器中获取。
|
||||
|
||||
* Learn more about the [different kinds of providers](guide/dependency-injection-providers).
|
||||
|
||||
更多知识,参见 [提供商的不同类型](guide/dependency-injection-providers)。
|
||||
|
||||
* Learn more about how the [injector hierarchy](guide/hierarchical-dependency-injection) works.
|
||||
|
||||
更多知识,参见[层次化注入器](guide/hierarchical-dependency-injection)的工作原理。
|
||||
|
||||
</div>
|
||||
|
||||
You can configure injectors with providers at different levels of your app, by setting a metadata value in one of three places:
|
||||
|
||||
你可以用三种方式之一来设置元数据,以便在应用的不同层级使用提供商来配置各个注入器:
|
||||
|
||||
* In the `@Injectable()` decorator for the service itself.
|
||||
|
||||
在服务本身的 `@Injectable()` 装饰器中。
|
||||
|
||||
* In the `@NgModule()` decorator for an NgModule.
|
||||
|
||||
在 NgModule 的 `@NgModule()` 装饰器中。
|
||||
|
||||
* In the `@Component()` decorator for a component.
|
||||
|
||||
在组件的 `@Component()` 装饰器中。
|
||||
|
||||
The `@Injectable()` decorator has the `providedIn` metadata option, where you can specify the provider of the decorated service class with the `root` injector, or with the injector for a specific NgModule.
|
||||
|
||||
`@Injectable()` 装饰器具有一个名叫 `providedIn` 的元数据选项,在那里你可以指定把被装饰类的提供商放到 `root` 注入器中,或某个特定 NgModule 的注入器中。
|
||||
|
||||
The `@NgModule()` and `@Component()` decorators have the `providers` metadata option, where you can configure providers for NgModule-level or component-level injectors.
|
||||
|
||||
`@NgModule()` 和 `@Component()` 装饰器都有用一个 `providers` 元数据选项,在那里你可以配置 NgModule 级或组件级的注入器。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
Components are directives, and the `providers` option is inherited from `@Directive()`. You can also configure providers for directives and pipes at the same level as the component.
|
||||
|
||||
所有组件都是指令,而 `providers` 选项是从 `@Directive()` 中继承来的。
|
||||
你也可以与组件一样的级别为指令、管道配置提供商。
|
||||
|
||||
Learn more about [where to configure providers](guide/hierarchical-dependency-injection#where-to-register).
|
||||
|
||||
欲知详情,参见[该在哪里配置提供商](guide/hierarchical-dependency-injection#where-to-register)。
|
||||
|
||||
</div>
|
||||
|
||||
{@a injector-config}
|
||||
|
@ -143,10 +222,16 @@ Learn more about [where to configure providers](guide/hierarchical-dependency-in
|
|||
|
||||
## Injecting services
|
||||
|
||||
## 注入服务
|
||||
|
||||
In order for `HeroListComponent` to get heroes from `HeroService`, it needs to ask for `HeroService` to be injected, rather than creating it's own `HeroService` instance with `new`.
|
||||
|
||||
`HeroListComponent` 要想从 `HeroService` 中获取英雄列表,就得要求注入 `HeroService`,而不是自己使用 `new` 来创建自己的 `HeroService` 实例。
|
||||
|
||||
You can tell Angular to inject a dependency in a component's constructor by specifying a **constructor parameter with the dependency type**. Here's the `HeroListComponent` constructor, asking for the `HeroService` to be injected.
|
||||
|
||||
你可以通过制定**带有依赖类型的构造函数参数**来要求 Angular 在组件的构造函数中注入依赖项。下面的代码是 `HeroListComponent` 的构造函数,它要求注入 `HeroService`。
|
||||
|
||||
<code-example header="src/app/heroes/hero-list.component (constructor signature)" path="dependency-injection/src/app/heroes/hero-list.component.ts"
|
||||
region="ctor-signature">
|
||||
</code-example>
|
||||
|
@ -154,6 +239,9 @@ region="ctor-signature">
|
|||
Of course, `HeroListComponent` should do something with the injected `HeroService`.
|
||||
Here's the revised component, making use of the injected service, side-by-side with the previous version for comparison.
|
||||
|
||||
当然,`HeroListComponent` 还应该使用注入的这个 `HeroService` 做一些事情。
|
||||
这里是修改过的组件,它转而使用注入的服务。与前一版本并列显示,以便比较。
|
||||
|
||||
<code-tabs>
|
||||
<code-pane header="hero-list.component (with DI)" path="dependency-injection/src/app/heroes/hero-list.component.2.ts">
|
||||
</code-pane>
|
||||
|
@ -165,38 +253,67 @@ Here's the revised component, making use of the injected service, side-by-side w
|
|||
`HeroService` must provided in some parent injector. The code in `HeroListComponent` doesn't depend on where `HeroService` comes from.
|
||||
If you decided to provide `HeroService` in `AppModule`, `HeroListComponent` wouldn't change.
|
||||
|
||||
必须在某些父注入器中提供 `HeroService`。`HeroListComponent` 并不关心 `HeroService` 来自哪里。
|
||||
如果你决定在 `AppModule` 中提供 `HeroService`,也不必修改 `HeroListComponent`。
|
||||
|
||||
{@a singleton-services}
|
||||
{@a component-child-injectors}
|
||||
|
||||
### Injector hierarchy and service instances
|
||||
|
||||
### 注入器树与服务实例
|
||||
|
||||
Services are singletons _within the scope of an injector_. That is, there is at most one instance of a service in a given injector.
|
||||
|
||||
*在某个注入器*的范围内,服务是单例的。也就是说,在指定的注入器中最多只有某个服务的最多一个实例。
|
||||
|
||||
There is only one root injector for an app. Providing `UserService` at the `root` or `AppModule` level means it is registered with the root injector. There is just one `UserService` instance in the entire app and every class that injects `UserService` gets this service instance _unless_ you configure another provider with a _child injector_.
|
||||
|
||||
应用只有一个根注入器。在 `root` 或 `AppModule` 级提供 `UserService` 意味着它注册到了根注入器上。
|
||||
在整个应用中只有一个 `UserService` 实例,每个要求注入 `UserService` 的类都会得到这一个服务实例,*除非*你在*子注入器*中配置了另一个提供商。
|
||||
|
||||
Angular DI has a [hierarchical injection system](guide/hierarchical-dependency-injection), which means that nested injectors can create their own service instances.
|
||||
Angular regularly creates nested injectors. Whenever Angular creates a new instance of a component that has `providers` specified in `@Component()`, it also creates a new _child injector_ for that instance.
|
||||
Similarly, when a new NgModule is lazy-loaded at run time, Angular can create an injector for it with its own providers.
|
||||
|
||||
Angular DI 具有[分层注入体系](guide/hierarchical-dependency-injection),这意味着下级注入器也可以创建它们自己的服务实例。
|
||||
Angular 会有规律的创建下级注入器。每当 Angular 创建一个在 `@Component()` 中指定了 `providers` 的组件实例时,它也会为该实例创建一个新的*子注入器*。
|
||||
类似的,当在运行期间加载一个新的 NgModule 时,Angular 也可以为它创建一个拥有自己的提供商的注入器。
|
||||
|
||||
Child modules and component injectors are independent of each other, and create their own separate instances of the provided services. When Angular destroys an NgModule or component instance, it also destroys that injector and that injector's service instances.
|
||||
|
||||
子模块和组件注入器彼此独立,并且会为所提供的服务分别创建自己的实例。当 Angular 销毁 NgModule 或组件实例时,也会销毁这些注入器以及注入器中的那些服务实例。
|
||||
|
||||
Thanks to [injector inheritance](guide/hierarchical-dependency-injection),
|
||||
you can still inject application-wide services into these components.
|
||||
A component's injector is a child of its parent component's injector,
|
||||
and a descendent of its parent's parent's injector, and so on all the way back to the application's _root_ injector. Angular can inject a service provided by any injector in that lineage.
|
||||
|
||||
借助[注入器继承机制](guide/hierarchical-dependency-injection),你仍然可以把全应用级的服务注入到这些组件中。
|
||||
组件的注入器是其父组件注入器的子节点,也是其父节点的父节点的后代,以此类推,直到应用的*根*注入器为止。
|
||||
Angular 可以注入该继承谱系中任何一个注入器提供的服务。
|
||||
|
||||
For example, Angular can inject `HeroListComponent` with both the `HeroService` provided in `HeroComponent` and the `UserService` provided in `AppModule`.
|
||||
|
||||
比如,Angular 既可以把 `HeroComponent` 中提供的 `HeroService` 注入到 `HeroListComponent`,也可以注入 `AppModule` 中提供的 `UserService`。
|
||||
|
||||
{@a testing-the-component}
|
||||
|
||||
## Testing components with dependencies
|
||||
|
||||
## 测试带有依赖的组件
|
||||
|
||||
Designing a class with dependency injection makes the class easier to test.
|
||||
Listing dependencies as constructor parameters may be all you need to test application parts effectively.
|
||||
|
||||
基于依赖注入设计一个类,能让它更易于测试。
|
||||
要想高效的测试应用的各个部分,你所要做的一切就是把这些依赖列到构造函数的参数表中而已。
|
||||
|
||||
For example, you can create a new `HeroListComponent` with a mock service that you can manipulate
|
||||
under test.
|
||||
|
||||
比如,你可以使用一个可在测试期间操纵的模拟服务来创建新的 `HeroListComponent`。
|
||||
|
||||
<code-example path="dependency-injection/src/app/test.component.ts" region="spec" header="src/app/test.component.ts" linenums="false">
|
||||
</code-example>
|
||||
|
||||
|
@ -204,17 +321,25 @@ under test.
|
|||
|
||||
Learn more in the [Testing](guide/testing) guide.
|
||||
|
||||
欲知详情,参见[测试](guide/testing)一章。
|
||||
|
||||
</div>
|
||||
|
||||
{@a service-needs-service}
|
||||
|
||||
## Services that need other services
|
||||
|
||||
## 那些需要其它服务的服务
|
||||
|
||||
Service can have their own dependencies. `HeroService` is very simple and doesn't have any dependencies of its own. Suppose, however, that you want it to report its activities through a logging service. You can apply the same *constructor injection* pattern,
|
||||
adding a constructor that takes a `Logger` parameter.
|
||||
|
||||
服务还可以具有自己的依赖。`HeroService` 非常简单,没有自己的依赖。不过,如果你希望通过日志服务来报告这些活动,那么就可以使用同样的*构造函数注入*模式,添加一个构造函数来接收一个 `Logger` 参数。
|
||||
|
||||
Here is the revised `HeroService` that injects `Logger`, side by side with the previous service for comparison.
|
||||
|
||||
这是修改后的 `HeroService`,它注入了 `Logger`,我们把它和前一个版本的服务放在一起进行对比。
|
||||
|
||||
<code-tabs>
|
||||
|
||||
<code-pane header="src/app/heroes/hero.service (v2)" path="dependency-injection/src/app/heroes/hero.service.2.ts">
|
||||
|
@ -231,19 +356,33 @@ Here is the revised `HeroService` that injects `Logger`, side by side with the p
|
|||
|
||||
The constructor asks for an injected instance of `Logger` and stores it in a private field called `logger`. The `getHeroes()` method logs a message when asked to fetch heroes.
|
||||
|
||||
该构造函数请求注入一个 `Logger` 的实例,并把它保存在一个名叫 `logger` 的私有字段中。
|
||||
当要求获取英雄列表时,`getHeroes()` 方法就会记录一条消息。
|
||||
|
||||
Notice that the `Logger` service also has the `@Injectable()` decorator, even though it might not need its own dependencies. In fact, the `@Injectable()` decorator is **required for all services**.
|
||||
|
||||
注意,虽然 `Logger` 服务没有自己的依赖项,但是它同样带有 `@Injectable()` 装饰器。实际上,`@Injectable()` **对所有服务都是必须的**。
|
||||
|
||||
When Angular creates a class whose constructor has parameters, it looks for type and injection metadata about those parameters so that it can inject the correct service.
|
||||
If Angular can't find that parameter information, it throws an error.
|
||||
Angular can only find the parameter information _if the class has a decorator of some kind_.
|
||||
The `@Injectable()` decorator is the standard decorator for service classes.
|
||||
|
||||
当 Angular 创建一个构造函数中有参数的类时,它会查找有关这些参数的类型,和供注入使用的元数据,以便找到正确的服务。
|
||||
如果 Angular 无法找到参数信息,它就会抛出一个错误。
|
||||
*只有当类具有某种装饰器时*,Angular 才能找到参数信息。
|
||||
`@Injectable()` 装饰器是所有服务类的标准装饰器。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
The decorator requirement is imposed by TypeScript. TypeScript normally discards parameter type information when it [transpiles](guide/glossary#transpile) the code to JavaScript. TypeScript preserves this information if the class has a decorator and the `emitDecoratorMetadata` compiler option is set `true` in TypeScript's `tsconfig.json` configuration file. The CLI configures `tsconfig.json` with `emitDecoratorMetadata: true`.
|
||||
|
||||
对装饰器的需求是 TypeScript 强制要求的。当 TypeScript 把代码[转译](guide/glossary#transpile)成 JavaScript 时,一般会丢弃参数的类型信息。只有当类具有装饰器,并且 `tsconfig.json` 中的编译器选项 `emitDecoratorMetadata` 为 `true` 时,TypeScript 才会保留这些信息。CLI 所配置的 `tsconfig.json` 就带有 `emitDecoratorMetadata: true`。
|
||||
|
||||
This means you're responsible for putting `@Injectable()` on your service classes.
|
||||
|
||||
这意味着你有责任给所有服务类加上 `@Injectable()`。
|
||||
|
||||
</div>
|
||||
|
||||
{@a token}
|
||||
|
@ -252,14 +391,22 @@ The `@Injectable()` decorator is the standard decorator for service classes.
|
|||
|
||||
### Dependency injection tokens
|
||||
|
||||
### 依赖注入令牌
|
||||
|
||||
When you configure an injector with a provider, you associate that provider with a [DI token](guide/glossary#di-token).
|
||||
The injector maintains an internal *token-provider* map that it references when
|
||||
asked for a dependency. The token is the key to the map.
|
||||
|
||||
当使用提供商配置注入器时,就会把提供商和一个 [DI 令牌](guide/glossary#di-token)关联起来。
|
||||
注入器维护一个内部*令牌-提供商*的映射表,当请求一个依赖项时就会引用它。令牌就是这个映射表的键。
|
||||
|
||||
In simple examples, the dependency value is an *instance*, and
|
||||
the class *type* serves as its own lookup key.
|
||||
Here you get a `HeroService` directly from the injector by supplying the `HeroService` type as the token:
|
||||
|
||||
在简单的例子中,依赖项的值是一个*实例*,而类的*类型*则充当键来查阅它。
|
||||
通过把 `HeroService` 类型作为令牌,你可以直接从注入器中获得一个 `HeroService` 实例。
|
||||
|
||||
<code-example path="dependency-injection/src/app/injector.component.ts" region="get-hero-service" header="src/app/injector.component.ts" linenums="false">
|
||||
</code-example>
|
||||
|
||||
|
@ -267,24 +414,38 @@ The behavior is similar when you write a constructor that requires an injected c
|
|||
When you define a constructor parameter with the `HeroService` class type,
|
||||
Angular knows to inject the service associated with that `HeroService` class token:
|
||||
|
||||
当你编写的构造函数中需要注入基于类的依赖项时,其行为也类似。
|
||||
当你使用 `HeroService` 类的类型来定义构造函数参数时,Angular 就会知道要注入与 `HeroService` 类这个令牌相关的服务。
|
||||
|
||||
<code-example path="dependency-injection/src/app/heroes/hero-list.component.ts" region="ctor-signature" header="src/app/heroes/hero-list.component.ts">
|
||||
</code-example>
|
||||
|
||||
Many dependency values are provided by classes, but not all. The expanded *provide* object lets you associate different kinds of providers with a DI token.
|
||||
|
||||
很多依赖项的值都是通过类来提供的,但不是全部。扩展的 *provide* 对象让你可以把多种不同种类的提供商和 DI 令牌关联起来。
|
||||
|
||||
* Learn more about [different kinds of providers](guide/dependency-injection-providers).
|
||||
|
||||
欲知详情,参见[不同种类的提供商](guide/dependency-injection-providers)。
|
||||
|
||||
{@a optional}
|
||||
|
||||
### Optional dependencies
|
||||
|
||||
### 可选依赖
|
||||
|
||||
`HeroService` *requires* a logger, but what if it could get by without
|
||||
one?
|
||||
|
||||
`HeroService` *需要*一个记录器,但是如果找不到它会怎么样?
|
||||
|
||||
When a component or service declares a dependency, the class constructor takes that dependency as a parameter.
|
||||
You can tell Angular that the dependency is optional by annotating the
|
||||
constructor parameter with `@Optional()`.
|
||||
|
||||
当组件或服务声明某个依赖项时,该类的构造函数会以参数的形式接收那个依赖项。
|
||||
通过给这个参数加上 `@Optional()` 注解,你可以告诉 Angular,该依赖是可选的。
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="import-optional">
|
||||
</code-example>
|
||||
|
||||
|
@ -295,28 +456,45 @@ When using `@Optional()`, your code must be prepared for a null value. If you
|
|||
don't register a logger provider anywhere, the injector sets the
|
||||
value of `logger` to null.
|
||||
|
||||
当使用 `@Optional()` 时,你的代码必须能正确处理 null 值。如果你没有在任何地方注册过 logger 提供商,那么注入器就会把 `logger` 的值设置为 null。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
`@Inject()` and `@Optional()` are _parameter decorators_. They alter the way the DI framework provides a dependency, by annotating the dependency parameter on the constructor of the class that requires the dependency.
|
||||
|
||||
`@Inject()` 和 `@Optional()` 都是*参数装饰器*。它们通过在需要依赖项的类的构造函数上对参数进行注解,来改变 DI 框架提供依赖项的方式。
|
||||
|
||||
Learn more about parameter decorators in [Hierarchical Dependency Injectors](guide/hierarchical-dependency-injection).
|
||||
|
||||
欲知详情,参见[多级注入器](guide/hierarchical-dependency-injection)。
|
||||
|
||||
</div>
|
||||
|
||||
## Summary
|
||||
|
||||
## 小结
|
||||
|
||||
You learned the basics of Angular dependency injection in this page.
|
||||
You can register various kinds of providers,
|
||||
and you know how to ask for an injected object (such as a service) by
|
||||
adding a parameter to a constructor.
|
||||
|
||||
本页中你学到了 Angular 依赖注入的基础知识。
|
||||
你可以注册多种提供商,并且知道了如何通过为构造函数添加参数来请求所注入的对象(比如服务)。
|
||||
|
||||
Dive deeper into the capabilities and advanced feature of the Angular DI system in the following pages:
|
||||
|
||||
在以下页面中可以深入了解 Angular DI 体系的能力及高级特性:
|
||||
|
||||
* Learn more about nested injectors in
|
||||
[Hierarchical Dependency Injection](guide/hierarchical-dependency-injection).
|
||||
|
||||
要深入了解嵌套注入器,参见[多级依赖注入](guide/hierarchical-dependency-injection)
|
||||
|
||||
* Learn more about [DI tokens and providers](guide/dependency-injection-providers).
|
||||
|
||||
到 [DI 令牌与提供商](guide/dependency-injection-providers)中学习更多知识。
|
||||
|
||||
* [Dependency Injection in Action](guide/dependency-injection-in-action) is a cookbook for some of the interesting things you can do with DI.
|
||||
|
||||
|
||||
[依赖注入实战](guide/dependency-injection-in-action)中讲了一些你能用 DI 做的一些有意思的事。
|
||||
|
|
|
@ -350,114 +350,192 @@ Read about how to enable CORS for specific servers at
|
|||
|
||||
## Optimize for production
|
||||
|
||||
## 为生产环境优化
|
||||
|
||||
Although deploying directly from the development environment works,
|
||||
you can generate an optimized build with additional CLI command line flags,
|
||||
starting with `--prod`.
|
||||
|
||||
虽然也可以直接用开发环境部署,但也可以使用其它的 CLI 命令行标志来生成优化过的构建成果,我们先从 `--prod` 开始讲。
|
||||
|
||||
### Build with _--prod_
|
||||
|
||||
### 使用*--prod*构建
|
||||
|
||||
<code-example language="none" class="code-shell">
|
||||
ng build --prod
|
||||
</code-example>
|
||||
|
||||
The `--prod` _meta-flag_ engages the following optimization features.
|
||||
|
||||
`--prod` 标志具有如下优化特性。
|
||||
|
||||
* [Ahead-of-Time (AOT) Compilation](guide/aot-compiler): pre-compiles Angular component templates.
|
||||
|
||||
[预先(AOT)编译](guide/aot-compiler):预编译 Angular 的组件模板。
|
||||
|
||||
* [Production mode](#enable-prod-mode): deploys the production environment which enables _production mode_.
|
||||
|
||||
[生产模式](#enable-prod-mode):部署到启用了*生产模式*的生产环境。
|
||||
|
||||
* Bundling: concatenates your many application and library files into a few bundles.
|
||||
|
||||
打包:把你的多个应用于库文件拼接到少量包(bundle)中。
|
||||
|
||||
* Minification: removes excess whitespace, comments, and optional tokens.
|
||||
|
||||
最小化:删除多余的空格、注释和可选令牌。
|
||||
|
||||
* Uglification: rewrites code to use short, cryptic variable and function names.
|
||||
|
||||
混淆/丑化:重写代码,使用简短的、不容易理解的变量名和函数名。
|
||||
|
||||
* Dead code elimination: removes unreferenced modules and much unused code.
|
||||
|
||||
消除死代码:删除未引用过的模块和很多未用到的代码。
|
||||
|
||||
The remaining [copy deployment steps](#copy-files) are the same as before.
|
||||
|
||||
其余的[复制等部署步骤](#copy-files)步骤和以前的一样。
|
||||
|
||||
See [`ng build`](cli/build) for more about CLI build options and what they do.
|
||||
|
||||
要了解关于 CLI 构建选项及其作用的更多知识,参见 [`ng build`](cli/build)。
|
||||
|
||||
{@a enable-prod-mode}
|
||||
|
||||
### Enable production mode
|
||||
|
||||
### 启用生产模式
|
||||
|
||||
Angular apps run in development mode by default, as you can see by the following message on the browser
|
||||
console:
|
||||
|
||||
Angular 应用默认运行在开发模式下,你可以在浏览器的控制台中看到如下信息:
|
||||
|
||||
<code-example format="nocode">
|
||||
Angular is running in the development mode. Call enableProdMode() to enable the production mode.
|
||||
</code-example>
|
||||
|
||||
Switching to _production mode_ can make it run faster by disabling development specific checks such as the dual change detection cycles.
|
||||
|
||||
切换到*生产模式*可以通过禁用开发阶段特有的检查(比如双重变更检测周期)来让它运行得更快。
|
||||
|
||||
Building for production (or appending the `--environment=prod` flag) enables _production mode_
|
||||
Look at the CLI-generated `main.ts` to see how this works.
|
||||
|
||||
为生产环境构建(添加 `--environment=prod` 标识)可以启用*生产模式*。
|
||||
阅读 CLI 生成的 `main.ts` 以了解它的工作原理。
|
||||
|
||||
{@a lazy-loading}
|
||||
|
||||
### Lazy loading
|
||||
|
||||
### 惰性加载
|
||||
|
||||
You can dramatically reduce launch time by only loading the application modules that
|
||||
absolutely must be present when the app starts.
|
||||
|
||||
通过只加载应用启动时绝对必须的那些模块,你可以戏剧性的缩短应用启动时间。
|
||||
|
||||
Configure the Angular Router to defer loading of all other modules (and their associated code), either by
|
||||
[waiting until the app has launched](guide/router#preloading "Preloading")
|
||||
or by [_lazy loading_](guide/router#asynchronous-routing "Lazy loading")
|
||||
them on demand.
|
||||
|
||||
可以配置 Angular 的路由器,来推迟所有其它模块(及其相关代码)的加载时机,方法有[一直等到应用启动完毕](guide/router#preloading "Preloading"),或者当用到时才按需[*惰性加载*](guide/router#asynchronous-routing "Lazy loading")。
|
||||
|
||||
<div class="alert is-helpful>
|
||||
|
||||
#### Don't eagerly import something from a lazy-loaded module
|
||||
|
||||
#### 不要急性(eagerly)导入来自惰性加载模块中的任何东西
|
||||
|
||||
If you mean to lazy-load a module, be careful not import it
|
||||
in a file that's eagerly loaded when the app starts (such as the root `AppModule`).
|
||||
If you do that, the module will be loaded immediately.
|
||||
|
||||
如果要惰性加载某个模块,就要小心别在应用启动时要急性加载的模块(比如根模块 `AppModule`)中导入它。
|
||||
如果那么做,该模块就会立刻加载起来。
|
||||
|
||||
The bundling configuration must take lazy loading into consideration.
|
||||
Because lazy-loaded modules aren't imported in JavaScript, bundlers exclude them by default.
|
||||
Bundlers don't know about the router configuration and can't create separate bundles for lazy-loaded modules.
|
||||
You would have to create these bundles manually.
|
||||
|
||||
配置打包方式时必须考虑惰性加载。
|
||||
因为默认情况下惰性加载的模块没有在 JavaScript 中导入过,因此打包器默认会排除它们。
|
||||
打包器不认识路由器配置,也就不能为惰性加载的模块创建独立的包。
|
||||
你必须手动创建这些包。
|
||||
|
||||
The CLI runs the
|
||||
[Angular Ahead-of-Time Webpack Plugin](https://github.com/angular/angular-cli/tree/master/packages/%40ngtools/webpack)
|
||||
which automatically recognizes lazy-loaded `NgModules` and creates separate bundles for them.
|
||||
|
||||
CLI 会运行 [Angular Ahead-of-Time Webpack 插件](https://github.com/angular/angular-cli/tree/master/packages/%40ngtools/webpack),它会自动识别出惰性加载的 `NgModules`,并为它们创建独立的包。
|
||||
|
||||
</div>
|
||||
|
||||
{@a measure}
|
||||
|
||||
### Measure performance
|
||||
|
||||
### 测量性能
|
||||
|
||||
You can make better decisions about what to optimize and how when you have a clear and accurate understanding of
|
||||
what's making the application slow.
|
||||
The cause may not be what you think it is.
|
||||
You can waste a lot of time and money optimizing something that has no tangible benefit or even makes the app slower.
|
||||
You should measure the app's actual behavior when running in the environments that are important to you.
|
||||
|
||||
如果你对哪些东西拖慢了应用有更加清晰、精确的了解,就可以更好地决定优化什么以及如何优化。
|
||||
慢的原因可能和你所想的不一样。
|
||||
你可能花费了大量的时间和金钱来优化一些实际上无关紧要的东西,甚至可能让应用变得更慢。
|
||||
你应该测量应用在运行环境中的实际行为,这才是最重要的。
|
||||
|
||||
The
|
||||
<a href="https://developers.google.com/web/tools/chrome-devtools/network-performance/understanding-resource-timing" title="Chrome DevTools Network Performance">
|
||||
Chrome DevTools Network Performance page</a> is a good place to start learning about measuring performance.
|
||||
|
||||
<a href="https://developers.google.com/web/tools/chrome-devtools/network-performance/understanding-resource-timing" title="Chrome DevTools Network Performance">
|
||||
Chrome DevTools 的网络和性能页</a>是你开始学习如何测量性能的好地方。
|
||||
|
||||
The [WebPageTest](https://www.webpagetest.org/) tool is another good choice
|
||||
that can also help verify that your deployment was successful.
|
||||
|
||||
[WebPageTest](https://www.webpagetest.org/)工具是另一个不错的选择,它还能帮你验证这次部署是否成功。
|
||||
|
||||
{@a inspect-bundle}
|
||||
|
||||
### Inspect the bundles
|
||||
|
||||
### 检查发布包
|
||||
|
||||
The <a href="https://github.com/danvk/source-map-explorer/blob/master/README.md">source-map-explorer</a>
|
||||
tool is a great way to inspect the generated JavaScript bundles after a production build.
|
||||
|
||||
<a href="https://github.com/danvk/source-map-explorer/blob/master/README.md">source-map-explorer</a> 工具可以帮你在生产环境构建之后探查 JavaScript 包。
|
||||
|
||||
Install `source-map-explorer`:
|
||||
|
||||
安装 `source-map-explorer`:
|
||||
|
||||
<code-example language="none" class="code-shell">
|
||||
npm install source-map-explorer --save-dev
|
||||
</code-example>
|
||||
|
||||
Build your app for production _including the source maps_
|
||||
|
||||
为生产环境构建应用,包括源码映射表(source map)
|
||||
|
||||
<code-example language="none" class="code-shell">
|
||||
ng build --prod --source-map
|
||||
</code-example>
|
||||
|
||||
List the generated bundles in the `dist/` folder.
|
||||
|
||||
在 `dist/` 目录下列出生成的包。
|
||||
|
||||
<code-example language="none" class="code-shell">
|
||||
ls dist/*.bundle.js
|
||||
</code-example>
|
||||
|
@ -465,6 +543,9 @@ List the generated bundles in the `dist/` folder.
|
|||
Run the explorer to generate a graphical representation of one of the bundles.
|
||||
The following example displays the graph for the _main_ bundle.
|
||||
|
||||
运行浏览器来生成其中一个包的图形化表示。
|
||||
下面的例子展示了 `main` 包的图表。
|
||||
|
||||
<code-example language="none" class="code-shell">
|
||||
node_modules/.bin/source-map-explorer dist/main.*.bundle.js
|
||||
</code-example>
|
||||
|
@ -472,8 +553,12 @@ The following example displays the graph for the _main_ bundle.
|
|||
The `source-map-explorer` analyzes the source map generated with the bundle and draws a map of all dependencies,
|
||||
showing exactly which classes are included in the bundle.
|
||||
|
||||
`source-map-explorer` 会分析与包一期生成的 source map,并画出所有依赖的地图,精确展示哪些类包含在哪个包中。
|
||||
|
||||
Here's the output for the _main_ bundle of the QuickStart.
|
||||
|
||||
下面是 "快速上手" 应用中 `main` 包的输出。
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/cli-quickstart/quickstart-sourcemap-explorer.png" alt="quickstart sourcemap explorer">
|
||||
</figure>
|
||||
|
@ -482,49 +567,82 @@ Here's the output for the _main_ bundle of the QuickStart.
|
|||
|
||||
## The `base` tag
|
||||
|
||||
## `base` 标签
|
||||
|
||||
The HTML [_<base href="..."/>_](/guide/router)
|
||||
specifies a base path for resolving relative URLs to assets such as images, scripts, and style sheets.
|
||||
For example, given the `<base href="/my/app/">`, the browser resolves a URL such as `some/place/foo.jpg`
|
||||
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="..."/>_](/guide/router) 标签指定了用于解析静态文件(如图片、脚本和样式表)相对地址的基地址。
|
||||
比如,对于 `<base href="/my/app/">`,浏览器就会把 `some/place/foo.jpg` 这样的 URL 解析成到 `my/app/some/place/foo.jpg` 的请求。
|
||||
在导航期间,Angular 路由器使用 *base href* 作为到组件模板文件和模块文件的基地址。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
See also the [*APP_BASE_HREF*](api/common/APP_BASE_HREF "API: APP_BASE_HREF") alternative.
|
||||
|
||||
另一种方式参见 [*APP_BASE_HREF*](api/common/APP_BASE_HREF "API: APP_BASE_HREF")。
|
||||
|
||||
</div>
|
||||
|
||||
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="/">`,因为 `/` 就是该应用的根路径。
|
||||
|
||||
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`.
|
||||
|
||||
但是在共享或生产服务器上,你可能会在子目录下启动服务器。
|
||||
比如,当前应用的加载地址可能类似于 `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.
|
||||
|
||||
这里如果不配置 `base` 标签,应用就会失败,并在浏览器的控制台中为缺失的文件显示一个 `404 - Not Found` 错误。看看它*试图*从哪里去查找那些文件,并据此调整 base 标签。
|
||||
|
||||
## Building and serving for deployment
|
||||
|
||||
## 为部署而构建和启动服务器
|
||||
|
||||
When you are designing and developing applications, you typically use `ng serve` to build your app for fast, local, iterative development.
|
||||
When you are ready to deploy, however, you must use the `ng build` command to build the app and deploy the build artifacts elsewhere.
|
||||
|
||||
在设计和开发应用程序时,通常使用 `ng serve` 来构建应用,已进行快速的、本地的、迭代式的开发。
|
||||
不过,当准备部署时,你必须使用 `ng build` 命令来构建应用,并在别处部署构建成果。
|
||||
|
||||
Both `ng build` and `ng serve` clear the output folder before they build the project, but only the `ng build` command writes the generated build artifacts to the output folder.
|
||||
|
||||
在构建之前,`ng build` 和 `ng serve` 都会清空输出目录,但是只有 `ng build` 命令才会把生成的构建成果写入到输出目录下。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
The output folder is `dist/` by default.
|
||||
To output to a different folder, change the `outputPath` in `angular.json`.
|
||||
|
||||
输出目录默认为 `dist/`。
|
||||
要想输出到其它目录,请修改 `angular.json` 中的 `outputPath`。
|
||||
|
||||
</div>
|
||||
|
||||
The `ng serve` command builds, watches, and serves the application from local memory, using a local development server.
|
||||
When you have deployed your app to another server, however, you might still want to serve the app so that you can continue to see changes that you make in it.
|
||||
You can do this by adding the `--watch` option to the `ng build` command.
|
||||
|
||||
`ng serve` 命令会构建、监视并使用本地开发服务器从内存中提供网站服务。
|
||||
但是,当你将应用部署到其它服务器时,你可能希望仍然能持续看到你对该应用所做的修改。这时候,你可以为 `ng build` 命令添加 `--watch` 选项来做到这一点。
|
||||
|
||||
```
|
||||
ng build --watch
|
||||
```
|
||||
Like the `ng serve` command, this regenerates output files when source files change.
|
||||
|
||||
像 `ng serve` 命令一样,当源码文件发生变化时,它会重新生成输出文件。
|
||||
|
||||
For complete details of the CLI commands, see the [CLI command reference](cli).
|
||||
|
||||
要了解 CLI 命令的详细信息,参见 [CLI 命令参考手册](cli)。
|
|
@ -170,7 +170,7 @@ In either style, the template data bindings have the same access to the componen
|
|||
|
||||
By default, the Angular CLI command [`ng generate component`](cli/generate) generates components with a template file. You can override that with:
|
||||
|
||||
默认情况下,Angular CLI 生成组件时会带有模板文件,你可以通过参数覆盖它:
|
||||
默认情况下,Angular CLI 命令 [`ng generate component`](cli/generate) 在生成组件时会带有模板文件,你可以通过参数来覆盖它:
|
||||
|
||||
<code-example hideCopy language="sh" class="code-shell">
|
||||
ng generate component hero -it
|
||||
|
|
|
@ -291,7 +291,7 @@ Using an Angular custom element makes the process much simpler and more transpar
|
|||
|
||||
The Popup Service example app (shown below) defines a component that you can either load dynamically or convert to a custom element.
|
||||
|
||||
这个弹窗服务的范例应用定义了一个组件,你可以动态加载它也可以把它转换成自定义组件。
|
||||
这个弹窗服务的范例应用(见后面)定义了一个组件,你可以动态加载它也可以把它转换成自定义组件。
|
||||
|
||||
- `popup.component.ts` defines a simple pop-up element that displays an input message, with some animation and styling.
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ module using the CLI by entering the following command in the
|
|||
root project directory. Replace `CustomerDashboard` with the
|
||||
name of your module. You can omit the "Module" suffix from the name because the CLI appends it:
|
||||
|
||||
如果你已经有了 CLI 生成的应用,可以在项目的根目录下输入下面的命令来创建特性模块。把这里的 `CustomerDashboard` 替换成你的模块名。你可以从名字中省略掉“Module”后缀,因为 CLI 会自动追加上它:
|
||||
如果你已经有了 [Angular CLI](cli) 生成的应用,可以在项目的根目录下输入下面的命令来创建特性模块。把这里的 `CustomerDashboard` 替换成你的模块名。你可以从名字中省略掉“Module”后缀,因为 CLI 会自动追加上它:
|
||||
|
||||
```sh
|
||||
|
||||
|
|
|
@ -153,6 +153,7 @@ Note that:
|
|||
* As these validators are all sync validators, you pass them in as the second argument.
|
||||
|
||||
由于这些验证器都是同步验证器,因此你要把它们作为第二个参数传进去。
|
||||
|
||||
* Support multiple validators by passing the functions in as an array.
|
||||
|
||||
可以通过把这些函数放进一个数组后传进去,可以支持多重验证器。
|
||||
|
@ -324,6 +325,7 @@ set the color of each form control's border.
|
|||
## Cross field validation
|
||||
|
||||
## 跨字段交叉验证
|
||||
|
||||
This section shows how to perform cross field validation. It assumes some basic knowledge of creating custom validators.
|
||||
|
||||
本节将展示如何进行跨字段验证。这里假设你已经有了创建自定义验证器所需的基础知识。
|
||||
|
@ -405,6 +407,7 @@ Note that we check if:
|
|||
- the `FormGroup` has the cross validation error returned by the `identityRevealed` validator,
|
||||
|
||||
`FormGroup` 应该有一个由 `identityRevealed` 验证器返回的交叉验证错误对象。
|
||||
|
||||
- the user is yet to [interact](guide/form-validation#why-check-dirty-and-touched) with the form.
|
||||
|
||||
用户已经和表单进行过[交互](guide/form-validation#why-check-dirty-and-touched)。
|
||||
|
@ -441,6 +444,7 @@ Note that we check if:
|
|||
- the form has the cross validation error returned by the `identityRevealed` validator,
|
||||
|
||||
该表单具有一个由 `identityRevealed` 验证器提供的交叉验证错误对象。
|
||||
|
||||
- the user is yet to [interact](guide/form-validation#why-check-dirty-and-touched) with the form.
|
||||
|
||||
用户已经和表单进行过[交互](guide/form-validation#why-check-dirty-and-touched)。
|
||||
|
@ -452,6 +456,7 @@ This completes the cross validation example. We managed to:
|
|||
- validate the form based on the values of two sibling controls,
|
||||
|
||||
基于两个相邻控件的值来验证表单
|
||||
|
||||
- show a descriptive error message after the user interacted with the form and the validation failed.
|
||||
|
||||
当用户与表单交互过并且验证失败时,才显示一个描述性的错误信息。
|
||||
|
@ -462,36 +467,68 @@ This completes the cross validation example. We managed to:
|
|||
|
||||
This section shows how to create asynchronous validators. It assumes some basic knowledge of creating [custom validators](guide/form-validation#custom-validators).
|
||||
|
||||
本节展示如何创建异步验证器。这里假设你已经具有了一些创建[自定义验证器](guide/form-validation#custom-validators)的基础知识。
|
||||
|
||||
### The Basics
|
||||
|
||||
### 基础
|
||||
|
||||
Just like synchronous validators have the `ValidatorFn` and `Validator` interfaces, asynchronous validators have their own counterparts: `AsyncValidatorFn` and `AsyncValidator`.
|
||||
|
||||
就像同步验证器有 `ValidatorFn` 和 `Validator` 接口一样,异步验证器也有自己的对应物:`AsyncValidatorFn` 和 `AsyncValidator`。
|
||||
|
||||
They are very similar with the only difference being:
|
||||
|
||||
它们非常像,但是有下列不同:
|
||||
|
||||
* They must return a Promise or an Observable,
|
||||
|
||||
它们必须返回承诺(Promise)或可观察对象(Observable),
|
||||
|
||||
* The observable returned must be finite, meaning it must complete at some point. To convert an infinite observable into a finite one, pipe the observable through a filtering operator such as `first`, `last`, `take`, or `takeUntil`.
|
||||
|
||||
返回的可观察对象必须是有限的,也就是说,它必须在某个时间点结束(complete)。要把无尽的可观察对象转换成有限的,可以使用 `first`、`last`、`take` 或 `takeUntil` 等过滤型管道对其进行处理。
|
||||
|
||||
It is important to note that the asynchronous validation happens after the synchronous validation, and is performed only if the synchronous validation is successful. This check allows forms to avoid potentially expensive async validation processes such as an HTTP request if more basic validation methods fail.
|
||||
|
||||
注意!异步验证总是会在同步验证之后执行,并且只有当同步验证成功了之后才会执行。如果更基本的验证方法已经失败了,那么这能让表单避免进行可能会很昂贵的异步验证过程,比如 HTTP 请求。
|
||||
|
||||
After asynchronous validation begins, the form control enters a `pending` state. You can inspect the control's `pending` property and use it to give visual feedback about the ongoing validation.
|
||||
|
||||
在异步验证器开始之后,表单控件会进入 `pending` 状态。你可以监视该控件的 `pending` 属性,利用它来给用户一些视觉反馈,表明正在进行验证。
|
||||
|
||||
A common UI pattern is to show a spinner while the async validation is being performed. The following example presents how to achieve this with template-driven forms:
|
||||
|
||||
常见的 UI 处理模式是在执行异步验证时显示一个旋转指示标(spinner)。下面的例子展示了在模板驱动表单中该怎么做:
|
||||
|
||||
```html
|
||||
<input [(ngModel)}="name" #model="ngModel" appSomeAsyncValidator>
|
||||
<app-spinner *ngIf="model.pending"></app-spinner>
|
||||
```
|
||||
|
||||
### Implementing Custom Async Validator
|
||||
|
||||
### 实现自定义异步验证器
|
||||
|
||||
In the following section, validation is performed asynchronously to ensure that our heroes pick an alter ego that is not already taken. New heroes are constantly enlisting and old heroes are leaving the service. That means that we do not have the list of available alter egos ahead of time.
|
||||
|
||||
在下一节中,会异步执行一个验证,以确保英雄选取了一个还没有人选过的第二人格。新的英雄不断招募,而老的英雄不断离开。这意味着我们没法提前拿到一个可用的第二人格列表。
|
||||
|
||||
To validate the potential alter ego, we need to consult a central database of all currently enlisted heroes. The process is asynchronous, so we need a special validator for that.
|
||||
|
||||
要验证潜在的第二人格,我们需要咨询一个存有全部已招募英雄的中央数据库。而这个过程是异步的,我们需要一个特殊的验证器。
|
||||
|
||||
Let's start by creating the validator class.
|
||||
|
||||
我们先创建一个验证器类。
|
||||
|
||||
<code-example path="form-validation/src/app/shared/alter-ego.directive.ts" region="async-validator" linenums="false"></code-example>
|
||||
|
||||
As you can see, the `UniqueAlterEgoValidator` class implements the `AsyncValidator` interface. In the constructor, we inject the `HeroesService` that has the following interface:
|
||||
|
||||
如你所见,`UniqueAlterEgoValidator` 类实现了 `AsyncValidator` 接口。在其构造函数中,我们注入了一个
|
||||
`HeroesService`,其接口如下:
|
||||
|
||||
```typescript
|
||||
interface HeroesService {
|
||||
isAlterEgoTaken: (alterEgo: string) => Observable<boolean>;
|
||||
|
@ -500,28 +537,50 @@ interface HeroesService {
|
|||
|
||||
In a real world application, the `HeroesService` is responsible for making an HTTP request to the hero database to check if the alter ego is available. From the validator's point of view, the actual implementation of the service is not important, so we can just code against the `HeroesService` interface.
|
||||
|
||||
在真实的应用中,`HeroesService` 负责向英雄数据库发起一个 HTTP 请求,以检查该第二人格是否可用。
|
||||
从该验证器的视角看,此服务的具体实现无关紧要,所以我们仅仅针对 `HeroesService` 接口来写实现代码。
|
||||
|
||||
As the validation begins, the `UniqueAlterEgoValidator` delegates to the `HeroesService` `isAlterEgoTaken()` method with the current control value. At this point the control is marked as `pending` and remains in this state until the observable chain returned from the `validate()` method completes.
|
||||
|
||||
当验证开始的时候,`UniqueAlterEgoValidator` 把任务委托给 `HeroesService` 的 `isAlterEgoTaken()` 方法,并传入当前控件的值。这时候,该控件会被标记为 `pending` 状态,直到 `validate()` 方法所返回的可观察对象完成(complete)了。
|
||||
|
||||
The `isAlterEgoTaken()` method dispatches an HTTP request that checks if the alter ego is available, and returns `Observable<boolean>` as the result. We pipe the response through the `map` operator and transform it into a validation result. As always, we return `null` if the form is valid, and `ValidationErrors` if it is not. We make sure to handle any potential errors with the `catchError` operator.
|
||||
|
||||
`isAlterEgoTaken()` 方法会发出一个 HTTP 请求,以检查该第二人格是否可用,并返回一个 `Observable<boolean>` 型结果。我们通过 `map` 操作符把响应对象串起来,并把它转换成一个有效性结果。
|
||||
与往常一样,如果表单有效则返回 `null`,否则返回 `ValidationErrors`。我们还是用 `catchError` 操作符来确保对任何潜在错误都进行了处理。
|
||||
|
||||
Here we decided that `isAlterEgoTaken()` error is treated as a successful validation, because failure to make a validation request does not necessarily mean that the alter ego is invalid. You could handle the error differently and return the `ValidationError` object instead.
|
||||
|
||||
这里,我们决定将 `isAlterEgoTaken()` 中的错误视为成功验证,因为如果没能发起验证请求,未必代表这个第二人格是无效的。你也可以将其视为失败,并返回 `ValidationError` 对象。
|
||||
|
||||
After some time passes, the observable chain completes and the async validation is done. The `pending` flag is set to `false`, and the form validity is updated.
|
||||
|
||||
一段时间之后,可观察对象完成了,异步验证也就结束了。这时候 `pending` 标志就改成了 `false`,并且表单的有效性也更新了。
|
||||
|
||||
### Note on performance
|
||||
|
||||
### 性能上的注意事项
|
||||
|
||||
By default, all validators are run after every form value change. With synchronous validators, this will not likely have a noticeable impact on application performance. However, it's common for async validators to perform some kind of HTTP request to validate the control. Dispatching an HTTP request after every keystroke could put a strain on the backend API, and should be avoided if possible.
|
||||
|
||||
默认情况下,每当表单值变化之后,都会执行所有验证器。对于同步验证器,没有什么会显著影响应用性能的地方。不过,异步验证器通常会执行某种 HTTP 请求来对控件进行验证。如果在每次按键之后都发出 HTTP 请求会给后端 API 带来沉重的负担,应该尽量避免。
|
||||
|
||||
We can delay updating the form validity by changing the `updateOn` property from `change` (default) to `submit` or `blur`.
|
||||
|
||||
我们可以把 `updateOn` 属性从 `change`(默认值)改成 `submit` 或 `blur` 来推迟表单验证的更新时机。
|
||||
|
||||
With template-driven forms:
|
||||
|
||||
对于模板驱动表单:
|
||||
|
||||
```html
|
||||
<input [(ngModel)]="name" [ngModelOptions]="{updateOn: 'blur'}">
|
||||
```
|
||||
|
||||
With reactive forms:
|
||||
|
||||
对于响应式表单:
|
||||
|
||||
```typescript
|
||||
new FormControl('', {updateOn: 'blur'});
|
||||
```
|
||||
|
|
|
@ -59,6 +59,8 @@ You can run the <live-example></live-example> in Stackblitz and download the cod
|
|||
|
||||
## Template-driven forms
|
||||
|
||||
## 模板驱动表单
|
||||
|
||||
You can build forms by writing templates in the Angular [template syntax](guide/template-syntax) with
|
||||
the form-specific directives and techniques described in this page.
|
||||
|
||||
|
@ -197,7 +199,7 @@ and one optional field (`alterEgo`).
|
|||
|
||||
Using the Angular CLI command [`ng generate class`](cli/generate), generate a new class named `Hero`:
|
||||
|
||||
使用 Angular CLI 生成一个名叫 `Hero` 的新类:
|
||||
使用 Angular CLI 命令 [`ng generate class`](cli/generate) 生成一个名叫 `Hero` 的新类:
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
|
||||
|
@ -247,7 +249,7 @@ Angular 表单分为两部分:基于 HTML 的*模板*和组件*类*,用来
|
|||
|
||||
Using the Angular CLI command [`ng generate component`](cli/generate), generate a new component named `HeroForm`:
|
||||
|
||||
使用 Angular CLI 生成一个名叫 `HeroForm` 的新组件:
|
||||
使用 Angular CLI 命令 [`ng generate class`](cli/generate) 生成一个名叫 `HeroForm` 的新组件:
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
|
||||
|
|
|
@ -178,7 +178,7 @@ Upper snake case uses words in all capital letters connected with underscores. F
|
|||
|
||||
A [decorator](guide/glossary#decorator) that appears immediately before a class definition, which declares the class to be of the given type, and provides metadata suitable to the type.
|
||||
|
||||
出现在类定义紧前方的[装饰器](guide/glossary#decorator)语句用来声明该类具有指定的类型,并且提供适合该类型的元数据。
|
||||
[装饰器](guide/glossary#decorator)会出现在类定义的紧前方,用来声明该类具有指定的类型,并且提供适合该类型的元数据。
|
||||
|
||||
The following decorators can declare Angular class types:
|
||||
|
||||
|
@ -210,8 +210,8 @@ A [decorator](guide/glossary#decorator) statement immediately before a field in
|
|||
|
||||
The [Angular CLI](cli) is a command-line tool for managing the Angular development cycle. Use it to create the initial filesystem scaffolding for a [workspace](guide/glossary#workspace) or [project](guide/glossary#project), and to run [schematics](guide/glossary#schematic) that add and modify code for initial generic versions of various elements. The CLI supports all stages of the development cycle, including building, testing, bundling, and deployment.
|
||||
|
||||
[Angular CLI](https://cli.angular.io/) 是一个命令行工具,用于管理 Angular 的开发周期。它用于为[工作空间](guide/glossary#workspace)或[项目](guide/glossary#project)创建初始的脚手架,并且运行[生成器(schematics)](guide/glossary#schematic)来为初始生成的版本添加或修改各类代码。
|
||||
该工具支持开发周期中的所有阶段,比如构建、测试、打包和部署。
|
||||
[Angular CLI](cli) 是一个命令行工具,用于管理 Angular 的开发周期。它用于为[工作空间](guide/glossary#workspace)或[项目](guide/glossary#project)创建初始的脚手架,并且运行[生成器(schematics)](guide/glossary#schematic)来为初始生成的版本添加或修改各类代码。
|
||||
CLI 支持开发周期中的所有阶段,比如构建、测试、打包和部署。
|
||||
|
||||
* To begin using the CLI for a new project, see [Getting Started](guide/quickstart).
|
||||
|
||||
|
@ -219,7 +219,7 @@ The [Angular CLI](cli) is a command-line tool for managing the Angular developme
|
|||
|
||||
* To learn more about the full capabilities of the CLI, see the [CLI command reference](cli).
|
||||
|
||||
要学习 CLI 的所有功能,参见 [Angular CLI 文档].(https://github.com/angular/angular-cli/wiki)
|
||||
要了解 CLI 的全部功能,参见 [CLI 命令参考手册](cli)。
|
||||
|
||||
{@a component}
|
||||
|
||||
|
@ -229,11 +229,12 @@ The [Angular CLI](cli) is a command-line tool for managing the Angular developme
|
|||
|
||||
A class with the `@Component()` [decorator](guide/glossary#decorator) that associates it with a companion [template](guide/glossary#template). Together, the component and template define a [view](guide/glossary#view).
|
||||
|
||||
一个带有 `@Component` [装饰器](guide/glossary#decorator)的类,和它的伴生[模板](guide/glossary#template)关联在一起。组件及其模板共同定义了一个[视图](guide/glossary#view)。
|
||||
一个带有 `@Component()` [装饰器](guide/glossary#decorator)的类,和它的伴生[模板](guide/glossary#template)关联在一起。组件及其模板共同定义了一个[视图](guide/glossary#view)。
|
||||
|
||||
A component is a special type of [directive](guide/glossary#directive).
|
||||
The `@Component()` decorator extends the `@Directive()` decorator with template-oriented features.
|
||||
|
||||
组件是[指令](guide/glossary#directive)的一种特例。`@Component` 装饰器扩展了 `@Directive` 装饰器,增加了一些与模板有关的特性。
|
||||
组件是[指令](guide/glossary#directive)的一种特例。`@Component()` 装饰器扩展了 `@Directive()` 装饰器,增加了一些与模板有关的特性。
|
||||
|
||||
An Angular component class is responsible for exposing data and handling most of the view's display and user-interaction logic through [data binding](guide/glossary#data-binding).
|
||||
|
||||
|
@ -241,7 +242,7 @@ Angular 的组件类负责暴露数据,并通过[数据绑定机制](guide/glo
|
|||
|
||||
Read more about components, templates, and views in [Architecture Overview](guide/architecture).
|
||||
|
||||
要了解更多关于组件、模板和视图的知识,参见 [架构](guide/architecture) 一章。
|
||||
要了解更多关于组件、模板和视图的知识,参见 [架构概览](guide/architecture) 一章。
|
||||
|
||||
{@a custom-element}
|
||||
|
||||
|
@ -264,7 +265,7 @@ You can use the API to transform an Angular component so that it can be register
|
|||
|
||||
See also [dynamic component loading](guide/glossary#dynamic-components).
|
||||
|
||||
参见[动态组件](guide/glossary#dynamic-components)。
|
||||
参见[加载动态组件](guide/glossary#dynamic-components)。
|
||||
|
||||
{@a D}
|
||||
|
||||
|
@ -294,31 +295,31 @@ Read about the following forms of binding in [Template Syntax](guide/template-sy
|
|||
|
||||
* [Interpolation](guide/template-syntax#interpolation)
|
||||
|
||||
[插值表达式 (interpolation)](guide/template-syntax#interpolation)
|
||||
[插值表达式](guide/template-syntax#interpolation)
|
||||
|
||||
* [Property binding](guide/template-syntax#property-binding)
|
||||
|
||||
[property 绑定 (property binding)](guide/template-syntax#property-binding)
|
||||
[property 绑定](guide/template-syntax#property-binding)
|
||||
|
||||
* [Event binding](guide/template-syntax#event-binding)
|
||||
|
||||
[事件绑定 (event binding)](guide/template-syntax#event-binding)
|
||||
[事件绑定](guide/template-syntax#event-binding)
|
||||
|
||||
* [Attribute binding](guide/template-syntax#attribute-binding)
|
||||
|
||||
[attribute 绑定 (attribute binding)](guide/template-syntax#attribute-binding)
|
||||
[attribute 绑定](guide/template-syntax#attribute-binding)
|
||||
|
||||
* [Class binding](guide/template-syntax#class-binding)
|
||||
|
||||
[CSS 类绑定 (class binding)](guide/template-syntax#class-binding)
|
||||
[CSS 类绑定](guide/template-syntax#class-binding)
|
||||
|
||||
* [Style binding](guide/template-syntax#style-binding)
|
||||
|
||||
[样式绑定 (style binding)](guide/template-syntax#style-binding)
|
||||
[样式绑定](guide/template-syntax#style-binding)
|
||||
|
||||
* [Two-way data binding with ngModel](guide/template-syntax#ngModel)
|
||||
|
||||
[基于 ngModel 的双向数据绑定 (Two-way data binding with ngModel)](guide/template-syntax#ngModel)
|
||||
[基于 ngModel 的双向数据绑定](guide/template-syntax#ngModel)
|
||||
|
||||
{@a declarable}
|
||||
|
||||
|
@ -402,7 +403,7 @@ An [injector](guide/glossary#injector) for an app (created automatically during
|
|||
|
||||
Learn more in [Dependency Injection in Angular](guide/dependency-injection).
|
||||
|
||||
要了解更多,参见[依赖注入](guide/dependency-injection)一章。
|
||||
要了解更多,参见[Angular 中的依赖注入](guide/dependency-injection)一章。
|
||||
|
||||
{@a di-token}
|
||||
|
||||
|
@ -466,6 +467,7 @@ Angular 提供了一些以 `ng` 为前缀的内置指令。你也可以创建新
|
|||
A special-purpose library or API; see [Domain-specific language](https://en.wikipedia.org/wiki/Domain-specific_language).
|
||||
|
||||
一种特殊用途的库或 API,参见[领域特定语言](https://en.wikipedia.org/wiki/Domain-specific_language)词条。
|
||||
|
||||
Angular extends TypeScript with domain-specific languages for a number of domains relevant to Angular apps, defined in NgModules such as [animations](guide/animations), [forms](guide/forms), and [routing and navigation](guide/router).
|
||||
|
||||
Angular 在一些相关的应用领域中用领域特定语言扩展了 TypeScript,这些 DSL 都定义在 NgModule 中,比如 [动画](guide/animations)、[表单](guide/forms)和[路由与导航](guide/router)。
|
||||
|
@ -490,10 +492,14 @@ See also [custom element](guide/glossary#custom-element), which provides an easi
|
|||
|
||||
## eager loading
|
||||
|
||||
## 急性加载(Eager Loading)
|
||||
|
||||
NgModules or components that are loaded on launch are called eager-loaded, to distinguish them from those
|
||||
that are loaded at run time (lazy-loaded).
|
||||
See [lazy loading](guide/glossary#lazy-load).
|
||||
|
||||
在启动时加载的 NgModule 和组件被称为急性加载,与之相对的是那些在运行期间才加载的方式(惰性加载)。
|
||||
参见[惰性加载](guide/glossary#lazy-load)。
|
||||
|
||||
{@a ecma}
|
||||
|
||||
|
@ -528,7 +534,7 @@ Angular 定义了 `ElementRef` 类来包装与渲染有关的原生 UI 元素。
|
|||
The documentation generally refers to *elements* (`ElementRef` instances), as distinct from *DOM elements*
|
||||
(which can be accessed directly if necessary).
|
||||
|
||||
本文档中一般会使用**元素(Element)**来指代 `ElementRef` 的实例,而用 **DOM 元素**来指代直接访问的 DOM。
|
||||
本文档中一般会使用**元素(Element)**来指代 `ElementRef` 的实例,注意与 **DOM 元素**(你必要时你可以直接访问它)区分开。
|
||||
|
||||
Compare to [custom element](guide/glossary#custom-element).
|
||||
|
||||
|
@ -548,7 +554,7 @@ Angular 的每个[范围化的包](guide/glossary#scoped-package)都有一个名
|
|||
|
||||
Within Angular, use [NgModules](guide/glossary#ngmodule) to make public parts available for import by other NgModules.
|
||||
|
||||
在 Angular 领域中,[NgModules](guide/glossary#ngmodule) 起到同样的作用。
|
||||
在 Angular 领域中,[NgModules](guide/glossary#ngmodule) 可以让一些公开的部分可以供其它 NgModules 导入。
|
||||
|
||||
{@a F}
|
||||
|
||||
|
@ -562,6 +568,8 @@ Within Angular, use [NgModules](guide/glossary#ngmodule) to make public parts av
|
|||
|
||||
## injectable
|
||||
|
||||
## 可注入对象(injectable)
|
||||
|
||||
An Angular class or other definition that provides a dependency using the [dependency injection](guide/glossary#di) mechanism. An injectable [service](guide/glossary#service) class must be marked by the `@Injectable()` [decorator](guide/glossary#decorator). Other items, such as constant values, can also be injectable.
|
||||
|
||||
Angular 中的类或其它概念使用[依赖注入](guide/glossary#di)机制来提供依赖。
|
||||
|
@ -597,7 +605,7 @@ Angular [依赖注入系统](guide/glossary#dependency-injection)中可以在缓
|
|||
|
||||
Learn more about the injector hierarchy in [Hierarchical Dependency Injectors](guide/hierarchical-dependency-injection).
|
||||
|
||||
要了解关于多级注入器的更多知识,参见[依赖注入](guide/hierarchical-dependency-injection)一章。
|
||||
要了解关于多级注入器的更多知识,参见[多级依赖注入](guide/hierarchical-dependency-injection)一章。
|
||||
|
||||
{@a input}
|
||||
|
||||
|
@ -610,7 +618,7 @@ makes that property available as a *target* of a [property binding](guide/templa
|
|||
Data values flow into an input property from the data source identified
|
||||
in the [template expression](guide/glossary#template-expression) to the right of the equal sign.
|
||||
|
||||
当定义[指令](guide/glossary#directive)时,指令属性上的 `@Input` 装饰器让该属性可以作为[属性绑定](guide/template-syntax#property-binding)的*目标*使用。
|
||||
当定义[指令](guide/glossary#directive)时,指令属性上的 `@Input()` 装饰器让该属性可以作为[属性绑定](guide/template-syntax#property-binding)的*目标*使用。
|
||||
数据值会从等号右侧的[模板表达式](guide/glossary#template-expression)所指定的数据源流入组件的输入属性。
|
||||
|
||||
To learn more, see [input and output properties](guide/template-syntax#inputs-outputs).
|
||||
|
@ -781,8 +789,8 @@ In JavaScript (ECMAScript), each file is a module and all objects defined in the
|
|||
|
||||
Angular ships as a collection of JavaScript modules (also called libraries). Each Angular library name begins with the `@angular` prefix. Install Angular libraries with the [npm package manager](https://docs.npmjs.com/getting-started/what-is-npm) and import parts of them with JavaScript `import` declarations.
|
||||
|
||||
Angular 就是用一组 JavaScript 模块(或叫库)的形式发布的。每个 Angular 库都带有 `@angular` 前缀。
|
||||
使用 NPM 包管理器安装它们,并且使用 JavaScript 的 `import` 声明语句从中导入各个部件。
|
||||
Angular 就是用一组 JavaScript 模块(也叫库)的形式发布的。每个 Angular 库都带有 `@angular` 前缀。
|
||||
使用 [NPM 包管理器](https://docs.npmjs.com/getting-started/what-is-npm)安装它们,并且使用 JavaScript 的 `import` 声明语句从中导入各个部件。
|
||||
|
||||
Compare to [NgModule](guide/glossary#ngmodule).
|
||||
|
||||
|
@ -796,7 +804,7 @@ Compare to [NgModule](guide/glossary#ngmodule).
|
|||
|
||||
A class definition preceded by the `@NgModule()` [decorator](guide/glossary#decorator), which declares and serves as a manifest for a block of code dedicated to an application domain, a workflow, or a closely related set of capabilities.
|
||||
|
||||
一种带有 `@NgModule` [装饰器](guide/glossary#decorator)的类定义,它会声明并提供一组专注于特定功能的代码块,比如业务领域、工作流或一组紧密相关的能力集等。
|
||||
一种带有 `@NgModule()` [装饰器](guide/glossary#decorator)的类定义,它会声明并提供一组专注于特定功能的代码块,比如业务领域、工作流或一组紧密相关的能力集等。
|
||||
|
||||
Like a [JavaScript module](guide/glossary#module), an NgModule can export functionality for use by other NgModules and import public functionality from other NgModules.
|
||||
The metadata for an NgModule class collects components, directives, and pipes that the application uses along with the list of imports and exports. See also [declarable](guide/glossary#declarable).
|
||||
|
@ -845,7 +853,7 @@ Angular 中到处都会用到异步事件处理。你要通过调用可观察对
|
|||
Observables can deliver single or multiple values of any type to subscribers, either synchronously (as a function delivers a value to its caller) or on a schedule. A subscriber receives notification of new values as they are produced and notification of either normal completion or error completion.
|
||||
|
||||
可观察对象可以把任意类型的一个或多个值传给订阅者,无论是同步(就像函数把值返回给它的调用者一样)还是异步。
|
||||
一旦生成了新值,订阅者就会收到通知,并且还会收到错误或正常完成的通知。
|
||||
订阅者会在生成了新值时收到包含这个新值的通知,以及正常结束或错误结束时的通知。
|
||||
|
||||
Angular uses a third-party library called [Reactive Extensions (RxJS)](http://reactivex.io/rxjs/).
|
||||
|
||||
|
@ -944,9 +952,11 @@ Angular 会为其自带的服务在每个注入器中注册它自己的提供商
|
|||
|
||||
See also [service](guide/glossary#service), [dependency injection](guide/glossary#di).
|
||||
|
||||
参见[服务](guide/glossary#service)和[依赖注入](guide/glossary#di)。
|
||||
|
||||
Learn more in [Dependency Injection](guide/dependency-injection).
|
||||
|
||||
参见[服务](guide/glossary#service)和[依赖注入](guide/glossary#di)。
|
||||
欲知详情,参见[依赖注入](guide/dependency-injection)。
|
||||
|
||||
{@a Q}
|
||||
|
||||
|
@ -982,7 +992,7 @@ When building reactive forms:
|
|||
|
||||
* The associated Angular directives are 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.
|
||||
|
||||
|
@ -1001,7 +1011,7 @@ A tool that configures and implements navigation among states and [views](guide/
|
|||
|
||||
The `Router` module is an [NgModule](guide/glossary#ngmodule) that provides the necessary service providers and directives for navigating through application views. A [routing component](guide/glossary#routing-component) is one that imports the `Router` module and whose template contains a `RouterOutlet` element where it can display views produced by the router.
|
||||
|
||||
路由器模块是一个 [NgModule](guide/glossary#ngmodule),它提供在应用视图间导航时需要的服务提供商和指令。[路由组件](guide/glossary#routing-component)是一种组件,它导入了路由模块,并且其模板中包含 `RouterOutlet` 元素,路由器生成的视图就会被显示在那里。
|
||||
`Router` 模块是一个 [NgModule](guide/glossary#ngmodule),它提供在应用视图间导航时需要的服务提供商和指令。[路由组件](guide/glossary#routing-component)是一种组件,它导入了 `Router` 模块,并且其模板中包含 `RouterOutlet` 元素,路由器生成的视图就会被显示在那里。
|
||||
|
||||
The router defines navigation among views on a single page, as opposed to navigation among pages. It interprets URL-like links to determine which views to create or destroy, and which components to load or unload. It allows you to take advantage of [lazy loading](guide/glossary#lazy-load) in your Angular apps.
|
||||
|
||||
|
@ -1041,14 +1051,23 @@ For more information, see [Routing and Navigation](guide/router).
|
|||
|
||||
## schematic
|
||||
|
||||
## 原理图(schematic)
|
||||
|
||||
A scaffolding library that defines how to generate or transform a programming project by creating, modifying, refactoring, or moving files and code.
|
||||
The Angular [CLI](guide/glossary#cli) uses schematics to generate and modify [Angular projects](guide/glossary#project) and parts of projects.
|
||||
|
||||
一种脚手架库,它会定义出要如何通过创建、修改、重构或移动文件和代码的方式生成或转换编程项目。
|
||||
Angular [CLI](guide/glossary#cli) 使用原理图来生成和修改 [Angular 项目](guide/glossary#project)及其各个部件。
|
||||
|
||||
* Angular provides a set of schematics for use with the CLI. See the [Angular CLI command reference](cli). The [`ng add`](cli/add) command runs schematics as part of adding a library to your project. The [`ng generate`](cli/generate) command runs schematics to create apps, libraries, and Angular code constructs.
|
||||
|
||||
Angular 提供了一组用于 CLI 的原理图。参见 [Angular CLI 命令参考手册](cli)。当 [`ng add`](cli/add) 命令向项目中添加某个库时,就会运行原理图。[`ng generate`](cli/generate) 命令则会运行原理图,来创建应用、库和 Angular 代码块。
|
||||
|
||||
* Library developers can create schematics that enable the CLI to generate their published libraries.
|
||||
For more information, see [devkit documentation](https://www.npmjs.com/package/@angular-devkit/schematics).
|
||||
|
||||
公共库的开发者可以创建原理图,来让 CLI 生成他们自己的发布的库。欲知详情,参见 [devkit 文档](https://www.npmjs.com/package/@angular-devkit/schematics)。
|
||||
|
||||
{@a scoped-package}
|
||||
|
||||
## scoped package
|
||||
|
@ -1058,7 +1077,7 @@ For more information, see [devkit documentation](https://www.npmjs.com/package/@
|
|||
A way to group related [npm packages](guide/npm-packages).
|
||||
NgModules are delivered within scoped packages whose names begin with the Angular *scope name* `@angular`. For example, `@angular/core`, `@angular/common`, `@angular/forms`, and `@angular/router`.
|
||||
|
||||
一种把相关的 NPM 包分组到一起的方式。
|
||||
一种把相关的 [npm 包](guide/npm-packages)分组到一起的方式。
|
||||
Angular 的 NgModule 都是在一些以 `@angular` 为范围名的*范围化包*中发布的。比如 `@angular/core`、`@angular/common`、`@angular/forms` 和 `@angular/router`。
|
||||
|
||||
Import a scoped package in the same way that you import a normal package.
|
||||
|
@ -1085,11 +1104,12 @@ The `@Injectable()` metadata allows the service class to be used with the [depen
|
|||
The injectable class is instantiated by a [provider](guide/glossary#provider).
|
||||
[Injectors](guide/glossary#injector) maintain lists of providers and use them to provide service instances when they are required by components or other services.
|
||||
|
||||
`@Injectable` 元数据让服务类能用于[依赖注入](guide/glossary#di)机制中。可注入的类是用[提供商](guide/glossary#provider)进行实例化的,模块中包含一个提供商列表,它可以为依赖它的组件或其它服务提供该服务的具体类。
|
||||
`@Injectable` 元数据让服务类能用于[依赖注入](guide/glossary#di)机制中。可注入的类是用[提供商](guide/glossary#provider)进行实例化的。
|
||||
[各个注入器](guide/glossary#injector)会维护一个提供商的列表,并根据组件或其它服务的需要,用它们来提供服务的实例。
|
||||
|
||||
To learn more, see [Introduction to Services and Dependency Injection](guide/architecture-services).
|
||||
|
||||
要了解更多,参见[服务简介](guide/architecture-services)。
|
||||
要了解更多,参见[服务与依赖注入简介](guide/architecture-services)。
|
||||
|
||||
{@a structural-directive}
|
||||
{@a structural-directives}
|
||||
|
@ -1123,7 +1143,7 @@ The act of subscribing to an observable triggers its execution, associates callb
|
|||
|
||||
The `subscribe()` method takes a JavaScript object (called an [observer](guide/glossary#observer)) with up to three callbacks, one for each type of notification that an observable can deliver:
|
||||
|
||||
`subscribe()` 方法接收一个 JavaScript 对象(叫做 "观察者"),其中最多可以包含三个回调,分别对应可观察对象可以发出的几种通知类型:
|
||||
`subscribe()` 方法接收一个 JavaScript 对象(叫做[观察者(observer)](guide/glossary#observer)),其中最多可以包含三个回调,分别对应可观察对象可以发出的几种通知类型:
|
||||
|
||||
* The `next` notification sends a value such as a number, a string, or an object.
|
||||
|
||||
|
@ -1156,7 +1176,7 @@ The Angular elements insert or calculate values that modify the HTML elements be
|
|||
|
||||
A template is associated with a [component](guide/glossary#component) class through the `@Component()` [decorator](guide/glossary#decorator). The HTML can be provided inline, as the value of the `template` property, or in a separate HTML file linked through the `templateUrl` property.
|
||||
|
||||
模板通过 `@Component` [装饰器](guide/glossary#decorator)与[组件](guide/glossary#component)类关联起来。其 HTML 可以作为 `template` 属性的值用内联的方式提供,也可以通过 `templateUrl` 属性链接到一个独立的 HTML 文件。
|
||||
模板通过 `@Component()` [装饰器](guide/glossary#decorator)与[组件](guide/glossary#component)类关联起来。其 HTML 可以作为 `template` 属性的值用内联的方式提供,也可以通过 `templateUrl` 属性链接到一个独立的 HTML 文件。
|
||||
|
||||
Additional templates, represented by `TemplateRef` objects, can define alternative or *embedded* views, which can be referenced from multiple components.
|
||||
|
||||
|
@ -1204,6 +1224,8 @@ Read about how to build template-driven forms in [Forms](guide/forms).
|
|||
|
||||
## template expression
|
||||
|
||||
## 模板表达式(template expression)
|
||||
|
||||
A TypeScript-like syntax that Angular evaluates within a [data binding](guide/glossary#data-binding).
|
||||
|
||||
一种类似 TypeScript 的语法,Angular 用它对[数据绑定 (data binding)](guide/glossary#data-binding)进行求值。
|
||||
|
@ -1321,7 +1343,7 @@ The [CLI](guide/glossary#cli) `ng new` command creates a workspace to contain pr
|
|||
Commands that create or operate on apps and libraries (such as `add` and `generate`) must be executed from within a workspace folder.
|
||||
|
||||
在 Angular 中,是指一个包含[项目](guide/glossary#project)(即应用和库)的文件夹。
|
||||
[CLI](guide/glossary#cli) 的 `new` 命令会创建一个包含项目的工作空间。而用来创建或操作应用和库的 `add` 和 `generate` 命令必须在工作空间目录下才能执行。
|
||||
[CLI](guide/glossary#cli) 的 `ng new` 命令会创建一个包含项目的工作空间。而用来创建或操作应用和库的 `add` 和 `generate` 命令必须在工作空间目录下才能执行。
|
||||
|
||||
{@a X}
|
||||
|
||||
|
|
|
@ -21,88 +21,146 @@ It uses examples based on this <live-example></live-example>.
|
|||
|
||||
## Where to configure providers
|
||||
|
||||
## 在哪里配置提供商
|
||||
|
||||
You can configure providers for different injectors in the injector hierarchy.
|
||||
An internal platform-level injector is shared by all running apps.
|
||||
The `AppModule` injector is the root of an app-wide injector hierarchy, and within
|
||||
an NgModule, directive-level injectors follow the structure of the component hierarchy.
|
||||
|
||||
你可以为注入器树中不同的注入器分别配置提供商。
|
||||
所有运行中的应用都会共享同一个内部的平台级注入器。
|
||||
`AppModule` 上的注入器是全应用级注入器树的根节点,在 NgModule 中,指令级的注入器会遵循组件树的结构。
|
||||
|
||||
The choices you make about where to configure providers lead to differences in the final bundle size, service _scope_, and service _lifetime_.
|
||||
|
||||
关于在哪里配置提供商的不同选择将导致一些差异:最终包的大小、服务的*范围*和服务的*生命周期*。
|
||||
|
||||
When you specify providers in the `@Injectable()` decorator of the service itself (typically at the app root level), optimization tools such as those used by the CLI's production builds can perform *tree shaking*, which removes services that aren't used by your app. Tree shaking results in smaller bundle sizes.
|
||||
|
||||
当你在服务自身的 `@Injectable()` 装饰器中指定提供商时(通常在应用的根一级),CLI 生产模式构建时所用的优化工具可以执行*摇树优化*,它会移除没有用过的那些服务。摇树优化生成的包会更小。
|
||||
|
||||
* Learn more about [tree-shakable providers](guide/dependency-injection-providers#tree-shakable-providers).
|
||||
|
||||
要了解更多,参见[可摇树优化的提供商](guide/dependency-injection-providers#tree-shakable-providers)。
|
||||
|
||||
You're likely to inject `UserService` in many places throughout the app and will want to inject the same service instance every time. Providing `UserService` through the `root` injector is a good choice, and is the default that the [Angular CLI](cli) uses when you generate a service for your app.
|
||||
|
||||
你可能会在应用程序的许多地方注入 `UserService`,并希望每次注入的都是服务的同一个实例。这种情况下,通过 `root` 来提供 `UserService` 就是不错的选择,而且这也是 [Angular CLI](cli) 为应用生成服务时的默认选项。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
<header>Platform injector</header>
|
||||
|
||||
<header>平台注入器</header>
|
||||
|
||||
When you use `providedIn:'root'`, you are configuring the root injector for the _app_, which is the injector for `AppModule`.
|
||||
The actual root of the entire injector hierarchy is a _platform injector_ that is the parent of app-root injectors.
|
||||
This allows multiple apps to share a platform configuration. For example, a browser has only one URL bar, no matter how many apps you have running.
|
||||
|
||||
当使用 `providedIn:'root'` 时,你是在配置*应用*的根注入器,也就是 `AppModule` 的注入器。
|
||||
整个注入器树的真正的根是*平台注入器*,它是根注入器的父节点。
|
||||
这可以让多个应用共享同一套平台配置。比如,无论你正在运行多少个应用,一个浏览器窗口都只有一个地址栏。
|
||||
|
||||
The platform injector is used internally during bootstrap, to configure platform-specific dependencies. You can configure additional platform-specific providers at the platform level by supplying `extraProviders` using the `platformBrowser()` function.
|
||||
|
||||
平台注入器是在启动期间内部使用的,用于配置与平台相关的依赖项。通过在调用 `platformBrowser()` 函数时提供 `extraProviders` 参数,你可以在平台级配置更多与平台相关的提供商。
|
||||
|
||||
Learn more about dependency resolution through the injector hierarchy:
|
||||
[What you always wanted to know about Angular Dependency Injection tree](https://blog.angularindepth.com/angular-dependency-injection-and-tree-shakeable-tokens-4588a8f70d5d)
|
||||
|
||||
组件的注入器可能是一个组件树中更高级的祖先注入器的*代理*。
|
||||
但这只是提升效率的实现细节,你不用在乎这点差异,在你的脑海里只要想象成每个组件都有自己的注入器就可以了。
|
||||
要了解借助注入器树解析依赖项的更多信息,参见[你所不知道的 Angular 依赖注入树](https://blog.angularindepth.com/angular-dependency-injection-and-tree-shakeable-tokens-4588a8f70d5d)。
|
||||
|
||||
</div>
|
||||
|
||||
*NgModule-level* providers can be specified with `@NgModule()` `providers` metadata option, or in the `@Injectable()` `providedIn` option (with some module other than the root `AppModule`).
|
||||
|
||||
*NgModule 级*的提供商可以在 `@NgModule()` `providers` 元数据中指定,也可以在 `@Injectable()` 的 `providedIn` 选项中指定某个模块类(但根模块 `AppModule` 除外)。
|
||||
|
||||
Use the `@NgModule()` `provides` option if a module is [lazy loaded](guide/lazy-loading-ngmodules). The module's own injector is configured with the provider when that module is loaded, and Angular can inject the corresponding services in any class it creates in that module. If you use the `@Injectable()` option `providedIn: MyLazyloadModule`, the provider could be shaken out at compile time, if it is not used anywhere else in the app.
|
||||
|
||||
如果某个模块是[惰性加载](guide/lazy-loading-ngmodules)的,那么请使用 `@NgModule()` 的 `provides` 选项。加载那个模块时,就会用这里的提供商来配置模块本身的注入器,而 Angular 会为该模块中创建的任何类注入相应的服务。如果你使用了 `@Injectable()` 中的 `providedIn: MyLazyloadModule` 选项,那么如果该提供商没有在别处用过,就可以在编译期间把它摇树优化掉。
|
||||
|
||||
* Learn more about [tree-shakable providers](guide/dependency-injection-providers#tree-shakable-providers).
|
||||
|
||||
欲知详情,参见[可摇树优化的提供商](guide/dependency-injection-providers#tree-shakable-providers)。
|
||||
|
||||
For both root-level and module-level injectors, a service instance lives for the life of the app or module, and Angular injects this one service instance in every class that needs it.
|
||||
|
||||
无论对于根级注入器还是模块级注入器,服务实例的生命周期都和应用或模块本身相同。Angular 可以把服务实例注入给任何需要它的类中。
|
||||
|
||||
*Component-level* providers configure each component instance's own injector.
|
||||
Angular can only inject the corresponding services in that component instance or one of its descendant component instances.
|
||||
Angular can't inject the same service instance anywhere else.
|
||||
|
||||
*组件级*提供商为每个组件实例配置自己的注入器。
|
||||
Angular 只能把相应的服务注入到该组件实例或其下级组件实例中,而不能把这个服务实例注入到其它地方。
|
||||
|
||||
A component-provided service may have a limited lifetime.
|
||||
Each new instance of the component gets its own instance of the service.
|
||||
When the component instance is destroyed, so is that service instance.
|
||||
|
||||
组件提供的服务具有受限的生命周期。
|
||||
该组件的每个新实例都会获得自己的一份服务实例。
|
||||
当销毁组件实例时,服务实例也会被同时销毁。
|
||||
|
||||
In our sample app, `HeroComponent` is created when the application starts
|
||||
and is never destroyed,
|
||||
so the `HeroService` instance created for `HeroComponent` lives for the life of the app.
|
||||
If you want to restrict `HeroService` access to `HeroComponent` and its nested
|
||||
`HeroListComponent`, provide `HeroService` at the component level, in `HeroComponent` metadata.
|
||||
|
||||
在这个范例应用中,应用一启动就会创建 `HeroComponent` 的实例,而且永不销毁,所以由 `HeroComponent` 创建的 `HeroService` 的实例的生命周期也和应用相同。
|
||||
如果你要把 `HeroService` 的访问权限制到 `HeroComponent` 及其内嵌的 `HeroListComponent` 中,可以通过修改 `HeroComponent` 的元数据,来要求在组件级提供 `HeroService`。
|
||||
|
||||
* See more [examples of component-level injection](#component-injectors) below.
|
||||
|
||||
参见稍后的[组件级注入的例子](#component-injectors)。
|
||||
|
||||
{@a register-providers-injectable}
|
||||
|
||||
### @Injectable-level configuration
|
||||
|
||||
### 在 @Injectable 级进行配置
|
||||
|
||||
The `@Injectable()` decorator identifies every service class. The `providedIn` metadata option for a service class configures a specific injector (typically `root`)
|
||||
to use the decorated class as a provider of the service.
|
||||
When an injectable class provides its own service to the `root` injector, the service is available anywhere the class is imported.
|
||||
|
||||
`@Injectable()` 装饰器会标出每个服务类。服务类的元数据选项 `providedIn` 会指定一个注入器(通常为 `root` 来用被装饰的类作为该服务的提供商。
|
||||
当可注入的类向 `root` 注入器提供了自己的服务时,任何导入了该类的地方都能使用这个服务。
|
||||
|
||||
The following example configures a provider for `HeroService` using the `@Injectable()` decorator on the class.
|
||||
|
||||
下面的例子使用类上的 `@Injectable()` 装饰器为 `HeroService` 配置了提供商。
|
||||
|
||||
<code-example path="dependency-injection/src/app/heroes/hero.service.0.ts" header="src/app/heroes/heroes.service.ts" linenums="false"> </code-example>
|
||||
|
||||
This configuration tells Angular that the app's root injector is responsible for creating an
|
||||
instance of `HeroService` by invoking its constructor,
|
||||
and for making that instance available across the application.
|
||||
|
||||
这个配置项告诉 Angular,要由此应用的根注入器负责通过调用 `HeroService` 的构造函数来创建它的实例。
|
||||
并让该实例在整个应用程序中可用。
|
||||
|
||||
Providing a service with the app's root injector is a typical case,
|
||||
and the CLI sets up this kind of a provider automatically for you
|
||||
when generating a new service.
|
||||
However, you might not always want to provide your service at the root level.
|
||||
You might, for instance, want users to explicitly opt-in to using the service.
|
||||
|
||||
典型的方式是通过应用的根注入器来提供服务,当 CLI 生成新的服务时,也会自动为你设置为这种方式。
|
||||
不过,你有时候可能不希望通过根注入器提供服务。比如,你可能会希望用户显式的选择如何使用该服务。
|
||||
|
||||
Instead of specifying the `root` injector, you can set `providedIn` to a specific NgModule.
|
||||
|
||||
除了指定给 `root` 注入器之外,你还可以把 `providedIn` 设置为某个特定的 NgModule。
|
||||
|
||||
For example, in the following excerpt, the `@Injectable()` decorator configures a provider
|
||||
that is available in any injector that includes the `HeroModule`.
|
||||
|
||||
比如,在下面的代码片段中,`@Injectable()` 装饰器配置了一个提供商,它能用于 `HeroModule` 包含的所有注入器中。
|
||||
|
||||
<code-example path="dependency-injection/src/app/heroes/hero.service.4.ts" header="src/app/heroes/hero.service.ts" linenums="false"> </code-example>
|
||||
|
||||
This is generally no different from configuring the injector of the NgModule itself,
|
||||
|
@ -111,23 +169,38 @@ It can be useful for a library that offers a particular service that some
|
|||
components *might* want to inject optionally,
|
||||
and leave it up to the app whether to provide the service.
|
||||
|
||||
一般来说,这和在 NgModule 本身的装饰器上配置注入器没有多少不同,主要的区别是如果 NgModule 没有用到该服务,那么它就是可以被摇树优化掉的。
|
||||
对于某个提供特定服务的库而言,有些组件*可能*会希望注入器是可选的,等使用该库的应用程序来决定是否要提供该服务。
|
||||
|
||||
* Learn more about [tree-shakable providers](guide/dependency-injection-providers#tree-shakable-providers).
|
||||
|
||||
欲知详情,参见[可摇树优化的提供商](guide/dependency-injection-providers#tree-shakable-providers)。
|
||||
|
||||
### @NgModule-level injectors
|
||||
|
||||
### @NgModule 级注入器
|
||||
|
||||
You can configure a provider at the module level using the `providedIn` metadata option for a non-root NgModule, in order to limit the scope of the provider to that module.
|
||||
This is the equivalent of specifying the non-root module in the `@Injectable()` metadata, except that the service provided this way is not tree-shakable.
|
||||
|
||||
你还可以在非根 NgModule 元数据的 `providedIn` 选项中配置一个模块级的提供商,以便把该服务的范围限定到该模块一级。
|
||||
这和在 `@Injectable()` 元数据中指定一个非根模块是基本等效的,但以这种方式提供的服务无法被摇树优化掉。
|
||||
|
||||
You generally don't need to specify `AppModule` with `providedIn`, because the app's `root` injector is the `AppModule` injector.
|
||||
However, if you configure a app-wide provider in the`@NgModule()` metadata for `AppModule`,
|
||||
it overrides one configured for `root` in the `@Injectable()` metadata.
|
||||
You can do this to configure a non-default provider of a service that is shared with multiple apps.
|
||||
|
||||
一般来说,你不必在 `providedIn` 中指定 `AppModule`,因为应用中的 `root` 注入器就是 `AppModule` 注入器。
|
||||
不过,如果你在 `AppModule` 的 `@NgModule()` 元数据中配置了全应用级的提供商,它就会覆盖通过 `@Injectable()` 配置的那一个。
|
||||
你可以用这种方式来为那些供多个应用使用的服务指定非默认的提供商。
|
||||
|
||||
Here is an example of the case where the component router configuration includes
|
||||
a non-default [location strategy](guide/router#location-strategy) by listing its provider
|
||||
in the `providers` list of the `AppModule`.
|
||||
|
||||
下面的例子中,通过把 [location 策略](guide/router#location-strategy) 的提供商添加到 `AppModule` 的 `providers` 列表中,为路由器配置了非默认的 [location 策略](guide/router#location-strategy)。
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/app.module.ts" region="providers" header="src/app/app.module.ts (providers)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
|
@ -137,25 +210,41 @@ in the `providers` list of the `AppModule`.
|
|||
|
||||
### @Component-level injectors
|
||||
|
||||
### @Component 级注入器
|
||||
|
||||
Individual components within an NgModule have their own injectors.
|
||||
You can limit the scope of a provider to a component and its children
|
||||
by configuring the provider at the component level using the `@Component` metadata.
|
||||
|
||||
NgModule 中每个组件都有它自己的注入器。
|
||||
通过使用 `@Component` 元数据在组件级配置某个提供商,你可以把这个提供商的范围限定到该组件及其子组件。
|
||||
|
||||
The following example is a revised `HeroesComponent` that specifies `HeroService` in its `providers` array. `HeroService` can provide heroes to instances of this component, or to any child component instances.
|
||||
|
||||
下面的例子是修改过的 `HeroesComponent`,它在 `providers` 数组中指定了 `HeroService`。`HeroService` 可以像该组件的实例以及任意子组件的实例提供英雄列表。
|
||||
|
||||
<code-example path="dependency-injection/src/app/heroes/heroes.component.1.ts" header="src/app/heroes/heroes.component.ts" linenums="false">
|
||||
</code-example>
|
||||
|
||||
### Element injectors
|
||||
|
||||
### 元素注入器
|
||||
|
||||
An injector does not actually belong to a component, but rather to the component instance's anchor element in the DOM. A different component instance on a different DOM element uses a different injector.
|
||||
|
||||
注入器本质上并不属于组件,而是 DOM 中该组件实例所附着到的元素。另一个 DOM 元素上的其它组件实例则会使用另一个注入器。
|
||||
|
||||
Components are a special type of directive, and the `providers` property of
|
||||
`@Component()` is inherited from `@Directive()`.
|
||||
Directives can also have dependencies, and you can configure providers
|
||||
in their `@Directive()` metadata.
|
||||
When you configure a provider for a component or directive using the `providers` property, that provider belongs to the injector for the anchor DOM element. Components and directives on the same element share an injector.
|
||||
|
||||
组件是一种特殊的指令,`@Component()` 中的 `providers` 属性是从 `@Directive()` 中继承来的。
|
||||
指令也能拥有依赖,并且你也可以在它们的 `@Directive()` 元数据中配置提供商。
|
||||
当你使用 `providers` 属性为组件或指令配置提供商时,该提供商属于所在 DOM 元素的那个注入器。
|
||||
同一个元素上的组件与指令共享同一个注入器。
|
||||
|
||||
<!--- TBD with examples
|
||||
* For an example of how this works, see [Element-level providers](guide/dependency-injection-in-action#directive-level-providers).
|
||||
--->
|
||||
|
@ -163,16 +252,19 @@ When you configure a provider for a component or directive using the `providers`
|
|||
* Learn more about [Element Injectors in Angular](https://blog.angularindepth.com/a-curios-case-of-the-host-decorator-and-element-injectors-in-angular-582562abcf0a).
|
||||
|
||||
|
||||
欲知详情,参见[Angular 中的元素注入器](https://blog.angularindepth.com/a-curios-case-of-the-host-decorator-and-element-injectors-in-angular-582562abcf0a)。
|
||||
|
||||
## Injector bubbling
|
||||
|
||||
## 注入器冒泡
|
||||
|
||||
Consider this guide's variation on the Tour of Heroes application.
|
||||
At the top is the `AppComponent` which has some subcomponents, such as the `HeroesListComponent`.
|
||||
The `HeroesListComponent` holds and manages multiple instances of the `HeroTaxReturnComponent`.
|
||||
The following diagram represents the state of this three-level component tree when there are three instances of `HeroTaxReturnComponent`
|
||||
open simultaneously.
|
||||
|
||||
考虑《英雄指南》应用的一个简单变种。它的顶层是 `AppComponent` 组件,它有一些子组件。
|
||||
考虑《英雄指南》应用的一个简单变种。它的顶层是 `AppComponent` 组件,它还有一些子组件,比如 `HeroesListComponent`。
|
||||
`HeroesListComponent` 组件保存和管理着 `HeroTaxReturnComponent` 的多个实例。
|
||||
下图展示了当 `HeroesCardComponent` 的三个 `HeroTaxReturnComponent` 实例同时展开时的三级组件树状态。
|
||||
|
||||
|
@ -188,12 +280,14 @@ If it runs out of ancestors, Angular throws an error.
|
|||
|
||||
当一个组件申请获得一个依赖时,Angular 先尝试用该组件自己的注入器来满足它。
|
||||
如果该组件的注入器没有找到对应的提供商,它就把这个申请转给它父组件的注入器来处理。
|
||||
如果那个注入器也无法满足这个申请,它就继续转给*它的*父组件的注入器。
|
||||
如果那个注入器也无法满足这个申请,它就继续转给它在注入器树中的父注入器。
|
||||
这个申请继续往上冒泡 —— 直到找到了一个能处理此申请的注入器或者超出了组件树中的祖先位置为止。
|
||||
如果超出了组件树中的祖先还未找到,Angular 就会抛出一个错误。
|
||||
|
||||
If you have registered a provider for the same DI token at different levels, the first one Angular encounters is the one it uses to provide the dependency. If, for example, a provider is registered locally in the component that needs a service, Angular doesn't look for another provider of the same service.
|
||||
|
||||
如果你在不同的层级上为同一个 DI 令牌注册了提供商,那么 Angular 所碰到的第一个注入器就会用来提供该依赖。
|
||||
比如,如果提供商注册在该组件的本地注入器上,那么当该组件需要这个服务时,Angular 就不会去找能提供同一服务的其它提供商。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
|
@ -201,15 +295,25 @@ You can cap the bubbling by adding the `@Host()` parameter decorator on the depe
|
|||
in a component's constructor.
|
||||
The hunt for providers stops at the injector for the host element of the component.
|
||||
|
||||
你可以通过在构造函数的依赖项参数上添加参数装饰器 `@Host()` 来限制冒泡。
|
||||
当搜索提供商时,就会在组件宿主元素的注入器处停下。
|
||||
|
||||
* See an [example](guide/dependency-injection-in-action#qualify-dependency-lookup) of using `@Host` together with `@Optional`, another parameter decorator that lets you handle the null case if no provider is found.
|
||||
|
||||
参见这个同时使用 `@Host` 和 `@Optional` 的[例子](guide/dependency-injection-in-action#qualify-dependency-lookup),另一个参数装饰器 `@Optional` 让你能在没有找到提供商时把参数置为 null。
|
||||
|
||||
* Learn more about the [`@Host` decorator and Element Injectors](https://blog.angularindepth.com/a-curios-case-of-the-host-decorator-and-element-injectors-in-angular-582562abcf0a).
|
||||
|
||||
到 [`@Host` 装饰器与元素注入器](https://blog.angularindepth.com/a-curios-case-of-the-host-decorator-and-element-injectors-in-angular-582562abcf0a) 中了解更多。
|
||||
|
||||
</div>
|
||||
|
||||
If you only register providers with the root injector at the top level (typically the root `AppModule`), the tree of injectors appears to be flat.
|
||||
All requests bubble up to the root injector, whether you configured it with the `bootstrapModule` method, or registered all providers with `root` in their own services.
|
||||
|
||||
如果你只在顶级的根注入器(通常为根模块 `AppModule`)上注册提供商,则注入器树看起来就是扁平的。
|
||||
无论你使用 `bootstrapModule` 方法配置它,还是在自己的服务中使用 `root` 注册了这些提供商,所有的请求都会冒泡到根注入器上。
|
||||
|
||||
{@a component-injectors}
|
||||
|
||||
## Component injectors
|
||||
|
@ -220,6 +324,7 @@ The ability to configure one or more providers at different levels opens up inte
|
|||
The guide sample offers some scenarios where you might want to do so.
|
||||
|
||||
在不同层次上重新配置一个或多个提供商的能力,开启了一些既有趣又有用的可能性。
|
||||
本指南中的例子提供了一些你可能会用到它的场景。
|
||||
|
||||
### Scenario: service isolation
|
||||
|
||||
|
@ -232,11 +337,16 @@ Architectural reasons may lead you to restrict access to a service to the applic
|
|||
For example, the guide sample includes a `VillainsListComponent` that displays a list of villains.
|
||||
It gets those villains from a `VillainsService`.
|
||||
|
||||
比如,这个例子中包括一个用于显示反派列表的 `VillainsListComponent`,它会从 `VillainsService` 中获得反派列表数据。
|
||||
|
||||
If you provide `VillainsService` in the root `AppModule` (where you registered the `HeroesService`),
|
||||
that would make the `VillainsService` available everywhere in the application, including the _Hero_ workflows. If you later modified the `VillainsService`, you could break something in a hero component somewhere. Providing the service in the root `AppModule` creates that risk.
|
||||
|
||||
如果你在根模块 `AppModule` 中(也就是你注册 `HeroesService` 的地方)提供 `VillainsService`,就会让应用中的任何地方都能访问到 `VillainsService`,包括针对英雄的工作流。如果你稍后修改了 `VillainsService`,就可能破坏了英雄组件中的某些地方。在根模块 `AppModule` 中提供该服务将会引入此风险。
|
||||
|
||||
Instead, you can provide the `VillainsService` in the `providers` metadata of the `VillainsListComponent` like this:
|
||||
|
||||
该怎么做呢?你可以在 `VillainsListComponent` 的 `providers` 元数据中提供 `VillainsService`,就像这样:
|
||||
|
||||
<code-example path="hierarchical-dependency-injection/src/app/villains-list.component.ts" linenums="false" header="src/app/villains-list.component.ts (metadata)" region="metadata">
|
||||
|
||||
|
@ -301,10 +411,10 @@ 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 could delegate that management to a helper service, as this example does.
|
||||
|
||||
实现方式之一就是让 `HeroTaxReturnComponent` 有逻辑来管理和还原那些更改。
|
||||
假设 `HeroTaxReturnComponent` 还有一些管理并还原这些更改的逻辑。
|
||||
这对于简单的报税单来说是很容易的。
|
||||
不过,在现实世界中,报税单的数据模型非常复杂,对这些修改的管理可能不得不投机取巧。
|
||||
于是你可以把这种管理任务委托给一个辅助服务,就像这个例子中所做的。
|
||||
你可以把这种管理任务委托给一个辅助服务,就像这个例子中所做的。
|
||||
|
||||
Here is the `HeroTaxReturnService`.
|
||||
It caches a single `HeroTaxReturn`, tracks changes to that return, and can save or restore it.
|
||||
|
@ -340,10 +450,13 @@ The component also asks the service to save and restore this tax return.
|
|||
This won't work if the service is an application-wide singleton.
|
||||
Every component would share the same service instance, and each component would overwrite the tax return that belonged to another hero.
|
||||
|
||||
如果*这个*服务是一个全应用范围的单例,每个组件就都会共享同一个服务实例,每个组件也都会覆盖属于其他英雄的报税单。
|
||||
但如果该服务是一个全应用范围的单例就不行了。
|
||||
每个组件就都会共享同一个服务实例,每个组件也都会覆盖属于其他英雄的报税单。
|
||||
|
||||
To prevent this, we configure the component-level injector of `HeroTaxReturnComponent` to provide the service, using the `providers` property in the component metadata.
|
||||
|
||||
要防止这一点,我们就要在 `HeroTaxReturnComponent` 元数据的 `providers` 属性中配置组件级的注入器,来提供该服务。
|
||||
|
||||
<code-example path="hierarchical-dependency-injection/src/app/hero-tax-return.component.ts" linenums="false" header="src/app/hero-tax-return.component.ts (providers)" region="providers">
|
||||
|
||||
</code-example>
|
||||
|
@ -354,8 +467,7 @@ Providing the service at the component level ensures that _every_ instance of th
|
|||
|
||||
`HeroTaxReturnComponent` 有它自己的 `HeroTaxReturnService` 提供商。
|
||||
回忆一下,每个组件的*实例*都有它自己的注入器。
|
||||
在组件级提供服务可以确保组件的*每个*实例都得到一个自己的、私有的服务实例。
|
||||
报税单不会再被意外覆盖,这下清楚了。
|
||||
在组件级提供服务可以确保组件的*每个*实例都得到一个自己的、私有的服务实例,而报税单也不会再被意外覆盖了。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
|
@ -374,13 +486,13 @@ You can review it and download it from the <live-example></live-example>.
|
|||
|
||||
Another reason to re-provide a service at another level is to substitute a _more specialized_ implementation of that service, deeper in the component tree.
|
||||
|
||||
重新提供服务的另一个原因,是在组件树的深层中把该服务替换为一个*更特殊的*实现。
|
||||
在其它层级重新提供服务的另一个理由,是在组件树的深层中把该服务替换为一个*更专门化的*实现。
|
||||
|
||||
Consider a Car component that depends on several services.
|
||||
Suppose you configured the root injector (marked as A) with _generic_ providers for
|
||||
`CarService`, `EngineService` and `TiresService`.
|
||||
|
||||
再次考虑[依赖注入](guide/dependency-injection)一章中车辆(Car)的例子。
|
||||
考虑一个依赖于一系列服务的 Car 组件。
|
||||
假设你在根注入器(代号 A)中配置了*通用的*提供商:`CarService`、`EngineService` 和 `TiresService`。
|
||||
|
||||
You create a car component (A) that displays a car constructed from these three generic services.
|
||||
|
|
|
@ -36,7 +36,8 @@ Angular 简化了国际化工作的下列几个方面:
|
|||
|
||||
* Preparing text in component templates for translation.
|
||||
|
||||
翻译组件模板中的文本。
|
||||
准备组件模板中待翻译的文本。
|
||||
|
||||
* Handling plural forms of words.
|
||||
|
||||
处理单词的复数形式。
|
||||
|
@ -497,6 +498,8 @@ 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>"` 语法来给它写上含义(meaning)、描述(description)和 id。
|
||||
|
||||
## Regular expressions for plurals and selections
|
||||
|
||||
## 复数与选择的表达式
|
||||
|
@ -614,7 +617,7 @@ for two, three, or any other number if the pluralization rules were different. F
|
|||
|
||||
### Select among alternative text messages
|
||||
|
||||
## 在候选文本中选择
|
||||
### 在候选文本中选择
|
||||
|
||||
If your template needs to display different text messages depending on the value of a variable, you
|
||||
need to translate all of those alternative text messages.
|
||||
|
@ -641,7 +644,7 @@ The message maps those values to the appropriate translations:
|
|||
|
||||
### Nesting plural and select ICU expressions
|
||||
|
||||
## 把"复数"与"选择"表达式嵌套在一起
|
||||
### 把"复数"与"选择"表达式嵌套在一起
|
||||
|
||||
You can also nest different ICU expressions together, as shown in this example:
|
||||
|
||||
|
@ -670,7 +673,7 @@ Open a terminal window at the root of the app project and run the CLI command `x
|
|||
|
||||
By default, the command creates a file named `messages.xlf` in your `src/` folder.
|
||||
|
||||
本工具默认会生成一个名叫 `messages.xlf` 的翻译文件,格式为<a href="https://en.wikipedia.org/wiki/XLIFF" target="_blank">XML本土化互换文件格式(XLIFF, version 1.2)</a>。
|
||||
本工具默认会在你的 `src/` 目录下生成一个名叫 `messages.xlf` 的翻译文件。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
|
@ -681,7 +684,8 @@ If you don't use the CLI, you have two options:
|
|||
* You can use the `ng-xi18n` tool directly from the `@angular/compiler-cli` package.
|
||||
For more information, see the [`ng xi18n` command documentation](cli/xi18n).
|
||||
|
||||
你可以直接使用来自 `@angular/compiler-cli` 包中的 `ng-xi18n` 工具。更多信息,参见 [CLI 文档中的 i18n 部分](https://github.com/angular/angular-cli/wiki/xi18n)。
|
||||
你可以直接使用来自 `@angular/compiler-cli` 包中的 `ng-xi18n` 工具。更多信息,参见 [`ng xi18n` 命令的文档](cli/xi18n)。
|
||||
|
||||
* You can use the CLI Webpack plugin `AngularCompilerPlugin` from the `@ngtools/webpack` package.
|
||||
Set the parameters `i18nOutFile` and `i18nOutFormat` to trigger the extraction.
|
||||
For more information, see the [Angular Ahead-of-Time Webpack Plugin documentation](https://github.com/angular/angular-cli/tree/master/packages/%40ngtools/webpack).
|
||||
|
@ -731,7 +735,7 @@ Bundle (XMB)</a>
|
|||
You can specify the translation format explicitly with the `--i18nFormat` command option, as illustrated in
|
||||
these example commands:
|
||||
|
||||
你可以使用 `--i18nFormat` 来明确指定想用的格式,范例如下:
|
||||
你可以使用 `--i18nFormat` 选项明确指定想用的格式,范例如下:
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
ng xi18n --i18n-format=xlf
|
||||
|
@ -755,7 +759,7 @@ The sample in this guide uses the default XLIFF 1.2 format.
|
|||
You can change the name of the translation source file that is generated by the extraction tool with
|
||||
the `--outFile` command option:
|
||||
|
||||
你还可以使用 `--out-file` 参数来为提取工具生成的翻译源文件改名:
|
||||
你还可以使用 `--out-file` 选项来为提取工具生成的翻译源文件改名:
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
|
||||
|
@ -765,7 +769,7 @@ the `--outFile` command option:
|
|||
|
||||
You can specify the base locale of your app with the`--i18n-locale` command option:
|
||||
|
||||
你还可以使用 `--i18n-locale` 参数来指定应用的基本地区:
|
||||
你还可以使用 `--i18n-locale` 选项来指定应用的基本地区:
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
|
||||
|
@ -782,16 +786,17 @@ file. This information is not used by Angular, but external translation tools ma
|
|||
|
||||
## Translate the source text
|
||||
|
||||
## 翻译文本信息
|
||||
## 翻译源文本
|
||||
|
||||
The `ng xi18n` command generates a translation source file named `messages.xlf` in the project `src`
|
||||
folder.
|
||||
`ng xi18n` 命令会在项目根目录生成一个名为 `messages.xlf` 的翻译源文件。
|
||||
|
||||
`ng xi18n` 命令会在项目的 `src` 目录下生成一个名为 `messages.xlf` 的翻译源文件。
|
||||
|
||||
The next step is to translate the display strings in this source file into language-specific
|
||||
translation files. The example in this guide creates a French translation file.
|
||||
|
||||
下一步是将英文模板文本翻译到指定语言的翻译文件。
|
||||
下一步是将要显示的字符串翻译到指定语言的翻译文件。
|
||||
这个例子中创建了一个法语翻译文件。
|
||||
|
||||
{@a localization-folder}
|
||||
|
@ -1067,9 +1072,10 @@ The sample app and its translation file are now as follows:
|
|||
To merge the translated text into component templates, compile the app with the completed
|
||||
translation file.
|
||||
|
||||
Provide the Angular compiler with three translation-specific pieces of information:
|
||||
|
||||
要把已经翻译的文件合并到组件模板,就要用翻译过的文件编译应用。
|
||||
|
||||
Provide the Angular compiler with three translation-specific pieces of information:
|
||||
|
||||
为 Angular 编译器提供三种与翻译有关的信息:
|
||||
|
||||
* The translation file.
|
||||
|
@ -1111,7 +1117,7 @@ the JIT compiler or the AOT compiler.
|
|||
The [AOT compiler](guide/glossary#aot) is part of a build process that produces a small, fast,
|
||||
ready-to-run application package, typically for production.
|
||||
|
||||
AOT(*预先*)编译器是构建过程的一部分,它可以生成又小又快,直接可用的应用包。
|
||||
AOT(*预先*)编译器是构建过程的一部分,它可以生成又小又快,直接可用的应用包,通常是打产品包。
|
||||
|
||||
When you internationalize with the AOT compiler, you must pre-build a separate application
|
||||
package for each language and serve the appropriate package based on either server-side language
|
||||
|
@ -1179,6 +1185,8 @@ sections of this guide:
|
|||
For production builds, you define a separate `production-fr` build configuration in
|
||||
the CLI configuration file, `angular.json`.
|
||||
|
||||
要进行产品环境构建,就要在 CLI 的配置文件 `angular.json` 中定义一个独立的 `production-fr` 构建选项。
|
||||
|
||||
```
|
||||
...
|
||||
"architect": {
|
||||
|
@ -1224,10 +1232,10 @@ The same configuration options can also be provided through the CLI with your ex
|
|||
|
||||
### 用 JIT 编译器合并
|
||||
|
||||
The [JITcompiler](guide/glossary#jit) compiles your app in the browser as the app loads.
|
||||
The [JIT compiler](guide/glossary#jit) compiles your app in the browser as the app loads.
|
||||
To support translation with the JIT compiler, you must do the following:
|
||||
|
||||
JIT(即时)编译器在应用程序加载时,在浏览器中编译应用。
|
||||
加载应用程序时,[即时(JIT)编译器](guide/glossary#jit)会在浏览器中编译应用。
|
||||
在使用 JIT 编译器的环境中翻译是一个动态的流程,包括:
|
||||
|
||||
1. Import the appropriate language translation file as a string constant.
|
||||
|
@ -1262,7 +1270,7 @@ while compiling the app:
|
|||
The Angular `bootstrapModule` method has a second `compilerOptions` parameter that can influence the
|
||||
behavior of the compiler. You can use it to specify the translation providers:
|
||||
|
||||
在下面的 `src/app/i18n-providers.ts` 文件的 `getTranslationProviders()` 函数中,根据用户的**语言环境**和对应的翻译文件构建这些提供商:
|
||||
Angular 的 `bootstrapModule` 方法具有第二参数 `compilerOptions`,它可以影响编译器的行为。你可以用它来指定翻译提供商:
|
||||
|
||||
<code-example path="i18n/doc-files/main.2.ts" header="src/main.ts">
|
||||
</code-example>
|
||||
|
@ -1324,11 +1332,18 @@ error:
|
|||
|
||||
### Build for multiple locales
|
||||
|
||||
### 为多种语言环境构建
|
||||
|
||||
When you use the CLI `build` or `serve` command to build your application for different locales, change the output path using the `--outputPath` command option (along with the i18n-specific command options), so that the translation files are saved to different locations.
|
||||
When you are serving a locale-specific version from a subdirectory, you can also change the base URL used by your app by specifying the `--baseHref` option.
|
||||
|
||||
当你使用 CLI 的 `build` 或 `serve` 命令来为不同的语言环境构建应用时,可以使用 `--outputPath` 选项来更改输出路径,把这些翻译文件保存在不同的位置。
|
||||
当你通过子目录来为各个语言环境分别启动服务器时,你还要通过指定 `--baseHref` 选项来修改应用的基地址。
|
||||
|
||||
For example, if the French version of your application is served from https://myapp.com/fr/, configure the build for the French version as follows.
|
||||
|
||||
比如,如果应用的法语版运行在 https://myapp.com/fr/,可以像下面这样为法语版配置构建选项。
|
||||
|
||||
```
|
||||
"configurations": {
|
||||
"fr": {
|
||||
|
@ -1343,3 +1358,5 @@ For example, if the French version of your application is served from https://my
|
|||
```
|
||||
|
||||
For more details about how to create scripts to generate an app in multiple languages and how to set up Apache 2 to serve them from different subdirectories, read [this tutorial by Philippe Martin](https://medium.com/@feloy/deploying-an-i18n-angular-app-with-angular-cli-fc788f17e358#.1xq4iy6fp).
|
||||
|
||||
要了解如何创建脚本来为不同的语言环境生成应用,以及如何配置 Apache 2 来从不同的子目录下启动服务,请阅读 [Philippe Martin 写的这份教程](https://medium.com/@feloy/deploying-an-i18n-angular-app-with-angular-cli-fc788f17e358#.1xq4iy6fp)。
|
||||
|
|
|
@ -241,7 +241,7 @@ In `AppRoutingModule`, update the `routes` array with the following:
|
|||
|
||||
The import statements stay the same. The first two paths are the routes to the `CustomersModule` and the `OrdersModule` respectively. Notice that the lazy loading syntax uses `loadChildren` followed by a string that is the relative path to the module, a hash mark or `#`, and the module’s class name.
|
||||
|
||||
这些 `import` 语句没有变化。前两个路径分别路由到了 `CustomersModule` 和 `OrdersModule`。注意看惰性加载的语法:`loadChildren` 后面紧跟着一个字符串,它指向模块路径,然后是一个 `#`,然后是该模块的类名。
|
||||
这些 `import` 语句没有变化。前两个路径分别路由到了 `CustomersModule` 和 `OrdersModule`。注意看惰性加载的语法:`loadChildren` 后面紧跟着一个字符串,它指向模块的相对路径,然后是一个 `#`,然后是该模块的类名。
|
||||
|
||||
### Inside the feature module
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ NgModule 是一些带有 `@NgModule` 装饰器的类。`@NgModule` 装饰器的
|
|||
|
||||
The `AppModule` generated from the [Angular CLI](cli) demonstrates both kinds of modules in action:
|
||||
|
||||
Angular CLI 生成的 `AppModule` 实际演示了这两种模块:
|
||||
[Angular CLI](cli) 生成的 `AppModule` 实际演示了这两种模块:
|
||||
|
||||
```typescript
|
||||
|
||||
|
|
|
@ -132,7 +132,7 @@ Typically you don’t interact with the compiler directly; rather, you use it in
|
|||
|
||||
**@angular/http**: Angular's old, deprecated, HTTP client.
|
||||
|
||||
**@angular/http**:Angular 的老的、很快就会废弃的 HTTP 客户端库。
|
||||
**@angular/http**:Angular 的老的、已废弃的 HTTP 客户端库。
|
||||
|
||||
**@angular/platform-browser**: Everything DOM and browser related, especially
|
||||
the pieces that help render into the DOM.
|
||||
|
@ -140,7 +140,7 @@ This package also includes the `bootstrapModuleFactory()` 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) 进行编译的应用程序。
|
||||
这个包还包含 `bootstrapModuleFactory()` 方法,用来引导那些在产品构建时要用 [AOT](guide/aot-compiler) 进行编译的应用程序。
|
||||
|
||||
**@angular/platform-browser-dynamic**: Includes [Providers](api/core/Provider)
|
||||
and methods to compile and run the app on the client
|
||||
|
|
|
@ -80,11 +80,11 @@ In order to show how subscribing works, we need to create a new observable. Ther
|
|||
|
||||
* `of(...items)`—Returns an `Observable` instance that synchronously delivers the values provided as arguments.
|
||||
|
||||
`Observable.of(...items)` —— 返回一个 `Observable` 实例,它用同步的方式把参数中提供的这些值发送出来。
|
||||
`of(...items)` —— 返回一个 `Observable` 实例,它用同步的方式把参数中提供的这些值发送出来。
|
||||
|
||||
* `from(iterable)`—Converts its argument to an `Observable` instance. This method is commonly used to convert an array to an observable.
|
||||
|
||||
`Observable.from(iterable)` —— 把它的参数转换成一个 `Observable` 实例。
|
||||
`from(iterable)` —— 把它的参数转换成一个 `Observable` 实例。
|
||||
该方法通常用于把一个数组转换成一个(发送多个值的)可观察对象。
|
||||
|
||||
</div>
|
||||
|
@ -125,7 +125,7 @@ Use the `Observable` constructor to create an observable stream of any type. The
|
|||
|
||||
For example, to create an observable equivalent to the `of(1, 2, 3)` above, you could do something like this:
|
||||
|
||||
比如,要创建一个与前面的 `Observable.of(1, 2, 3)` 等价的可观察对象,你可以这样做:
|
||||
比如,要创建一个与前面的 `of(1, 2, 3)` 等价的可观察对象,你可以这样做:
|
||||
|
||||
<code-example path="observables/src/creating.ts" region="subscriber" header="Create observable with constructor"></code-example>
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ A provider is an instruction to the DI system on how to obtain a value for a dep
|
|||
|
||||
If you already have an app that was created with the [Angular CLI](cli), you can create a service using the [`ng generate`](cli/generate) CLI command in the root project directory. Replace _User_ with the name of your service.
|
||||
|
||||
如果你是用 CLI 创建的应用,那么可以使用下列 CLI 命令在项目根目录下创建一个服务。把其中的 `User` 替换成你的服务名。
|
||||
如果你是用 [Angular CLI](cli) 创建的应用,那么可以使用下列 CLI 的 [`ng generate`](cli/generate) 命令在项目根目录下创建一个服务。把其中的 `User` 替换成你的服务名。
|
||||
|
||||
```sh
|
||||
|
||||
|
@ -168,7 +168,8 @@ You may also be interested in:
|
|||
|
||||
* [Tree-shakable Providers](guide/dependency-injection-providers#tree-shakable-providers).
|
||||
|
||||
[可摇树优化的服务提供商](guide/dependency-injection#tree-shakable-providers)。
|
||||
[可摇树优化的服务提供商](guide/dependency-injection-providers#tree-shakable-providers)。
|
||||
|
||||
* [NgModule FAQ](guide/ngmodule-faq).
|
||||
|
||||
[NgModule 常见问题](guide/ngmodule-faq)。
|
||||
|
|
|
@ -1,52 +1,85 @@
|
|||
# Getting started
|
||||
|
||||
# 快速上手
|
||||
|
||||
Welcome to Angular! Angular helps you build modern applications for the web, mobile, or desktop.
|
||||
|
||||
欢迎使用 Angular!Angular 可以帮助你为 Web、移动端或桌面构建现代应用程序。
|
||||
|
||||
This guide shows you how to build and run a simple Angular
|
||||
app. You'll use the [Angular CLI tool](cli "CLI command reference") to accelerate development,
|
||||
while adhering to the [Style Guide](guide/styleguide "Angular style guide") recommendations that
|
||||
benefit _every_ Angular project.
|
||||
|
||||
本指南会介绍如何构建并运行一个简单的 Angular 应用。
|
||||
你将使用 [Angular CLI 工具](cli "CLI command reference")来加速开发,同时学着遵守[风格指南](guide/styleguide "Angular style guide")中的建议,这些建议将使*每一个* Angular 应用受益。
|
||||
|
||||
This guide takes less than 30 minutes to complete.
|
||||
At the end of this guide—as part of final code review—there is a link to download a copy of the final application code. (If you don't execute the commands in this guide, you can still download the final application code.)
|
||||
|
||||
|
||||
本指南只要不到 30 分钟即可完成。本指南的末尾(作为最终代码回顾的一部分)提供了一个链接,你可以去下载最终应用代码的一份复本。(即使你不执行本章的这些命令,仍然可以直接下载这份最终版的应用代码)
|
||||
|
||||
{@a devenv}
|
||||
{@a prerequisites}
|
||||
## Prerequisites
|
||||
|
||||
## 先决条件
|
||||
|
||||
Before you begin, make sure your development environment includes `Node.js®` and an npm package manager.
|
||||
|
||||
在开始之前,请确保你的开发环境已经包含了 `Node.js®` 和 npm 包管理器。
|
||||
|
||||
{@a nodejs}
|
||||
### Node.js
|
||||
|
||||
Angular requires `Node.js` version 8.x or 10.x.
|
||||
|
||||
Angular 需要 `Node.js` 的 8.x 或 10.x 版本。
|
||||
|
||||
* To check your version, run `node -v` in a terminal/console window.
|
||||
|
||||
要想检查你的版本,请在终端/控制台窗口中运行 `node -v` 命令。
|
||||
|
||||
* To get `Node.js`, go to [nodejs.org](https://nodejs.org "Nodejs.org").
|
||||
|
||||
要想安装 `Node.js`,请访问 [nodejs.org](https://nodejs.org "Nodejs.org")。
|
||||
|
||||
{@a npm}
|
||||
### npm package manager
|
||||
|
||||
### npm 包管理器
|
||||
|
||||
Angular, the Angular CLI, and Angular apps depend on features and functionality provided by libraries that are available as [npm packages](https://docs.npmjs.com/getting-started/what-is-npm). To download and install npm packages, you must have an npm package manager.
|
||||
|
||||
Angular、Angular CLI 和 Angular 应用都依赖于由一些库所提供的特性和功能,它们主要是 [npm 包](https://docs.npmjs.com/getting-started/what-is-npm)。要下载和安装 npm 包,你必须拥有一个 npm 包管理器。
|
||||
|
||||
This Quick Start uses the [npm client](https://docs.npmjs.com/cli/install) command line interface, which is installed with `Node.js` by default.
|
||||
|
||||
本 "快速上手" 中使用的是 [npm 客户端](https://docs.npmjs.com/cli/install)命令行界面,它已经在安装 `Node.js` 时默认安装上了。
|
||||
|
||||
To check that you have the npm client installed, run `npm -v` in a terminal/console window.
|
||||
|
||||
要想检查你是否已经安装了 npm 客户端,请在终端/控制台窗口中运行 `npm -v` 命令。
|
||||
|
||||
{@a install-cli}
|
||||
|
||||
## Step 1: Install the Angular CLI
|
||||
|
||||
## 第一步:安装 Angular CLI
|
||||
|
||||
You use the Angular CLI
|
||||
to create projects, generate application and library code, and perform a variety of ongoing development tasks such as testing, bundling, and deployment.
|
||||
|
||||
你要用 Angular CLI 来创建项目、创建应用和库代码,并执行多种开发任务,比如测试、打包和发布。
|
||||
|
||||
Install the Angular CLI globally.
|
||||
|
||||
全局安装 Angular CLI。
|
||||
|
||||
To install the CLI using `npm`, open a terminal/console window and enter the following command:
|
||||
|
||||
要想使用 `npm` 来安装 CLI,请打开终端/控制台窗口,并输入下列命令:
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
npm install -g @angular/cli
|
||||
|
@ -59,12 +92,22 @@ To install the CLI using `npm`, open a terminal/console window and enter the fol
|
|||
|
||||
## Step 2: Create a workspace and initial application
|
||||
|
||||
## 第二部:创建工作空间和初始应用
|
||||
|
||||
You develop apps in the context of an Angular [**workspace**](guide/glossary#workspace). A workspace contains the files for one or more [**projects**](guide/glossary/#project). A project is the set of files that comprise an app, a library, or end-to-end (e2e) tests.
|
||||
|
||||
Angular [**工作空间**](guide/glossary#workspace)就是你开发应用的上下文环境。
|
||||
每个工作空间包含一些供一个或多个[**项目**](guide/glossary/#project)使用的文件。
|
||||
每个项目都是一组由应用、库或端到端(e2e)测试构成的文件。
|
||||
|
||||
To create a new workspace and initial app project:
|
||||
|
||||
要想创建工作空间和初始应用项目:
|
||||
|
||||
1. Run the CLI command `ng new` and provide the name `my-app`, as shown here:
|
||||
|
||||
运行 CLI 命令 `ng new`,并提供一个名字 `my-app`,如下所示:
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
ng new my-app
|
||||
|
||||
|
@ -72,27 +115,54 @@ To create a new workspace and initial app project:
|
|||
|
||||
2. The `ng new` command prompts you for information about features to include in the initial app project. Accept the defaults by pressing the Enter or Return key.
|
||||
|
||||
`ng new` 会提示你要把哪些特性包含在初始的应用项目中。请按 Enter 或 Return 键接受默认值。
|
||||
|
||||
The Angular CLI installs the necessary Angular npm packages and other dependencies. This can take a few minutes.
|
||||
|
||||
Angular CLI 会安装必要的 Angular npm 包及其它依赖。这可能要花几分钟。
|
||||
|
||||
It also creates the following workspace and starter project files:
|
||||
|
||||
还将创建下列工作空间和初始项目文件:
|
||||
|
||||
* A new workspace, with a root folder named `my-app`
|
||||
|
||||
一个新的工作空间,根目录名叫 `my-app`
|
||||
|
||||
* An initial skeleton app project, also called `my-app` (in the `src` subfolder)
|
||||
|
||||
一个初始的骨架应用项目,也叫 `my-app`(但位于 `src` 子目录下)
|
||||
|
||||
* An end-to-end test project (in the `e2e` subfolder)
|
||||
|
||||
一个端到端测试项目(位于 `e2e` 子目录下)
|
||||
|
||||
* Related configuration files
|
||||
|
||||
相关的配置文件
|
||||
|
||||
The initial app project contains a simple Welcome app, ready to run.
|
||||
|
||||
初始的应用项目是一个简单的 "欢迎" 应用,随时可以运行它。
|
||||
|
||||
{@a serve}
|
||||
|
||||
## Step 3: Serve the application
|
||||
|
||||
## 步骤 3:启动开发服务器
|
||||
|
||||
Angular includes a server, so that you can easily build and serve your app locally.
|
||||
|
||||
Angular 包含一个开发服务器,以便你能在本地轻松地构建应用和启动开发服务器。
|
||||
|
||||
1. Go to the workspace folder (`my-app`).
|
||||
|
||||
进入工作空间目录(`my-app`)。
|
||||
|
||||
1. Launch the server by using the CLI command `ng serve`, with the `--open` option.
|
||||
|
||||
使用 CLI 命令 `ng serve` 启动开发服务器,并带上 `--open` 选项。
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
cd my-app
|
||||
ng serve --open
|
||||
|
@ -101,11 +171,16 @@ Angular includes a server, so that you can easily build and serve your app local
|
|||
The `ng serve` command launches the server, watches your files,
|
||||
and rebuilds the app as you make changes to those files.
|
||||
|
||||
`ng serve` 命令会自动开发服务器,并监视你的文件变化,当你修改这些文件时,它就会重新构建应用。
|
||||
|
||||
The `--open` (or just `-o`) option automatically opens your browser
|
||||
to `http://localhost:4200/`.
|
||||
|
||||
`--open`(或只用 `-o`)选项会自动打开浏览器,并访问 `http://localhost:4200/`。
|
||||
|
||||
Your app greets you with a message:
|
||||
|
||||
看,你的应用使用一条消息在欢迎你:
|
||||
|
||||
<figure>
|
||||
<img src='generated/images/guide/cli-quickstart/app-works.png' alt="Welcome to my-app!">
|
||||
|
@ -117,25 +192,42 @@ Your app greets you with a message:
|
|||
|
||||
## Step 4: Edit your first Angular component
|
||||
|
||||
## 步骤 4:编辑你的第一个 Angular 组件
|
||||
|
||||
[**_Components_**](guide/glossary#component) are the fundamental building blocks of Angular applications.
|
||||
They display data on the screen, listen for user input, and take action based on that input.
|
||||
|
||||
[**组件**](guide/glossary#component) 是 Angular 应用中的基本构造块。
|
||||
它们在屏幕上显示数据、监听用户输入,并根据这些输入采取行动。
|
||||
|
||||
As part of the initial app, the CLI created the first Angular component for you. It is the _root component_, and it is named `app-root`.
|
||||
|
||||
作为初始应用的一部分,CLI 也会为你创建第一个 Angular 组件。它就是*根组件*,名叫 `app-root`。
|
||||
|
||||
1. Open `./src/app/app.component.ts`.
|
||||
|
||||
打开 `./src/app/app.component.ts`。
|
||||
|
||||
2. Change the `title` property from `'my-app'` to `'My First Angular App'`.
|
||||
|
||||
把 `title` 属性从 `'my-app'` 修改成 `'My First Angular App'`。
|
||||
|
||||
<code-example path="cli-quickstart/src/app/app.component.ts" region="component" header="src/app/app.component.ts" linenums="false"></code-example>
|
||||
|
||||
The browser reloads automatically with the revised title. That's nice, but it could look better.
|
||||
|
||||
浏览器将会用修改过的标题自动刷新。不错,但是还可以更好看。
|
||||
|
||||
3. Open `./src/app/app.component.css` and give the component some style.
|
||||
|
||||
打开 `./src/app/app.component.css` 并给这个组件提供一些样式。
|
||||
|
||||
<code-example path="cli-quickstart/src/app/app.component.css" header="src/app/app.component.css" linenums="false"></code-example>
|
||||
|
||||
Looking good!
|
||||
|
||||
看起来不错!
|
||||
|
||||
<figure>
|
||||
<img src='generated/images/guide/cli-quickstart/my-first-app.png' alt="Output of Getting Started app">
|
||||
</figure>
|
||||
|
@ -147,38 +239,56 @@ Looking good!
|
|||
|
||||
## Final code review
|
||||
|
||||
## 最终代码回顾
|
||||
|
||||
You can <a href="generated/zips/cli-quickstart/cli-quickstart.zip" target="_blank">download an example</a> of the app that you created in this Getting Started guide.
|
||||
|
||||
你可以<a href="generated/zips/cli-quickstart/cli-quickstart.zip" target="_blank">下载</a>在本章中创建的这个例子。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
**Tip:** Most Angular guides include links to download example files and run live examples in [Stackblitz](http://www.stackblitz.com), so that you can see Angular concepts and code in action.
|
||||
|
||||
**提示:** 这里的大多数章节中都包含同时下载范例文件和通过 [Stackblitz](http://www.stackblitz.com) 在线运行它的链接,这样你就能在实战中观察这些 Angular 的概念和代码。
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
For more information about Angular project files and the file structure, see [Workspace and project file struture](guide/file-structure).
|
||||
|
||||
|
||||
要了解关于 Angular 项目文件和文件结构的更多信息,请参见[工作空间与项目的文件结构](guide/file-structure)。
|
||||
|
||||
|
||||
## Next steps
|
||||
|
||||
## 下一步
|
||||
|
||||
Now that you've seen the essentials of an Angular app and the Angular CLI, continue with these other introductory materials:
|
||||
|
||||
现在,你已经了解了 Angular 和 Angular CLI 的基本元素,请访问下列介绍性素材以继续:
|
||||
|
||||
* The [Tour of Heroes tutorial](tutorial "Tour of Heroes tutorial") provides additional hands-on learning. It walks you through the steps to build an app that helps a staffing agency manage a group of superhero employees.
|
||||
It has many of the features you'd expect to find in a data-driven application:
|
||||
|
||||
- Acquiring and displaying a list of items
|
||||
[英雄指南教程](tutorial "Tour of Heroes tutorial")提供了更多手动练习。它将引导你完成构建应用程序的那些步骤。该应用程序可以帮助管理机构管理一些身为超级英雄的员工。
|
||||
它具有你期望在数据驱动的应用中能找到的许多特性:
|
||||
|
||||
- Editing a selected item's detail
|
||||
- Acquiring and displaying a list of items
|
||||
|
||||
- Navigating among different views of the data
|
||||
获取与现实条目的列表
|
||||
|
||||
- Editing a selected item's detail
|
||||
|
||||
编辑所选条目的详情
|
||||
|
||||
- Navigating among different views of the data
|
||||
|
||||
在数据的不同视图之间导航
|
||||
|
||||
* The [Architecture guide](guide/architecture "Architecture guide") describes key concepts such as modules, components, services, and dependency injection (DI). It provides a foundation for more in-depth guides about specific Angular concepts and features.
|
||||
|
||||
[架构](guide/architecture "Architecture guide")描述了一些关键概念,比如模块、组件、服务和依赖注入(DI)。它为你深入了解一些 Angular 专属的概念和特性奠定了基础。
|
||||
|
||||
After the Tutorial and Architecture guide, you'll be ready to continue exploring Angular on your own through the other guides and references in this documentation set, focusing on the features most important for your apps.
|
||||
|
||||
|
||||
在读完 "英雄指南" 和 "架构" 之后,你还可以通过本文档中的其它指南和参考资料自行探索 Angular,可以重点关注那些对你的应用至关重要的特性。
|
||||
|
|
|
@ -20,16 +20,16 @@ Try the <live-example title="Reactive Forms in Stackblitz">Reactive Forms live-e
|
|||
|
||||
Reactive forms use an explicit and immutable approach to managing the state of a form at a given point in time. Each change to the form state returns a new state, which maintains the integrity of the model between changes. Reactive forms are built around observable streams, where form inputs and values are provided as streams of input values, which can be accessed synchronously.
|
||||
|
||||
响应式表单使用显式的、不可变的方式,管理表单在特定的时间点上的状态。对表单状态的每一次变更都会返回一个新的状态,这样可以在变化时维护模型的整体性。响应式表单是围绕 Observable 的流构建的,表单的输入和值都是通过这些输入值组成的流来提供的,同时,也赋予你对数据进行同步访问的能力。这种方式允许你的模板利用这些表单的“状态变更流”,而不必依赖它们。
|
||||
响应式表单使用显式的、不可变的方式,管理表单在特定的时间点上的状态。对表单状态的每一次变更都会返回一个新的状态,这样可以在变化时维护模型的整体性。响应式表单是围绕 Observable 的流构建的,表单的输入和值都是通过这些输入值组成的流来提供的,它可以同步访问。
|
||||
|
||||
Reactive forms also provide a straightforward path to testing because you are assured that your data is consistent and predictable when requested. Any consumers of the streams have access to manipulate that data safely.
|
||||
|
||||
响应式表单还让你能更简单的进行测试,因为在请求的那一刻你可以确信这些数据是一致的、可预料的。模板之外的消费方也可以访问同样的流,它们可以安全地操纵这些数据。
|
||||
响应式表单还提供了一种更直白的测试路径,因为在请求时你可以确信这些数据是一致的、可预料的。这个流的任何一个消费者都可以安全地操纵这些数据。
|
||||
|
||||
Reactive forms differ from template-driven forms in distinct ways. Reactive forms provide more predictability with synchronous access to the data model, immutability with observable operators, and change tracking through observable streams. If you prefer direct access to modify data in your template, template-driven forms are less explicit because they rely on directives embedded in the template, along with mutable data to track changes asynchronously. See the [Forms Overview](guide/forms-overview) for detailed comparisons between the two paradigms.
|
||||
|
||||
响应式表单与模板驱动的表单有着显著的不同点。响应式表单通过对数据模型的同步访问提供了更多的可预测性,使用 Observable 的操作符提供了不可变性,并且通过 Observable 流提供了变化追踪功能。
|
||||
如果你更喜欢在模板中直接访问数据,那么模板驱动的表单会显得更明确,因为它们依赖嵌入到模板中的指令,并借助可变数据来异步跟踪变化。参见[附录](#appendix)来了解这两种范式之间的详细比较。
|
||||
如果你更喜欢在模板中直接访问数据,那么模板驱动的表单会显得更明确,因为它们依赖嵌入到模板中的指令,并借助可变数据来异步跟踪变化。参见[表单概览](guide/forms-overview)来了解这两种范式之间的详细比较。
|
||||
|
||||
## Getting started
|
||||
|
||||
|
@ -37,7 +37,7 @@ Reactive forms differ from template-driven forms in distinct ways. Reactive form
|
|||
|
||||
This section describes how to add a single form control. In the example, the user enters their name into an input field, captures that input value, and displays the current value of the form control element.
|
||||
|
||||
本节描述了添加单个表单控件的一些关键步骤。这里的例子允许用户在输入框中输入自己的名字,捕获输入的值,并把表单控件元素的当前值显示出来。
|
||||
本节描述了如何添加单个表单控件。这里的例子允许用户在输入框中输入自己的名字,捕获输入的值,并把表单控件元素的当前值显示出来。
|
||||
|
||||
### Step 1: Registering the reactive forms module
|
||||
|
||||
|
@ -53,7 +53,7 @@ To use reactive forms, import `ReactiveFormsModule` from the `@angular/forms` pa
|
|||
|
||||
### Step 2: Generating and importing a new form control
|
||||
|
||||
### 步骤 2 - 导入并创建一个新的表单控件
|
||||
### 步骤 2 - 生成并导入一个新的表单控件
|
||||
|
||||
Generate a component for the control.
|
||||
|
||||
|
@ -67,7 +67,7 @@ Generate a component for the control.
|
|||
|
||||
The `FormControl` class is the basic building block when using reactive forms. To register a single form control, import the `FormControl` class into your component and create a new instance of the form control to save as a class property.
|
||||
|
||||
当使用响应式表单时,`FormControl` 是最基本的构造块。要注册单个的表单控件,请在组件中导入 `FormControl` 类,并创建一个 `FormControl` 的新实例,把它保存在类的某个属性中。
|
||||
当使用响应式表单时,`FormControl` 类是最基本的构造块。要注册单个的表单控件,请在组件中导入 `FormControl` 类,并创建一个 `FormControl` 的新实例,把它保存在类的某个属性中。
|
||||
|
||||
<code-example path="reactive-forms/src/app/name-editor/name-editor.component.ts" region="create-control" header="src/app/name-editor/name-editor.component.ts">
|
||||
|
||||
|
@ -75,7 +75,7 @@ The `FormControl` class is the basic building block when using reactive forms. T
|
|||
|
||||
Use the constructor of `FormControl` to set its initial value, which in this case is an empty string. By creating these controls in your component class, you get immediate access to listen for, update, and validate the state of the form input.
|
||||
|
||||
`FormControl` 的构造函数可以设置初始值,这个例子中它是空字符串。通过在你的组件类中创建这些控件,你可以直接对表单控件的状态进行监听、修改和校验。
|
||||
可以用 `FormControl` 的构造函数设置初始值,这个例子中它是空字符串。通过在你的组件类中创建这些控件,你可以直接对表单控件的状态进行监听、修改和校验。
|
||||
|
||||
### Step 3: Registering the control in the template
|
||||
|
||||
|
@ -107,7 +107,7 @@ Using the template binding syntax, the form control is now registered to the `na
|
|||
|
||||
The form control assigned to `name` is displayed when the component is added to a template.
|
||||
|
||||
一旦把该组件添加到模板中,指派给 `name` 的 `FormControl` 就会显示出来。
|
||||
把该组件添加到模板时,将显示指派给 `name` 的表单控件。
|
||||
|
||||
<code-example path="reactive-forms/src/app/app.component.1.html" region="app-name-editor" linenums="false" header="src/app/app.component.html (name editor)">
|
||||
|
||||
|
@ -124,7 +124,7 @@ The form control assigned to `name` is displayed when the component is added to
|
|||
Reactive forms give you access to the form control state and value at a point in time. You can manipulate
|
||||
the current state and value through the component class or the component template. The following examples display the value of the form control instance and change it.
|
||||
|
||||
响应式表单让你可以访问表单控件此刻的状态和值。你可以通过组件类或组件模板来操纵其当前状态和值。下面的例子会显示及修改 `FormConrol` 的值。
|
||||
响应式表单让你可以访问表单控件此刻的状态和值。你可以通过组件类或组件模板来操纵其当前状态和值。下面的例子会显示及修改 `FormConrol` 实例的值。
|
||||
|
||||
{@a display-value}
|
||||
|
||||
|
@ -211,7 +211,7 @@ The form model is the source of truth for the control, so when you click the but
|
|||
|
||||
Just as a form control instance gives you control over a single input field, a form group instance tracks the form state of a group of form control instances (for example, a form). Each control in a form group instance is tracked by name when creating the form group. The following example shows how to manage multiple form control instances in a single group.
|
||||
|
||||
正如 `FormControl` 的实例能让你控制单个输入框所对应的控件,`FormGroup` 可以跟踪一组 `FormControl` 实例(比如一个表单)的表单状态。当创建 `FormGroup` 时,其中的每个控件都会根据其名字进行跟踪。下列例子展示了如何管理单个控件组中的多个 `FormControl` 实例。
|
||||
就像 `FormControl` 的实例能让你控制单个输入框所对应的控件一样,`FormGroup` 的实例也能跟踪一组 `FormControl` 实例(比如一个表单)的表单状态。当创建 `FormGroup` 时,其中的每个控件都会根据其名字进行跟踪。下列例子展示了如何管理单个控件组中的多个 `FormControl` 实例。
|
||||
|
||||
Generate a `ProfileEditor` component and import the `FormGroup` and `FormControl` classes from the `@angular/forms` package.
|
||||
|
||||
|
@ -229,7 +229,7 @@ Generate a `ProfileEditor` component and import the `FormGroup` and `FormControl
|
|||
|
||||
### Step 1: Creating a FormGroup instance
|
||||
|
||||
### 步骤 1 - 创建 `FormGroup`
|
||||
### 步骤 1 - 创建 `FormGroup` 实例
|
||||
|
||||
Create a property in the component class named `profileForm` and set the property to a new form group instance. To initialize the form group, provide the constructor with an object of named keys mapped to their control.
|
||||
|
||||
|
@ -292,7 +292,7 @@ The `onSubmit()` method in the `ProfileEditor` component captures the current va
|
|||
|
||||
The `submit` event is emitted by the `form` tag using the native DOM event. You trigger the event by clicking a button with `submit` type. This allows the user to press the **Enter** key to submit the completed form.
|
||||
|
||||
`form` 标签所发出的 `submit` 事件是原生 DOM 事件,通过点击类型为 `submit` 的按钮可以触发本事件。这还让用户可以在填写完表单之后使用回车键来触发提交。
|
||||
`form` 标签所发出的 `submit` 事件是原生 DOM 事件,通过点击类型为 `submit` 的按钮可以触发本事件。这还让用户可以用回车键来提交填完的表单。
|
||||
|
||||
Use a `button` element to add a button to the bottom of the form to trigger the form submission.
|
||||
|
||||
|
@ -344,7 +344,7 @@ When building complex forms, managing the different areas of information is easi
|
|||
|
||||
An address is a good example of information that can be grouped together. Form groups can accept both form control and form group instances as children. This makes composing complex form models easier to maintain and logically group together. To create a nested group in `profileForm`, add a nested `address` element to the form group instance.
|
||||
|
||||
“地址”就是可以把信息进行分组的绝佳范例。`FormGroup` 可以同时接纳 `FormControl` 和 `FormGroup` 作为子控件。这使得那些比较复杂的表单模型可以更易于维护、更有逻辑性。要想在 `profileForm` 中创建一个嵌套的分组,请添加一个内嵌的名叫 `address` 的 `FormGroup`。
|
||||
“地址”就是可以把信息进行分组的绝佳范例。`FormGroup` 可以同时接纳 `FormControl` 和 `FormGroup` 作为子控件。这使得那些比较复杂的表单模型可以更易于维护、更有逻辑性。要想在 `profileForm` 中创建一个嵌套的分组,请添加一个内嵌的名叫 `address` 的元素指向这个 `FormGroup` 实例。
|
||||
|
||||
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.ts" region="nested-formgroup" linenums="false" header="src/app/profile-editor/profile-editor.component.ts (nested form group)">
|
||||
|
||||
|
@ -392,7 +392,7 @@ The `ProfileEditor` form is displayed as one group, but the model is broken down
|
|||
|
||||
When updating the value for a form group instance that contains multiple controls, you may only want to update parts of the model. This section covers how to update specific parts of a form control data model.
|
||||
|
||||
当修改包含多个控件的 `FormGroup` 的值时,你可能只希望更新模型中的一部分,而不是完全替换掉。这一节会讲解该如何更新 `AbstractControl` 模型中的一部分。
|
||||
当修改包含多个 `FormGroup` 实例的值时,你可能只希望更新模型中的一部分,而不是完全替换掉。这一节会讲解该如何更新 `AbstractControl` 模型中的一部分。
|
||||
|
||||
### Patching the model value
|
||||
|
||||
|
@ -465,7 +465,7 @@ Import the `FormBuilder` class from the `@angular/forms` package.
|
|||
|
||||
The `FormBuilder` service is an injectable provider that is provided with the reactive forms module. Inject this dependency by adding it to the component constructor.
|
||||
|
||||
FormBuilder 是一个可注入的服务,它是由 `ReactiveFormModule` 提供的。只要把它添加到组件的构造函数中就可以注入这个依赖。
|
||||
`FormBuilder` 是一个可注入的服务提供商,它是由 `ReactiveFormModule` 提供的。只要把它添加到组件的构造函数中就可以注入这个依赖。
|
||||
|
||||
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.2.ts" region="inject-form-builder" header="src/app/profile-editor/profile-editor.component.ts (constructor)">
|
||||
|
||||
|
@ -501,7 +501,7 @@ In the example above, you use the `group()` method with the same object to defin
|
|||
|
||||
Compare using the form builder to creating the instances manually.
|
||||
|
||||
这两种方式达成了相同的效果。
|
||||
比较一下用表单构建器和手动创建实例这两种方式。
|
||||
|
||||
<code-tabs>
|
||||
|
||||
|
@ -702,7 +702,7 @@ The `*ngFor` directive iterates over each form control instance provided by the
|
|||
|
||||
Each time a new alias instance is added, the new form array instance is provided its control based on the index. This allows you to track each individual control when calculating the status and value of the root control.
|
||||
|
||||
每当新的 `alias` 加进来时,`FormArray` 就会基于这个索引号提供它的控件。这将允许你在每次计算根控件的状态和值时跟踪每个控件。
|
||||
每当新的 `alias` 加进来时,`FormArray` 的实例就会基于这个索引号提供它的控件。这将允许你在每次计算根控件的状态和值时跟踪每个控件。
|
||||
|
||||
#### Adding an alias
|
||||
|
||||
|
@ -910,7 +910,7 @@ Listed below are the base classes and services used to create and manage form co
|
|||
|
||||
Syncs `FormControl` in an existing `FormGroup` instance to a form control element by name.
|
||||
|
||||
把一个现有 `FormGroup` 中的 `FormControl` 根据名字绑定到表单控件元素。
|
||||
把一个现有 `FormGroup` 中的 `FormControl` 实例根据名字绑定到表单控件元素。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -928,7 +928,7 @@ Listed below are the base classes and services used to create and manage form co
|
|||
|
||||
Syncs an existing `FormGroup` instance to a DOM element.
|
||||
|
||||
把一个现有的 `FormGroup` 绑定到 DOM 元素。
|
||||
把一个现有的 `FormGroup` 实例绑定到 DOM 元素。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -946,7 +946,7 @@ Listed below are the base classes and services used to create and manage form co
|
|||
|
||||
Syncs a nested `FormGroup` instance to a DOM element.
|
||||
|
||||
把一个内嵌的 `FormGroup` 绑定到一个 DOM 元素。
|
||||
把一个内嵌的 `FormGroup` 实例绑定到一个 DOM 元素。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -964,7 +964,7 @@ Listed below are the base classes and services used to create and manage form co
|
|||
|
||||
Syncs a nested `FormArray` instance to a DOM element.
|
||||
|
||||
把一个内嵌的 `FormArray` 绑定到一个 DOM 元素。
|
||||
把一个内嵌的 `FormArray` 实例绑定到一个 DOM 元素。
|
||||
|
||||
</td>
|
||||
|
||||
|
|
|
@ -133,7 +133,7 @@ The following example creates five route definitions, configures the router via
|
|||
and adds the result to the `AppModule`'s `imports` array.
|
||||
|
||||
路由器需要先配置才会有路由信息。
|
||||
下面的例子创建了四个路由定义,并用 `RouterModule.forRoot` 方法来配置路由器,
|
||||
下面的例子创建了五个路由定义,并用 `RouterModule.forRoot` 方法来配置路由器,
|
||||
并把它的返回值添加到 `AppModule` 的 `imports` 数组中。
|
||||
|
||||
<code-example path="router/src/app/app.module.0.ts" linenums="false" header="src/app/app.module.ts (excerpt)">
|
||||
|
@ -266,17 +266,27 @@ The router resolves that array into a complete URL.
|
|||
|
||||
### Active router links
|
||||
|
||||
### 路由链接的激活状态
|
||||
|
||||
The `RouterLinkActive` directive toggles css classes for active `RouterLink` bindings based on the current `RouterState`.
|
||||
|
||||
`RouterLinkActive` 指令会基于当前的 `RouterState` 为活动的 `RouterLink` 切换所绑定的 css 类。
|
||||
|
||||
On each anchor tag, you see a [property binding](guide/template-syntax#property-binding) to the `RouterLinkActive` directive that look like `routerLinkActive="..."`.
|
||||
|
||||
在每个 A 标签上,你会看到一个到 `RouterLinkActive` 的[属性绑定](guide/template-syntax#property-binding),形如 `routerLinkActive="..."`。
|
||||
|
||||
The template expression to the right of the equals (=) contains a space-delimited string of CSS classes
|
||||
that the Router will add when this link is active (and remove when the link is inactive). You set the `RouterLinkActive`
|
||||
directive to a string of classes such as `[routerLinkActive]="'active fluffy'"` or bind it to a component
|
||||
property that returns such a string.
|
||||
|
||||
等号右边的模板表达式包含一些用空格分隔的 CSS 类名,当这个链接激活时,路由器将会把它们加上去(并在处于非活动状态时移除)。你还可以把 `RouterLinkActive` 设置为一个类组成的字符串,如 `[routerLinkActive]="'active fluffy'"`,或把它绑定到一个返回类似字符串的组件属性。
|
||||
|
||||
Active route links cascade down through each level of the route tree, so parent and child router links can be active at the same time. To override this behavior, you can bind to the `[routerLinkActiveOptions]` input binding with the `{ exact: true }` expression. By using `{ exact: true }`, a given `RouterLink` will only be active if its URL is an exact match to the current URL.
|
||||
|
||||
路由链接的激活状态会向下级联到路由树中的每个层级,所以,父子路由链接可能会同时激活。要覆盖这种行为,可以把 `[routerLinkActiveOptions]` 绑定为 `{ exact: true }` 表达式,这样 `RouterLink` 只有当 URL 与当前 URL 精确匹配时才会激活。
|
||||
|
||||
{@a basics-router-state}
|
||||
|
||||
### Router state
|
||||
|
@ -584,6 +594,8 @@ During each navigation, the `Router` emits navigation events through the `Router
|
|||
An [event](api/router/RouteConfigLoadStart) triggered before the `Router`
|
||||
[lazy loads](#asynchronous-routing) a route configuration.
|
||||
|
||||
本[事件](api/router/RouteConfigLoadStart)会在 `Router` [惰性加载](#asynchronous-routing) 某个路由配置之前触发。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
@ -595,6 +607,8 @@ During each navigation, the `Router` emits navigation events through the `Router
|
|||
|
||||
An [event](api/router/RouteConfigLoadEnd) triggered after a route has been lazy loaded.
|
||||
|
||||
本[事件](api/router/RouteConfigLoadEnd)会在惰性加载了某个路由后触发。
|
||||
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
@ -627,6 +641,8 @@ During each navigation, the `Router` emits navigation events through the `Router
|
|||
|
||||
An [event](api/router/GuardsCheckStart) triggered when the Router begins the Guards phase of routing.
|
||||
|
||||
本[事件](api/router/GuardsCheckStart)会在路由器开始 Guard 阶段之前触发。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
@ -638,6 +654,8 @@ During each navigation, the `Router` emits navigation events through the `Router
|
|||
|
||||
An [event](api/router/ChildActivationStart) triggered when the Router begins activating a route's children.
|
||||
|
||||
本[事件](api/router/ChildActivationStart)会在路由器开始激活路由的子路由时触发。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
@ -649,6 +667,8 @@ During each navigation, the `Router` emits navigation events through the `Router
|
|||
|
||||
An [event](api/router/ActivationStart) triggered when the Router begins activating a route.
|
||||
|
||||
本[事件](api/router/ActivationStart)会在路由器开始激活某个路由时触发。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
@ -660,6 +680,8 @@ During each navigation, the `Router` emits navigation events through the `Router
|
|||
|
||||
An [event](api/router/GuardsCheckEnd) triggered when the Router finishes the Guards phase of routing successfully.
|
||||
|
||||
本[事件](api/router/GuardsCheckEnd)会在路由器成功完成了 Guard 阶段时触发。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
@ -672,7 +694,7 @@ During each navigation, the `Router` emits navigation events through the `Router
|
|||
|
||||
An [event](api/router/ResolveStart) triggered when the Router begins the Resolve phase of routing.
|
||||
|
||||
本[事件](api/router/RouteConfigLoadStart)会在 `Router` 对一个路由配置进行[惰性加载](#asynchronous-routing)之前触发。
|
||||
本[事件](api/router/ResolveStart)会在 `Router` 开始解析(Resolve)阶段时触发。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -688,6 +710,8 @@ During each navigation, the `Router` emits navigation events through the `Router
|
|||
|
||||
An [event](api/router/ResolveEnd) triggered when the Router finishes the Resolve phase of routing successfuly.
|
||||
|
||||
本[事件](api/router/ResolveEnd)会在路由器成功完成了路由的解析(Resolve)阶段时触发。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
@ -700,6 +724,8 @@ During each navigation, the `Router` emits navigation events through the `Router
|
|||
|
||||
An [event](api/router/ChildActivationEnd) triggered when the Router finishes activating a route's children.
|
||||
|
||||
本[事件](api/router/ChildActivationEnd)会在路由器激活了路由的子路由时触发。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
@ -711,7 +737,7 @@ During each navigation, the `Router` emits navigation events through the `Router
|
|||
|
||||
An [event](api/router/ActivationStart) triggered when the Router finishes activating a route.
|
||||
|
||||
本[事件](api/router/RouteConfigLoadEnd)会在路由被惰性加载之后触发。
|
||||
本[事件](api/router/ActivationStart)会在路由器激活了某个路由时触发。
|
||||
|
||||
</td>
|
||||
|
||||
|
@ -780,6 +806,8 @@ During each navigation, the `Router` emits navigation events through the `Router
|
|||
|
||||
An [event](api/router/Scroll) that represents a scrolling event.
|
||||
|
||||
本[事件](api/router/Scroll)代表一个滚动事件。
|
||||
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
@ -1195,7 +1223,7 @@ Select a crisis and the application takes you to a crisis editing screen.
|
|||
The _Crisis Detail_ appears in a child component on the same page, beneath the list.
|
||||
|
||||
选择其中之一,该应用就会把你带到此危机的编辑页面。
|
||||
*危机详情*出现在了当前页的子视图区,也就是在列表的紧下方。
|
||||
*危机详情*是当前页的子组件,就在列表的紧下方。
|
||||
|
||||
Alter the name of a crisis.
|
||||
Notice that the corresponding name in the crisis list does _not_ change.
|
||||
|
@ -1252,7 +1280,7 @@ Proceed to the first application milestone.
|
|||
|
||||
## Milestone 1: Getting started
|
||||
|
||||
## 里程碑 1:从路由器开始
|
||||
## 里程碑 1:起步
|
||||
|
||||
Begin with a simple version of the app that navigates between two empty views.
|
||||
|
||||
|
@ -1305,9 +1333,12 @@ activates an instance of `CrisisListComponent`, displays its view, and updates t
|
|||
browser's address location and history with the URL for that path.
|
||||
|
||||
**当应用程序请求导航到路径 `/crisis-center` 时,路由器激活一个 `CrisisListComponent` 的实例,显示它的视图,并将该路径更新到浏览器地址栏和历史。**
|
||||
|
||||
The first configuration defines an array of two routes with simple paths leading to the
|
||||
`CrisisListComponent` and `HeroListComponent`. Generate the `CrisisList` and `HeroList` components.
|
||||
|
||||
第一个配置定义了由两个路由构成的数组,它们用简单的路径指向了 `CrisisListComponent` 和 `HeroListComponent`。来生成 `CrisisList` 和 `HeroList`。
|
||||
|
||||
<code-example language="none" class="code-shell">
|
||||
ng generate component crisis-list
|
||||
</code-example>
|
||||
|
@ -1334,12 +1365,17 @@ Replace the contents of each component with the sample HTML below.
|
|||
|
||||
In order to use the Router, you must first register the `RouterModule` from the `@angular/router` package. Define an array of routes, `appRoutes`, and pass them to the `RouterModule.forRoot()` method. It returns a module, containing the configured `Router` service provider, plus other providers that the routing library requires. Once the application is bootstrapped, the `Router` performs the initial navigation based on the current browser URL.
|
||||
|
||||
下面是第一个配置。把路由数组传递到 `RouterModule.forRoot` 方法,该方法返回一个包含已配置的 `Router` 服务提供商模块和一些其它路由包需要的服务提供商。应用启动时,`Router` 将在当前浏览器 URL 的基础上进行初始导航。
|
||||
要使用路由器,必须先注册来自 `@angular/router` 包中的 `RouterModule`。
|
||||
定义一个路由数组 `appRoutes` 并把它传给 `RouterModule.forRoot()` 方法。
|
||||
它会返回一个模块,其中包含配置好的 `Router` 服务提供商,以及路由库所需的其它提供商。
|
||||
一旦启动了应用,`Router` 就会根据当前的浏览器 URL 进行首次导航。
|
||||
|
||||
<div class="alert is-important">
|
||||
|
||||
**Note:** The `RouterModule.forRoot` method is a pattern used to register application-wide providers. Read more about application-wide providers in the [Singleton services](guide/singleton-services#forroot) guide.
|
||||
|
||||
**注意:** `RouterModule.forRoot` 方法是用于注册全应用级提供商的编码模式。要详细了解全应用级提供商,参见[单例服务](guide/singleton-services#forroot) 一章。
|
||||
|
||||
</div>
|
||||
|
||||
<code-example path="router/src/app/app.module.1.ts" linenums="false" header="src/app/app.module.ts (first-config)" region="first-config">
|
||||
|
@ -1354,23 +1390,23 @@ and create a **[Routing Module](#routing-module)**, a special type of `Service M
|
|||
of routing in feature modules.
|
||||
|
||||
作为简单的路由配置,将添加配置好的 `RouterModule` 到 `AppModule` 中就足够了。
|
||||
随着应用的成长,你将需要将路由配置重构到单独的文件,并创建**[路由模块](#routing-module)** - 一种特别的、专门为特性模块的路由器服务的**服务模块**。
|
||||
随着应用的成长,你将需要[将路由配置重构](#refactor-the-routing-configuration-into-a-routing-module)到单独的文件中,并创建**[路由模块](#routing-module)** - 一种特别的、专门为特性模块的路由器服务的**服务模块**。
|
||||
|
||||
</div>
|
||||
|
||||
Registering the `RouterModule.forRoot()` in the `AppModule` imports makes the `Router` service available everywhere in the application.
|
||||
|
||||
在 `AppModule` 中提供 `RouterModule`,让该路由器在应用的任何地方都能被使用。
|
||||
把 `RouterModule.forRoot()` 注册到 `AppModule` 的 `imports` 中,能让该 `Router` 服务在应用的任何地方都能使用。
|
||||
|
||||
{@a shell}
|
||||
|
||||
### Add the Router Outlet
|
||||
|
||||
### *AppComponent* 外壳组件
|
||||
### 添加路由出口
|
||||
|
||||
The root `AppComponent` is the application shell. It has a title, a navigation bar with two links, and a router outlet where the router swaps components on and off the page. Here's what you get:
|
||||
|
||||
根组件 `AppComponent` 是本应用的壳。它在顶部有一个标题、一个带两个链接的导航条,在底部有一个*路由器出口*,路由器会在它所指定的位置上把视图切入或调出页面。就像下图中所标出的:
|
||||
根组件 `AppComponent` 是本应用的壳。它在顶部有一个标题、一个带两个链接的导航条,在底部有一个*路由器出口*,路由器会在它所指定的位置上把组件切入或调出页面。就像下图中所标出的:
|
||||
|
||||
<figure>
|
||||
<img src='generated/images/guide/router/shell-and-outlet.png' alt="Shell">
|
||||
|
@ -1394,7 +1430,7 @@ The corresponding component template looks like this:
|
|||
|
||||
### Define a Wildcard route
|
||||
|
||||
### 通配符路由
|
||||
### 定义通配符路由
|
||||
|
||||
You've created two routes in the app so far, one to `/crisis-center` and the other to `/heroes`. Any other URL causes the router to throw an error and crash the app.
|
||||
|
||||
|
@ -1464,7 +1500,7 @@ The browser address bar continues to point to the invalid URL.
|
|||
|
||||
### Set up redirects
|
||||
|
||||
### 把*默认*路由设置为英雄列表
|
||||
### 设置跳转
|
||||
|
||||
When the application launches, the initial URL in the browser bar is something like:
|
||||
|
||||
|
@ -1836,13 +1872,22 @@ The **Routing Module** has several characteristics:
|
|||
|
||||
### Integrate routing with your app
|
||||
|
||||
### 把路由集成到应用中
|
||||
|
||||
The sample routing application does not include routing by default.
|
||||
When you use the [Angular CLI](cli) to create a project that will use routing, set the `--routing` option for the project or app, and for each NgModule.
|
||||
When you create or initialize a new project (using the CLI [`ng new`](cli/new) command) or a new app (using the [`ng generate app`](cli/generate) command), specify the `--routing` option. This tells the CLI to include the `@angular/router` npm package and create a file named `app-routing.module.ts`.
|
||||
You can then use routing in any NgModule that you add to the project or app.
|
||||
|
||||
路由应用范例中默认不包含路由。
|
||||
要想在使用 [Angular CLI](cli) 创建项目时支持路由,请为项目或应用的每个 NgModule 设置 `--routing` 选项。
|
||||
当你用 CLI 命令 [`ng new`](cli/new) 创建新项目或用 [`ng generate app`](cli/generate) 命令创建新应用,请指定 `--routing` 选项。这会告诉 CLI 包含上 `@angular/router` 包,并创建一个名叫 `app-routing.module.ts` 的文件。
|
||||
然后你就可以在添加到项目或应用中的任何 NgModule 中使用路由功能了。
|
||||
|
||||
For example, the following command generates an NgModule that can use routing.
|
||||
|
||||
比如,可以用下列命令生成带路由的 NgModule。
|
||||
|
||||
```sh
|
||||
ng generate module my-module --routing
|
||||
```
|
||||
|
@ -1850,6 +1895,9 @@ ng generate module my-module --routing
|
|||
This creates a separate file named `my-module-routing.module.ts` to store the NgModule's routes.
|
||||
The file includes an empty `Routes` object that you can fill with routes to different components and NgModules.
|
||||
|
||||
这将创建一个名叫 `my-module-routing.module.ts` 的独立文件,来保存这个 NgModule 的路由信息。
|
||||
该文件包含一个空的 `Routes` 对象,你可以使用一些指向各个组件和 NgModule 的路由来填充该对象。
|
||||
|
||||
{@a routing-refactor}
|
||||
|
||||
### Refactor the routing configuration into a _routing module_
|
||||
|
@ -1858,7 +1906,7 @@ The file includes an empty `Routes` object that you can fill with routes to diff
|
|||
|
||||
Create an `AppRouting` module in the `/app` folder to contain the routing configuration.
|
||||
|
||||
在 `/app` 目录下创建一个名叫 `app-routing.module.ts` 的文件,以包含这个路由模块。
|
||||
在 `/app` 目录下创建一个 `AppRouting` 模块,以包含路由配置。
|
||||
|
||||
<code-example language="none" class="code-shell">
|
||||
ng generate module app-routing --module app --flat
|
||||
|
@ -1887,8 +1935,7 @@ After these steps, the file should look like this.
|
|||
Next, update the `app.module.ts` file, removing `RouterModule.forRoot` in
|
||||
the `imports` array.
|
||||
|
||||
接下来,修改 `app.module.ts` 文件,首先从 `app-routing.module.ts` 中导入新创建的 `AppRoutingModule`,
|
||||
然后把 `imports` 数组中的 `RouterModule.forRoot` 替换为 `AppRoutingModule`。
|
||||
接下来,修改 `app.module.ts` 文件,从 `imports` 数组中移除 `RouterModule.forRoot`。
|
||||
|
||||
<code-example path="router/src/app/app.module.2.ts" header="src/app/app.module.ts">
|
||||
|
||||
|
@ -1899,7 +1946,7 @@ the `imports` array.
|
|||
Later in this guide you will create [multiple routing modules](#heroes-functionality) and discover that
|
||||
you must import those routing modules [in the correct order](#routing-module-order).
|
||||
|
||||
本章稍后的部分,你将创建一个[多路由模块](guide/router#hero-routing-module),并揭示你为何必须[以正确的顺序导入那些路由模块](guide/router#routing-module-order)。
|
||||
本章稍后的部分,你将创建一个[多路由模块](#heroes-functionality),并揭示你为何必须[以正确的顺序导入那些路由模块](#routing-module-order)。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -2037,15 +2084,25 @@ Follow these steps:
|
|||
|
||||
* Delete the `<app-hero-detail>` component at the bottom of the template.
|
||||
|
||||
删除模板底部的 `<hero-detail>`。
|
||||
删除模板底部的 `<app-hero-detail>` 组件。
|
||||
|
||||
|
||||
* Copy the contents of the `heroes/heroes.component.css` from the live example into the `hero-list.component.css` file.
|
||||
|
||||
把在线例子中 `heroes/heroes.component.css` 文件的内容复制到 `hero-list.component.css` 文件中。
|
||||
|
||||
* Copy the contents of the `heroes/heroes.component.ts` from the live example into the `hero-list.component.ts` file.
|
||||
|
||||
把在线例子中 `heroes/heroes.component.ts` 文件的内容复制到 `hero-list.component.ts` 文件中。
|
||||
|
||||
* Change the component class name to `HeroListComponent`.
|
||||
|
||||
把组件类名改为 `HeroListComponent`。
|
||||
|
||||
* Change the `selector` to `app-hero-list`.
|
||||
|
||||
把 `selector` 改为 `app-hero-list`。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
Selectors are **not required** for _routed components_ due to the components are dynamically inserted when the page is rendered, but are useful for identifying and targeting them in your HTML element tree.
|
||||
|
@ -2055,13 +2112,25 @@ Follow these steps:
|
|||
</div>
|
||||
|
||||
* Copy the `hero-detail` folder, the `hero.ts`, `hero.service.ts`, and `mock-heroes.ts` files into the `heroes` subfolder.
|
||||
|
||||
把 `hero-detail` 目录中的 `hero.ts`、`hero.service.ts` 和 `mock-heroes.ts` 文件复制到 `heroes` 子目录下。
|
||||
|
||||
* Copy the `message.service.ts` into the `src/app` folder.
|
||||
|
||||
把 `message.service.ts` 文件复制到 `src/app` 目录下。
|
||||
|
||||
* Update the relative path import to the `message.service` in the `hero.service.ts` file.
|
||||
|
||||
在 `hero.service.ts` 文件中修改导入 `message.service` 的相对路径。
|
||||
|
||||
Next, you'll update the `HeroesModule` metadata.
|
||||
|
||||
接下来,还要修改 `HeroesModule` 的元数据。
|
||||
|
||||
* Import and add the `HeroDetailComponent` and `HeroListComponent` to the `declarations` array in the `HeroesModule`.
|
||||
|
||||
导入 `HeroDetailComponent` 和 `HeroListComponent`,并添加到 `HeroesModule` 模块的 `declarations` 数组中。
|
||||
|
||||
<code-example path="router/src/app/heroes/heroes.module.ts" header="src/app/heroes/heroes.module.ts">
|
||||
|
||||
</code-example>
|
||||
|
@ -2157,7 +2226,7 @@ hero-list
|
|||
|
||||
#### *Hero* feature routing requirements
|
||||
|
||||
### *英雄*特性区的路由需求
|
||||
#### *英雄*特性区的路由需求
|
||||
|
||||
The heroes feature has two interacting components, the hero list and the hero detail.
|
||||
The list view is self-sufficient; you navigate to it, it gets a list of heroes and displays them.
|
||||
|
@ -2179,7 +2248,7 @@ You tell the detail view which hero to display by including the selected hero's
|
|||
|
||||
Import the hero components from their new locations in the `src/app/heroes/` folder, define the two hero routes.
|
||||
|
||||
从新位置 `src/app/heroes/` 目录中导入英雄相关的组件,定义两个“英雄管理”路由,并导出 `HeroRoutingModule` 类。
|
||||
从新位置 `src/app/heroes/` 目录中导入英雄相关的组件,定义两个“英雄管理”路由。
|
||||
|
||||
Now that you have routes for the `Heroes` module, register them with the `Router` via the
|
||||
`RouterModule` _almost_ as you did in the `AppRoutingModule`.
|
||||
|
@ -2232,7 +2301,7 @@ But routes have a tendency to grow more complex and consistency in patterns pays
|
|||
|
||||
#### Remove duplicate hero routes
|
||||
|
||||
### 移除重复的“英雄管理”路由
|
||||
#### 移除重复的“英雄管理”路由
|
||||
|
||||
The hero routes are currently defined in _two_ places: in the `HeroesRoutingModule`,
|
||||
by way of the `HeroesModule`, and in the `AppRoutingModule`.
|
||||
|
@ -2396,7 +2465,7 @@ a route for some other hero.
|
|||
|
||||
#### Setting the route parameters in the list view
|
||||
|
||||
### 在列表视图中设置路由参数
|
||||
#### 在列表视图中设置路由参数
|
||||
|
||||
After navigating to the `HeroDetailComponent`, you expect to see the details of the selected hero.
|
||||
You need *two* pieces of information: the routing path to the component and the hero's `id`.
|
||||
|
@ -2739,7 +2808,7 @@ It holds the _path to the `HeroListComponent`_:
|
|||
|
||||
#### Route Parameters: Required or optional?
|
||||
|
||||
### 路由参数:必须还是可选?
|
||||
#### 路由参数:必须还是可选?
|
||||
|
||||
Use [*route parameters*](#route-parameters) to specify a *required* parameter value *within* the route URL
|
||||
as you do when navigating to the `HeroDetailComponent` in order to view the hero with *id* 15:
|
||||
|
@ -2756,7 +2825,7 @@ For example, when returning to the hero-detail.component.ts list from the hero d
|
|||
it would be nice if the viewed hero was preselected in the list.
|
||||
|
||||
你也能在路由请求中添加*可选*信息。
|
||||
比如,当从 `HeroDetailComponent` 返回英雄列表时,如果能自动选中刚刚查看过的英雄就好了。
|
||||
比如,当从 hero-detail.component.ts 返回到列表时,如果能自动选中刚刚查看过的英雄就好了。
|
||||
|
||||
<figure>
|
||||
<img src='generated/images/guide/router/selected-hero.png' alt="Selected hero">
|
||||
|
@ -2802,7 +2871,7 @@ prefer an *optional parameter* when the value is optional, complex, and/or multi
|
|||
|
||||
#### Heroes list: optionally selecting a hero
|
||||
|
||||
### 英雄列表:选定一个英雄(也可不选)
|
||||
#### 英雄列表:选定一个英雄(也可不选)
|
||||
|
||||
When navigating to the `HeroDetailComponent` you specified the _required_ `id` of the hero-to-edit in the
|
||||
*route parameter* and made it the second item of the [_link parameters array_](#link-parameters-array).
|
||||
|
@ -2989,6 +3058,8 @@ Look for it within the repeated `<li>` tag as shown here:
|
|||
|
||||
Add some styles to apply when the list item is selected.
|
||||
|
||||
当选中列表条目时,要添加一些样式。
|
||||
|
||||
<code-example path="router/src/app/heroes/hero-list/hero-list.component.css" linenums="false" region="selected" header="src/app/heroes/hero-list/hero-list.component.css">
|
||||
|
||||
</code-example>
|
||||
|
@ -3025,7 +3096,7 @@ This section shows you how to add some [animations](guide/animations) to the `He
|
|||
|
||||
First import the `BrowserAnimationsModule` and add it to the `imports` array:
|
||||
|
||||
首先导入 `BrowserAnimationsModule`:
|
||||
首先导入 `BrowserAnimationsModule`,并添加到 `imports` 数组中:
|
||||
|
||||
<code-example path="router/src/app/app.module.ts" linenums="false" header="src/app/app.module.ts (animations-module)" region="animations-module">
|
||||
|
||||
|
@ -3064,17 +3135,16 @@ This file does the following:
|
|||
|
||||
* Defines one *transition* when switching back and forth from the `heroes` and `hero` routes to ease the component in from the left of the screen as it enters the application view (`:enter`), the other to animate the component to the right as it leaves the application view (`:leave`).
|
||||
|
||||
定义两个*过渡效果*,其中一个(`:enter`)在组件进入应用视图时让它从屏幕左侧缓动进入(ease-in),另一个(`:leave`)在组件离开应用视图时让它向下飞出。
|
||||
定义一个*转场动画*,当在 `heroes` 和 `hero` 路由之间来回切换时,如果进入(`:enter`)应用视图则让组件从屏幕的左侧滑入,如果离开(`:leave`)应用视图则让组件从右侧划出。
|
||||
|
||||
You could also create more transitions for other routes. This trigger is sufficient for the current milestone.
|
||||
|
||||
你可以为其它路由组件用不同的转场效果创建更多触发器。现在这个触发器已经足够当前的里程碑用了。
|
||||
你还可以为其它路由组件用不同的转场效果创建更多触发器。现在这个触发器已经足够当前的里程碑用了。
|
||||
|
||||
Back in the `AppComponent`, import the `RouterOutlet` token from the `@angular/router` package and the `slideInDownAnimation` from
|
||||
`'./animations.ts`.
|
||||
|
||||
返回 `HeroDetailComponent`,从 `'./animations.ts` 中导入 `slideInDownAnimation`。
|
||||
从 `@angular/core` 中导入 `HostBinding` 装饰器,你很快就会用到它。
|
||||
回到 `AppComponent`,从 `@angular/router` 中导入 `RouterOutlet` 令牌,并从 `'./animations.ts` 中导入 `slideInDownAnimation`。
|
||||
|
||||
Add an `animations` array to the `@Component` metadata's that contains the `slideInDownAnimation`.
|
||||
|
||||
|
@ -3100,6 +3170,8 @@ For the `@routeAnimation` transitions to key off states, you'll need to provide
|
|||
|
||||
The `@routeAnimation` property is bound to the `getAnimationData` with the provided `routerOutlet` reference, so you'll need to define that function in the `AppComponent`. The `getAnimationData` function returns the animation property from the `data` provided through the `ActivatedRoute`. The `animation` property matches the `transition` names you used in the `slideDownAnimation` defined in `animations.ts`.
|
||||
|
||||
`@routeAnimation` 属性绑定到了 `getAnimationData` 和 `routerOutlet` 的引用,因此你需要在 `AppComponent` 中定义那个函数。`getAnimationData` 函数根据 `ActivatedRoute` 所提供的 `data` 对象返回动画的属性。`animation` 属性会匹配你在 `animations.ts` 中定义 `slideDownAnimation` 时使用的 `transition` 名称。
|
||||
|
||||
<code-example path="router/src/app/app.component.2.ts" linenums="false" header="src/app/app.component.ts (router outlet)" region="function-binding">
|
||||
|
||||
</code-example>
|
||||
|
@ -3456,13 +3528,16 @@ Begin by imitating the heroes feature:
|
|||
把 `app/heroes` 中的文件和目录复制到新的 `crisis-center` 文件夹中。
|
||||
|
||||
* In the new files, change every mention of "hero" to "crisis", and "heroes" to "crises".
|
||||
|
||||
在这些新建的文件中,把每个 "hero" 都改成 "crisis",每个 "heroes" 都改成 "crises"。
|
||||
|
||||
* Rename the NgModule files to `crisis-center.module.ts` and `crisis-center-routing.module.ts`.
|
||||
|
||||
在这些新文件中,把每一个对“hero”替换为“crisis”,并把“heroes”替换为“crises”。
|
||||
|
||||
You'll use mock crises instead of mock heroes:
|
||||
|
||||
你将会把 `CrisisService` 转换成模拟的危机列表,而不再是模拟的英雄列表:
|
||||
你还要用模拟的危机列表替换模拟的英雄列表:
|
||||
|
||||
<code-example path="router/src/app/crisis-center/mock-crises.ts" header="src/app/crisis-center/mock-crises.ts">
|
||||
|
||||
|
@ -3543,6 +3618,8 @@ Generate a `CrisisCenter` component in the `crisis-center` folder:
|
|||
|
||||
Update the component template to look like this:
|
||||
|
||||
把组件模板修改成这样:
|
||||
|
||||
<code-example path="router/src/app/crisis-center/crisis-center/crisis-center.component.html" linenums="false" header="src/app/crisis-center/crisis-center/crisis-center.component.html">
|
||||
</code-example>
|
||||
|
||||
|
@ -3575,6 +3652,8 @@ it has no business logic, and its template has no links, just a title and
|
|||
|
||||
As a host page for the "Crisis Center" feature, generate a `CrisisCenterHome` component in the `crisis-center` folder.
|
||||
|
||||
在 `crisis-center` 目录下生成一个 `CrisisCenterHome` 组件,作为 "危机中心" 特性的宿主页面。
|
||||
|
||||
<code-example language="none" class="code-shell">
|
||||
ng generate component crisis-center/crisis-center-home
|
||||
</code-example>
|
||||
|
@ -3589,8 +3668,8 @@ Update the template with a welcome message to the `Crisis Center`.
|
|||
Update the `crisis-center-routing.module.ts` you renamed after copying it from `heroes-routing.module.ts` file.
|
||||
This time, you define **child routes** *within* the parent `crisis-center` route.
|
||||
|
||||
像 `heroes-routing.module.ts` 文件一样,你也创建一个 `crisis-center-routing.module.ts`。
|
||||
但这次,你要把**子路由**定义在父路由 `crisis-center` 中。
|
||||
把 `heroes-routing.module.ts` 文件复制过来,改名为 `crisis-center-routing.module.ts`,并修改它。
|
||||
这次你要把**子路由**定义在父路由 `crisis-center` 中。
|
||||
|
||||
<code-example path="router/src/app/crisis-center/crisis-center-routing.module.1.ts" linenums="false" header="src/app/crisis-center/crisis-center-routing.module.ts (Routes)" region="routes">
|
||||
</code-example>
|
||||
|
@ -3903,7 +3982,7 @@ and two buttons, "Send" and "Cancel".
|
|||
|
||||
Here's the component, its template and styles:
|
||||
|
||||
下面是该组件及其模板:
|
||||
下面是该组件及其模板和样式:
|
||||
|
||||
<code-tabs>
|
||||
|
||||
|
@ -4177,7 +4256,7 @@ A guard's return value controls the router's behavior:
|
|||
|
||||
**Note:**The guard can also tell the router to navigate elsewhere, effectively canceling the current navigation.
|
||||
|
||||
守卫还可以告诉路由器导航到别处,这样也取消当前的导航。
|
||||
**注意**:守卫还可以告诉路由器导航到别处,这样也取消当前的导航。
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -4448,8 +4527,8 @@ feature module, a dashboard route and two unfinished components to manage crises
|
|||
Although the admin dashboard `RouterLink` only contains a relative slash without an additional URL segment, it
|
||||
is considered a match to any route within the admin feature area. You only want the `Dashboard` link to be active when the user visits that route. Adding an additional binding to the `Dashboard` routerLink,`[routerLinkActiveOptions]="{ exact: true }"`, marks the `./` link as active when the user navigates to the `/admin` URL and not when navigating to any of the child routes.
|
||||
|
||||
由于 `AdminModule` 中 `AdminComponent` 中的 `RouterLink` 是一个空路径的路由,所以它会匹配到管理特性区的任何路由。
|
||||
但你只有在访问 `Dashboard` 路由时才希望该链接被激活。
|
||||
虽然管理仪表盘中的 `RouterLink` 只包含一个没有其它 URL 段的斜杠 `/`,但它能匹配管理特性区下的任何路由。
|
||||
但你只希望在访问 `Dashboard` 路由时才激活该链接。
|
||||
往 `Dashboard` 这个 routerLink 上添加另一个绑定 `[routerLinkActiveOptions]="{ exact: true }"`,
|
||||
这样就只有当用户导航到 `/admin` 这个 URL 时才会激活它,而不会在导航到它的某个子路由时。
|
||||
|
||||
|
@ -4527,12 +4606,12 @@ This is a general purpose guard—you can imagine other features
|
|||
that require authenticated users—so you generate an
|
||||
`AuthGuard` in the `auth` folder.
|
||||
|
||||
这是一个通用的守卫(你可以假设另外一些特性区也要求已认证过的用户才能访问),所以你可以在 `auth` 目录下生成一个 `AuthGuard`。
|
||||
|
||||
<code-example language="none" class="code-shell">
|
||||
ng generate guard auth/auth
|
||||
</code-example>
|
||||
|
||||
这是一种具有通用性的守护目标(通常会有其它特性需要登录用户才能访问),所以你要在应用的根目录下创建一个 `auth-guard.ts` 文件。
|
||||
|
||||
At the moment you're interested in seeing how guards work so the first version does nothing useful.
|
||||
It simply logs to console and `returns` true immediately, allowing navigation to proceed:
|
||||
|
||||
|
@ -4690,7 +4769,7 @@ Extend the `AuthGuard` to protect when navigating between the `admin` routes.
|
|||
Open `auth.guard.ts` and add the `CanActivateChild` interface to the imported tokens from the router package.
|
||||
|
||||
扩展 `AuthGuard` 以便在 `admin` 路由之间导航时提供保护。
|
||||
打开 `auth-guard.service.ts` 并从路由库中导入 `CanActivateChild` 接口。
|
||||
打开 `auth.guard.service.ts` 并从路由库中导入 `CanActivateChild` 接口。
|
||||
|
||||
Next, implement the `canActivateChild()` method which takes the same arguments as the `canActivate()` method:
|
||||
an `ActivatedRouteSnapshot` and `RouterStateSnapshot`.
|
||||
|
@ -4769,7 +4848,7 @@ You need the `CanDeactivate` guard.
|
|||
|
||||
#### Cancel and save
|
||||
|
||||
### 取消与保存
|
||||
#### 取消与保存
|
||||
|
||||
The sample application doesn't talk to a server.
|
||||
Fortunately, you have another way to demonstrate an asynchronous router hook.
|
||||
|
@ -4821,18 +4900,20 @@ is like waiting for the server asynchronously.
|
|||
|
||||
Generate a `Dialog` service to handle user confirmation.
|
||||
|
||||
生成一个 `Dialog` 服务,以处理用户的确认操作。
|
||||
|
||||
<code-example language="none" class="code-shell">
|
||||
ng generate service dialog
|
||||
</code-example>
|
||||
|
||||
Add a `confirm()` method to the `DialogService` to prompt the user to confirm their intent. The `window.confirm` is a _blocking_ action that displays a modal dialog and waits for user interaction.
|
||||
|
||||
为 `DialogService` 添加一个 `confirm()` 方法,以提醒用户确认。`window.confirm` 是一个*阻塞型*操作,它会显示一个模态对话框,并等待用户的交互。
|
||||
|
||||
<code-example path="router/src/app/dialog.service.ts" header="src/app/dialog.service.ts">
|
||||
|
||||
</code-example>
|
||||
|
||||
`DialogService`(为了在应用级使用,已经注入到了 `AppModule`)就可以做到这些。
|
||||
|
||||
It returns an `Observable` that *resolves* when the user eventually decides what to do: either
|
||||
to discard changes and navigate away (`true`) or to preserve the pending changes and stay in the crisis editor (`false`).
|
||||
|
||||
|
@ -4842,9 +4923,12 @@ to discard changes and navigate away (`true`) or to preserve the pending changes
|
|||
|
||||
Generate a _guard_ that checks for the presence of a `canDeactivate()` method in a component—any component.
|
||||
|
||||
生成一个*守卫(guard)*,以检查组件(任意组件均可)中是否存在 `canDeactivate()` 方法。
|
||||
|
||||
<code-example language="none" class="code-shell">
|
||||
ng generate guard can-deactivate
|
||||
</code-example>
|
||||
|
||||
The `CrisisDetailComponent` will have this method.
|
||||
But the guard doesn't have to know that.
|
||||
The guard shouldn't know the details of any component's deactivation method.
|
||||
|
@ -4947,7 +5031,7 @@ You need a *resolver*.
|
|||
|
||||
#### Fetch data before navigating
|
||||
|
||||
### 导航前预先加载路由信息
|
||||
#### 导航前预先加载路由信息
|
||||
|
||||
At the moment, the `CrisisDetailComponent` retrieves the selected crisis.
|
||||
If the crisis is not found, it navigates back to the crisis list view.
|
||||
|
@ -4980,7 +5064,7 @@ and move them into the `CrisisDetailResolverService`.
|
|||
Import the `Crisis` model, `CrisisService`, and the `Router`
|
||||
so you can navigate elsewhere if you can't fetch the crisis.
|
||||
|
||||
在 `CrisisDetailComponent.ngOnInit` 中拿到相关的危机检索逻辑,并且把它们移到 `CrisisDetailResolver` 中。
|
||||
在 `CrisisDetailComponent.ngOnInit` 中拿到相关的危机检索逻辑,并且把它们移到 `CrisisDetailResolverService` 中。
|
||||
导入 `Crisis` 模型、`CrisisService` 和 `Router` 以便让你可以在找不到指定的危机时导航到别处。
|
||||
|
||||
Be explicit. Implement the `Resolve` interface with a type of `Crisis`.
|
||||
|
@ -4999,8 +5083,14 @@ of its values. You use the `take` operator with an argument of `1` to ensure tha
|
|||
Observable completes after retrieving the first value from the Observable returned by the
|
||||
`getCrisis` method.
|
||||
|
||||
`CrisisService.getCrisis` 方法返回一个可观察对象,以防止在数据获取完之前加载本路由。
|
||||
`Router` 守卫要求这个可观察对象必须可结束(`complete`),也就是说它已经发出了所有值。
|
||||
你可以为 `take` 操作符传入一个参数 `1`,以确保这个可观察对象会在从 `getCrisis` 方法所返回的可观察对象中取到第一个值之后就会结束。
|
||||
|
||||
If it doesn't return a valid `Crisis`, return an empty `Observable`, canceling the previous in-flight navigation to the `CrisisDetailComponent` and navigate the user back to the `CrisisListComponent`. The update resolver service looks like this:
|
||||
|
||||
如果它没有返回有效的 `Crisis`,就会返回一个 `Observable`,以取消以前到 `CrisisDetailComponent` 的在途导航,并把用户导航回 `CrisisListComponent`。修改后的 `resolver` 服务是这样的:
|
||||
|
||||
<code-example path="router/src/app/crisis-center/crisis-detail-resolver.service.ts" header="src/app/crisis-center/crisis-detail-resolver.service.ts">
|
||||
|
||||
</code-example>
|
||||
|
@ -5038,7 +5128,7 @@ It will be there when the `CrisisDetailComponent` ask for it.
|
|||
The `CrisisDetailResolverService` doesn't inherit from a base class.
|
||||
The router looks for that method and calls it if found.
|
||||
|
||||
路由器的这个 `Resolve` 接口是可选的。`CrisisDetailResolver` 没有继承自某个基类。路由器只要找到了这个方法,就会调用它。
|
||||
路由器的这个 `Resolve` 接口是可选的。`CrisisDetailResolverService` 没有继承自某个基类。路由器只要找到了这个方法,就会调用它。
|
||||
|
||||
1. Rely on the router to call the resolver.
|
||||
Don't worry about all the ways that the user could navigate away.
|
||||
|
@ -5280,7 +5370,7 @@ Give it a `loadChildren` property instead of a `children` property, set to the a
|
|||
The address is the `AdminModule` file location (relative to the app root),
|
||||
followed by a `#` separator, followed by the name of the exported module class, `AdminModule`.
|
||||
|
||||
给它一个 `loadChildren` 属性(注意不是 `children` 属性),把它设置为 `AdminModule` 的地址。
|
||||
给它一个 `loadChildren` 属性(替换掉 `children` 属性),把它设置为 `AdminModule` 的地址。
|
||||
该地址是 `AdminModule` 的文件路径(相对于 `app` 目录的),加上一个 `#` 分隔符,再加上导出模块的类名 `AdminModule`。
|
||||
|
||||
<code-example path="router/src/app/app-routing.module.5.ts" region="admin-1" header="app-routing.module.ts (load children)">
|
||||
|
@ -5360,7 +5450,7 @@ Import the `CanLoad` interface from `@angular/router`.
|
|||
Add it to the `AuthGuard` class's `implements` list.
|
||||
Then implement `canLoad()` as follows:
|
||||
|
||||
打开 `auth-guard.service.ts`,从 `@angular/router` 中导入 `CanLoad` 接口。
|
||||
打开 `auth.guard.service.ts`,从 `@angular/router` 中导入 `CanLoad` 接口。
|
||||
把它添加到 `AuthGuard` 类的 `implements` 列表中。
|
||||
然后实现 `canLoad`,代码如下:
|
||||
|
||||
|
@ -5543,7 +5633,7 @@ This tells the `Router` preloader to immediately load _all_ lazy loaded routes (
|
|||
When you visit `http://localhost:4200`, the `/heroes` route loads immediately upon launch
|
||||
and the router starts loading the `CrisisCenterModule` right after the `HeroesModule` loads.
|
||||
|
||||
当访问 `http://localhost:3000` 时,`/heroes` 路由立即随之启动,并且路由器在加载了 `HeroesModule` 之后立即开始加载 `CrisisCenterModule`。
|
||||
当访问 `http://localhost:4200` 时,`/heroes` 路由立即随之启动,并且路由器在加载了 `HeroesModule` 之后立即开始加载 `CrisisCenterModule`。
|
||||
|
||||
Surprisingly, the `AdminModule` does _not_ preload. Something is blocking it.
|
||||
|
||||
|
@ -5603,9 +5693,9 @@ Set the `data.preload` flag in the `crisis-center` route in the `AppRoutingModul
|
|||
|
||||
</code-example>
|
||||
|
||||
Generate a new `SelectivePreloadingStrategy` service.
|
||||
Generate a new `SelectivePreloadingStrategyService` service.
|
||||
|
||||
生成一个新的 `SelectivePreloadingStrategy` 服务。
|
||||
生成一个新的 `SelectivePreloadingStrategyService` 服务。
|
||||
|
||||
<code-example language="none" class="code-shell">
|
||||
ng generate service selective-preloading-strategy
|
||||
|
@ -5619,7 +5709,7 @@ Generate a new `SelectivePreloadingStrategy` service.
|
|||
|
||||
`SelectivePreloadingStrategyService` implements the `PreloadingStrategy`, which has one method, `preload`.
|
||||
|
||||
`SelectivePreloadingStrategy` 实现了 `PreloadingStrategy`,它只有一个方法 `preload`。
|
||||
`SelectivePreloadingStrategyService` 实现了 `PreloadingStrategy`,它只有一个方法 `preload`。
|
||||
|
||||
The router calls the `preload` method with two arguments:
|
||||
|
||||
|
@ -5649,7 +5739,7 @@ It also has a side-effect.
|
|||
`SelectivePreloadingStrategyService` logs the `path` of a selected route in its public `preloadedModules` array.
|
||||
|
||||
它还有一个副作用。
|
||||
`SelectivePreloadingStrategy` 会把所选路由的 `path` 记录在它的公共数组 `preloadedModules` 中。
|
||||
`SelectivePreloadingStrategyService` 会把所选路由的 `path` 记录在它的公共数组 `preloadedModules` 中。
|
||||
|
||||
Shortly, you'll extend the `AdminDashboardComponent` to inject this service and display its `preloadedModules` array.
|
||||
|
||||
|
@ -5661,16 +5751,16 @@ But first, make a few changes to the `AppRoutingModule`.
|
|||
|
||||
1. Import `SelectivePreloadingStrategyService` into `AppRoutingModule`.
|
||||
|
||||
把 `SelectivePreloadingStrategy` 导入到 `AppRoutingModule` 中。
|
||||
把 `SelectivePreloadingStrategyService` 导入到 `AppRoutingModule` 中。
|
||||
|
||||
1. Replace the `PreloadAllModules` strategy in the call to `forRoot` with this `SelectivePreloadingStrategyService`.
|
||||
|
||||
把 `PreloadAllModules` 策略替换成对 `forRoot` 的调用,并且传入这个 `SelectivePreloadingStrategy`。
|
||||
把 `PreloadAllModules` 策略替换成对 `forRoot` 的调用,并且传入这个 `SelectivePreloadingStrategyService`。
|
||||
|
||||
1. Add the `SelectivePreloadingStrategyService` strategy to the `AppRoutingModule` providers array so it can be injected
|
||||
elsewhere in the app.
|
||||
|
||||
把 `SelectivePreloadingStrategy` 策略添加到 `AppRoutingModule` 的 `providers` 数组中,以便它可以注入到应用中的任何地方。
|
||||
把 `SelectivePreloadingStrategyService` 策略添加到 `AppRoutingModule` 的 `providers` 数组中,以便它可以注入到应用中的任何地方。
|
||||
|
||||
Now edit the `AdminDashboardComponent` to display the log of preloaded routes.
|
||||
|
||||
|
@ -5678,7 +5768,8 @@ Now edit the `AdminDashboardComponent` to display the log of preloaded routes.
|
|||
|
||||
1. Import the `SelectivePreloadingStrategyService`.
|
||||
|
||||
导入 `SelectivePreloadingStrategy`(它是一个服务)。
|
||||
导入 `SelectivePreloadingStrategyService`(它是一个服务)。
|
||||
|
||||
1. Inject it into the dashboard's constructor.
|
||||
|
||||
把它注入到仪表盘的构造函数中。
|
||||
|
@ -5775,6 +5866,8 @@ So instead, you'll update the empty path route in `app-routing.module.ts` to red
|
|||
|
||||
Update the `goToHeroes()` method in the `hero-detail.component.ts` to navigate back to `/superheroes` with the optional route parameters.
|
||||
|
||||
修改 `hero-detail.component.ts` 中的 `goToHeroes()` 方法,使用可选的路由参数导航回 `/superheroes`。
|
||||
|
||||
<code-example path="router/src/app/heroes/hero-detail/hero-detail.component.ts" linenums="false" region="redirect" header="src/app/heroes/hero-detail/hero-detail.component.ts (goToHeroes)">
|
||||
|
||||
</code-example>
|
||||
|
@ -6076,14 +6169,19 @@ resort to hash routes.
|
|||
|
||||
#### The *<base href>*
|
||||
|
||||
#### *<base href>* 标签
|
||||
|
||||
The router uses the browser's
|
||||
<a href="https://developer.mozilla.org/en-US/docs/Web/API/History_API#Adding_and_modifying_history_entries" title="HTML5 browser history push-state">history.pushState</a>
|
||||
for navigation. Thanks to `pushState`, you can make in-app URL paths look the way you want them to
|
||||
look, e.g. `localhost:4200/crisis-center`. The in-app URLs can be indistinguishable from server URLs.
|
||||
|
||||
路由器使用浏览器的 <a href="https://developer.mozilla.org/en-US/docs/Web/API/History_API#Adding_and_modifying_history_entries" title="HTML5 browser history push-state">history.pushState</a> API 进行导航。借助 `pushState` 你可以让应用中的 URL 路径看上去就像你期望的那样,比如 `localhost:4200/crisis-center`,应用内的 URL 和服务器的 URL 没有区别。
|
||||
|
||||
Modern HTML5 browsers were the first to support `pushState` which is why many people refer to these URLs as
|
||||
"HTML5 style" URLs.
|
||||
|
||||
现代的 HTML5 浏览器都支持 `pushState`,这也就是为什么很多人把这种 URL 形式称为 "HTML 5" 风格的 URL。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
|
@ -6095,6 +6193,9 @@ learn why HTML5 style is preferred, how to adjust its behavior, and how to switc
|
|||
older hash (#) style, if necessary.
|
||||
|
||||
|
||||
路由器默认使用 HTML5 风格的导航。
|
||||
在附录中的 [LocationStrategy 与浏览器 URL 风格](#browser-url-styles)中,你可以了解为何推荐使用 HTML5 风格的 URL,如何调整其行为,以及必要时如何切换到老式的 hash(#)风格。
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
@ -6105,10 +6206,14 @@ to the app's `index.html` for `pushState` routing to work.
|
|||
The browser uses the `<base href>` value to prefix *relative* URLs when referencing
|
||||
CSS files, scripts, and images.
|
||||
|
||||
你必须在应用的 `index.html` 中**添加一个 <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base" title="base href"><base href> 元素</a>**才能让 `pushState` 路由正常工作。
|
||||
浏览器要用 `<base href>` 的值为引用 CSS、脚本和图片文件时使用的*相对* URL 添加前缀。
|
||||
|
||||
Add the `<base>` element just after the `<head>` tag.
|
||||
If the `app` folder is the application root, as it is for this application,
|
||||
set the `href` value in **`index.html`** *exactly* as shown here.
|
||||
|
||||
请把 `<base>` 元素添加在 `<head>` 标签的紧后面。如果应用的根目录是 `app` 目录,那么就可以像这个应用程序一样,设置 **`index.html`** 中的 `href` 值。代码如下。
|
||||
|
||||
<code-example path="router/src/index.html" linenums="false" header="src/index.html (base-href)" region="base-href">
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ an app created with the [Angular CLI](cli), this is everything in the `dist` dir
|
|||
the user's `src/ngsw-config.json` configuration.
|
||||
|
||||
为了确保资源的整体性,Angular Service Worker 会验证所有带哈希的资源的哈希值。
|
||||
通常,对于 CLI 应用程序,用户的 `src/ngsw-config.json` 配置文件中会涵盖 `dist` 目录下的所有内容。
|
||||
通常,对于 [Angular CLI](cli) 应用程序,用户的 `src/ngsw-config.json` 配置文件中会涵盖 `dist` 目录下的所有内容。
|
||||
|
||||
If a particular file fails validation, the Angular service worker
|
||||
attempts to re-fetch the content using a "cache-busting" URL
|
||||
|
|
|
@ -102,10 +102,7 @@ To serve the directory containing your web files with `http-server`, run the fol
|
|||
要想使用 `http-server` 服务器,进入包含这些 web 文件的目录,并启动开发服务器:
|
||||
|
||||
```sh
|
||||
|
||||
|
||||
http-server -p 8080
|
||||
-c-1 dist/<project-name>
|
||||
http-server -p 8080 -c-1 dist/<project-name>
|
||||
```
|
||||
|
||||
### Initial load
|
||||
|
@ -228,11 +225,8 @@ next step is understanding how updates work.
|
|||
再次构建并运行此服务器:
|
||||
|
||||
```sh
|
||||
|
||||
ng build --prod
|
||||
|
||||
http-server -p 8080
|
||||
-c-1 dist/<project-name>
|
||||
http-server -p 8080 -c-1 dist/<project-name>
|
||||
```
|
||||
|
||||
### Updating your application in the browser
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
Service workers augment the traditional web deployment model and empower applications to deliver a user experience with the reliability and performance on par with natively-installed code. Adding a service worker to an Angular application is one of the steps for turning an application into a [Progressive Web App](https://developers.google.com/web/progressive-web-apps/) (also known as a PWA).
|
||||
|
||||
Service Worker 可以增强传统的 Web 发布模式,并使应用程序能够提供可与本机代码媲美的高可靠、高性能的用户体验。
|
||||
Service Worker 可以增强传统的 Web 发布模式,并使应用程序能够提供可与本机代码媲美的高可靠、高性能的用户体验。为 Angular 应用添加 Service Worker 是把应用转换成[渐进式应用(PWA)](https://developers.google.com/web/progressive-web-apps/)的步骤之一。
|
||||
|
||||
At its simplest, a service worker is a script that runs in the web browser and manages caching for an application.
|
||||
|
||||
|
|
|
@ -128,7 +128,7 @@ Consequently, there are _many more files_ in the project folder on your machine,
|
|||
most of which you can [learn about later](guide/file-structure).
|
||||
|
||||
**《快速上手》种子** 包含了与《快速上手》游乐场一样的应用,但是,它真正的目的是提供坚实的*本地*开发基础。
|
||||
所以你的电脑里的项目目录里面有*更多文件*,参见[搭建剖析](guide/setup-systemjs-anatomy "Setup Anatomy")。
|
||||
所以你的电脑里的项目目录里面有*更多文件*,其中的大部分你都会[在稍后学到](guide/file-structure)。
|
||||
|
||||
{@a app-files}
|
||||
|
||||
|
|
|
@ -4380,7 +4380,7 @@ Compare with the less preferred `host` metadata alternative.
|
|||
|
||||
**Why?** When you register a service in the `@Injectable` decorator of the service, optimization tools such as those used by the [Angular CLI's](cli) production builds can perform tree shaking and remove services that aren't used by your app.
|
||||
|
||||
**为何?**当你在服务的 `@Injectable` 中注册服务时,CLI 生产环境构建时使用的优化工具可以进行摇树优化,从而移除那些你的应用中从未用过的服务。
|
||||
**为何?**当你在服务的 `@Injectable` 中注册服务时,[Angular CLI](cli) 生产环境构建时使用的优化工具可以进行摇树优化,从而移除那些你的应用中从未用过的服务。
|
||||
|
||||
</div>
|
||||
|
||||
|
|
|
@ -30,13 +30,13 @@ The sample application and all tests in this guide are available for inspection
|
|||
|
||||
The Angular CLI downloads and install everything you need to test an Angular application with the [Jasmine test framework](https://jasmine.github.io/).
|
||||
|
||||
Angular CLI 会下载并安装试用 [Jasmine 测试框架](http://jasmine.github.io/2.4/introduction.html) 测试 Angular 应用时所需的一切。
|
||||
Angular CLI 会下载并安装试用 [Jasmine 测试框架](https://jasmine.github.io/) 测试 Angular 应用时所需的一切。
|
||||
|
||||
The project you create with the CLI is immediately ready to test.
|
||||
Just run the [`ng test`](cli/test) CLI command:
|
||||
|
||||
你使用 CLI 创建的项目是可以立即用于测试的。
|
||||
运行下列 CLI 命令即可:
|
||||
运行 CLI 命令 [`ng test`](cli/test) 即可:
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
ng test
|
||||
|
@ -45,7 +45,7 @@ Just run the [`ng test`](cli/test) CLI command:
|
|||
The `ng test` command builds the app in _watch mode_,
|
||||
and launches the [karma test runner](https://karma-runner.github.io).
|
||||
|
||||
`ng test` 命令在*监视模式*下构建应用,并启动 [karma 测试运行器](https://karma-runner.github.io/1.0/index.html)。
|
||||
`ng test` 命令在*监视模式*下构建应用,并启动 [karma 测试运行器](https://karma-runner.github.io)。
|
||||
|
||||
The console output looks a bit like this:
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ There are three main reasons to create a Universal version of your app.
|
|||
|
||||
### Facilitate web crawlers
|
||||
|
||||
#### 帮助网络爬虫
|
||||
### 帮助网络爬虫
|
||||
|
||||
Google, Bing, Facebook, Twitter, and other social media sites rely on web crawlers to index your application content and make that content searchable on the web.
|
||||
|
||||
|
@ -92,7 +92,7 @@ Enabling web crawlers is often referred to as
|
|||
|
||||
### Improve performance on mobile and low-powered devices
|
||||
|
||||
#### 提升手机和低功耗设备上的性能
|
||||
### 提升手机和低功耗设备上的性能
|
||||
|
||||
Some devices don't support JavaScript or execute JavaScript so poorly that the user experience is unacceptable.
|
||||
For these cases, you may require a server-rendered, no-JavaScript version of the app.
|
||||
|
@ -107,9 +107,10 @@ people who otherwise couldn't use the app at all.
|
|||
|
||||
### Show the first page quickly
|
||||
|
||||
#### 快速显示第一页
|
||||
### 快速显示第一页
|
||||
|
||||
Displaying the first page quickly can be critical for user engagement.
|
||||
|
||||
快速显示第一页对于吸引用户是至关重要的。
|
||||
|
||||
[53percent of mobile site visits are abandoned](https://www.doubleclickbygoogle.com/articles/mobile-speed-matters/) if pages take longer than 3 seconds to load.
|
||||
|
@ -124,7 +125,7 @@ The pages don't handle browser events, but they _do_ support navigation through
|
|||
|
||||
使用 Angular Universal,你可以为应用生成“着陆页”,它们看起来就和完整的应用一样。
|
||||
这些着陆页是纯 HTML,并且即使 JavaScript 被禁用了也能显示。
|
||||
这些页面不会处理浏览器事件,不过它们*可以*用 [routerLink](guide/router.html#router-link) 在这个网站中导航。
|
||||
这些页面不会处理浏览器事件,不过它们*可以*用 `[routerLink](guide/router#router-link)` 在这个网站中导航。
|
||||
|
||||
In practice, you'll serve a static version of the landing page to hold the user's attention.
|
||||
At the same time, you'll load the full Angular app behind it.
|
||||
|
@ -132,24 +133,35 @@ The user perceives near-instant performance from the landing page
|
|||
and gets the full interactive experience after the full app loads.
|
||||
|
||||
在实践中,你可能要使用一个着陆页的静态版本来保持用户的注意力。
|
||||
同时,你也会在幕后加载完整的 Angular 应用,就像[稍后解释的那样](#transition)。
|
||||
同时,你也会在幕后加载完整的 Angular 应用。
|
||||
用户会觉得着陆页几乎是立即出现的,而当完整的应用加载完之后,又可以获得完整的交互体验。
|
||||
|
||||
{@a how-does-it-work}
|
||||
|
||||
## Universal web servers
|
||||
|
||||
## Universal Web 服务器
|
||||
|
||||
A Universal web server responds to application page requests with static HTML rendered by the [Universal template engine](#universal-engine).
|
||||
The server receives and responds to HTTP requests from clients (usually browsers), and serves static assets such as scripts, CSS, and images.
|
||||
It may respond to data requests, either directly or as a proxy to a separate data server.
|
||||
|
||||
Universal Web 服务器使用 [Universal 模板引擎](#universal-engine)渲染出的静态 HTML 来响应对应用页面的请求。
|
||||
服务器接收并响应来自客户端(通常是浏览器)的 HTTP 请求,并回复静态文件,如脚本、CSS 和图片。
|
||||
它可以直接响应数据请求,也可以作为独立数据服务器的代理进行响应。
|
||||
|
||||
The sample web server for this guide is based on the popular [Express](https://expressjs.com/) framework.
|
||||
|
||||
这个例子中的范例 Web 服务器是基于常见的 [Express](https://expressjs.com/) 框架的。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
**Note:** _Any_ web server technology can serve a Universal app as long as it can call Universal's `renderModuleFactory()` function.
|
||||
The principles and decision points discussed here apply to any web server technology.
|
||||
|
||||
**注意:** **任何一种** Web 服务器技术都可以作为 Universal 应用的服务器,只要它能调用 Universal 的 `renderModuleFactory()` 函数。
|
||||
这里所讨论的这些原则和决策点也适用于任何 Web 服务器技术。
|
||||
|
||||
</div>
|
||||
|
||||
To make a Universal app, install the `platform-server` package, which provides server implementations
|
||||
|
@ -157,29 +169,32 @@ of the DOM, `XMLHttpRequest`, and other low-level features that don't rely on a
|
|||
Compile the client application with the `platform-server` module (instead of the `platform-browser` module)
|
||||
and run the resulting Universal app on a web server.
|
||||
|
||||
你要使用 `platform-server` 模块而不是 `platform-browser` 模块来编译这个客户端应用,并且在一个 Web 服务器上运行这个 Universal 应用。
|
||||
要制作一个 Universal 应用,就要安装 `platform-server` 包,它提供了 DOM 的服务端实现、`XMLHttpRequest` 以及其它不依赖浏览器的底层特性。
|
||||
使用 `platform-server` 模块(代替 `platform-browser` 模块)编译客户端应用,并在 Web 服务器上运行其生成的 Universal 应用。
|
||||
|
||||
The server ([Node Express](https://expressjs.com/) in this guide's example)
|
||||
passes client requests for application pages to Universal's `renderModuleFactory()` function.
|
||||
|
||||
服务器(这个例子中使用的是 [Node Express](https://expressjs.com/) 服务器)会把客户端对应用页面的请求传给 `renderModuleFactory` 函数。
|
||||
服务器(这个例子中使用的是 [Node Express](https://expressjs.com/) 服务器)会把客户端对应用页面的请求传给 `renderModuleFactory()` 函数。
|
||||
|
||||
The `renderModuleFactory()` function takes as inputs a *template* HTML page (usually `index.html`),
|
||||
an Angular *module* containing components,
|
||||
and a *route* that determines which components to display.
|
||||
|
||||
`renderModuleFactory` 函数接受一个*模板* HTML 页面(通常是 `index.html`)、一个包含组件的 Angular *模块*和一个用于决定该显示哪些组件的*路由*作为输入。
|
||||
`renderModuleFactory()` 函数接受一个*模板* HTML 页面(通常是 `index.html`)、一个包含组件的 Angular *模块*和一个用于决定该显示哪些组件的*路由*作为输入。
|
||||
|
||||
The route comes from the client's request to the server.
|
||||
|
||||
Each request results in the appropriate view for the requested route.
|
||||
该路由从客户端的请求中传给服务器。
|
||||
|
||||
Each request results in the appropriate view for the requested route.
|
||||
|
||||
每次请求都会给出所请求路由的一个适当的视图。
|
||||
|
||||
The `renderModuleFactory()` function renders the view within the `<app>` tag of the template,
|
||||
creating a finished HTML page for the client.
|
||||
|
||||
`renderModuleFactory` 在模板中的 `<app>` 标记中渲染出哪个视图,并为客户端创建一个完成的 HTML 页面。
|
||||
`renderModuleFactory()` 在模板中的 `<app>` 标记中渲染出哪个视图,并为客户端创建一个完成的 HTML 页面。
|
||||
|
||||
Finally, the server returns the rendered page to the client.
|
||||
|
||||
|
@ -188,62 +203,116 @@ Finally, the server returns the rendered page to the client.
|
|||
{@a summary}
|
||||
## Preparing for server-side rendering
|
||||
|
||||
## 准备服务端渲染
|
||||
|
||||
Before your app can be rendered on a server, you must make changes in the app itself, and also set up the server.
|
||||
|
||||
要想让应用可以在服务器上渲染,就要对应用自身做一些修改,然后搭建服务器环境。
|
||||
|
||||
1. Install dependencies.
|
||||
|
||||
安装依赖。
|
||||
|
||||
1. Prepare your app by modifying both the app code and its configuration.
|
||||
|
||||
通过修改应用代码及其配置进行准备。
|
||||
|
||||
1. Add a build target, and build a Universal bundle using the CLI with the `@nguniversal/express-engine` schematic.
|
||||
|
||||
添加构建目标,并使用 CLI 中的 `@nguniversal/express-engine` 原理图来构建出 Universal 包。
|
||||
|
||||
1. Set up a server to run Universal bundles.
|
||||
|
||||
设置服务器,以运行 Universal 包。
|
||||
|
||||
1. Pack and run the app on the server.
|
||||
|
||||
打包并在服务器上运行此应用。
|
||||
|
||||
The following sections go into each of these main steps in more detail.
|
||||
|
||||
下面各节将会更详细的介绍这些主要步骤。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
**Note:** The [Universal tutorial](#the-example) below walks you through the steps using the Tour of Heroes sample app, and goes into more detail about what you can do and why you might want to do it.
|
||||
|
||||
**注意:稍后的 **[Universal 教程](#the-example)将引导你基于 "英雄指南" 应用来完成各个步骤,并详细介绍你能做什么以及为什么要那么做。
|
||||
|
||||
To see a working version of an app with server-side rendering, clone the [Angular Universal starter](https://github.com/angular/universal-starter).
|
||||
|
||||
要亲自体验带服务端渲染功能的应用,请把 [Angular Universal starter](https://github.com/angular/universal-starter) 克隆下来试试。
|
||||
|
||||
</div>
|
||||
|
||||
<div class="callout is-critical">
|
||||
|
||||
<header>Security for server requests</header>
|
||||
|
||||
<header>服务端请求的安全性</header>
|
||||
|
||||
HTTP requests issued from a browser app aren't the same as those issued by the Universal app on the server.
|
||||
Universal HTTP requests have different security requirements
|
||||
|
||||
应用从浏览器上发出的请求和从服务器上发出的请求是不同的。
|
||||
Universal 的 HTTP 请求有不同的安全需求。
|
||||
|
||||
When a browser makes an HTTP request, the server can make assumptions about cookies, XSRF headers, and so on.
|
||||
For example, the browser automatically sends authentication cookies for the current user.
|
||||
Angular Universal can't forward these credentials to a separate data server.
|
||||
If your server handles HTTP requests, you'll have to add your own security plumbing.
|
||||
|
||||
当浏览器发出 HTTP 请求时,服务器处理时会具有一些假设,比如 Cookie、XSRF 头等等。
|
||||
例如,浏览器会自动发送当前用户的认证 Cookie。
|
||||
Angular Universal 却没办法把这些凭证转发给独立的数据服务器。
|
||||
如果你的服务器要处理 HTTP 请求,你必须另行添加自己的通道来提供安全性。
|
||||
|
||||
</div>
|
||||
|
||||
## Step 1: Install dependencies
|
||||
|
||||
## 步骤一:安装依赖
|
||||
|
||||
Install `@angular/platform-server` into your project. Use the same version as the other `@angular` packages in your project. You also need `ts-loader` for your webpack build and `@nguniversal/module-map-ngfactory-loader` to handle lazy-loading in the context of a server-render.
|
||||
|
||||
把 `@angular/platform-server` 安装到项目中。在项目中使用与其它 `@angular` 包相同的版本。你还需要 `ts-loader` 供 Webpack 构建时使用,还要安装 `@nguniversal/module-map-ngfactory-loader` 来处理服务端渲染环境下的惰性加载。
|
||||
|
||||
```
|
||||
$ npm install --save @angular/platform-server @nguniversal/module-map-ngfactory-loader ts-loader
|
||||
```
|
||||
|
||||
## Step 2: Prepare your app
|
||||
|
||||
## 步骤二:准备你的应用
|
||||
|
||||
To prepare your app for Universal rendering, take the following steps:
|
||||
|
||||
要让你的应用为 Universal 渲染做好准备,要遵循如下步骤:
|
||||
|
||||
* Add Universal support to your app.
|
||||
|
||||
为应用添加 Universal 支持。
|
||||
|
||||
* Create a server root module.
|
||||
|
||||
创建服务端根模块。
|
||||
|
||||
* Create a main file to export the server root module.
|
||||
|
||||
创建一个 main 文件,以导出服务端根模块。
|
||||
|
||||
* Configure the server root module.
|
||||
|
||||
配置服务端根模块。
|
||||
|
||||
### 2a. Add Universal support to your app
|
||||
|
||||
### 2a. 为应用添加 Universal 支持
|
||||
|
||||
Make your `AppModule` compatible with Universal by adding `.withServerTransition()` and an application ID to your `BrowserModule` import in `src/app/app.module.ts`.
|
||||
|
||||
要想让你的 `AppModule` 与 Universal 兼容,就要在 `src/app/app.module.ts` 中导入时 `BrowserModule` 添加一个 `.withServerTransition()` 并带上应用的 ID。
|
||||
|
||||
<code-example format="." language="typescript" linenums="false">
|
||||
@NgModule({
|
||||
bootstrap: [AppComponent],
|
||||
|
@ -261,10 +330,16 @@ export class AppModule {}
|
|||
|
||||
### 2b. Create a server root module
|
||||
|
||||
### 2b. 创建服务端根模块
|
||||
|
||||
Create a module named `AppServerModule` to act as the root module when running on the server. This example places it alongside `app.module.ts` in a file named `app.server.module.ts`. The new module imports everything from the root `AppModule`, and adds `ServerModule`. It also adds `ModuleMapLoaderModule` to help make lazy-loaded routes possible during server-side renders with the Angular CLI.
|
||||
|
||||
在服务器上运行时,要创建一个名叫 `AppServerModule` 的模块作为根模块。这个例子中把它放在了 `app.module.ts` 附近的 `app.server.module.ts` 文件中。这个新模块从 `AppModule` 中导入了所有东西,并且导入了 `ServerModule`。它还导入了 `ModuleMapLoaderModule` 以帮助在服务端渲染时也能使用惰性加载路由。
|
||||
|
||||
Here's an example in `src/app/app.server.module.ts`.
|
||||
|
||||
下面是 `src/app/app.server.module.ts` 的例子。
|
||||
|
||||
<code-example format="." language="typescript" linenums="false">
|
||||
import {NgModule} from '@angular/core';
|
||||
import {ServerModule} from '@angular/platform-server';
|
||||
|
@ -290,19 +365,33 @@ export class AppServerModule {}
|
|||
|
||||
### 2c. Create a main file to export AppServerModule
|
||||
|
||||
### 2c. 创建一个 main 文件,导出 AppServerModule
|
||||
|
||||
Create a main file for your Universal bundle in the app `src/` folder to export your `AppServerModule` instance. This example calls the file `main.server.ts`.
|
||||
|
||||
在应用的 `src/` 目录下为你的 Universal 包创建一个 main 文件,以导出 `AppServerModule` 实例。在这个例子里它叫 `main.server.ts`。
|
||||
|
||||
<code-example format="." language="typescript" linenums="false">
|
||||
export { AppServerModule } from './app/app.server.module';
|
||||
</code-example>
|
||||
|
||||
### 2d. Create a configuration file for AppServerModule
|
||||
|
||||
### 2d. 为 AppServerModule 创建配置文件
|
||||
|
||||
Copy `tsconfig.app.json` to `tsconfig.server.json` and modify it as follows:
|
||||
|
||||
把 `tsconfig.app.json` 复制到 `tsconfig.server.json` 中,并做如下修改:
|
||||
|
||||
* In `"compilerOptions"`, set the `"module"` target to `"commonjs"`.
|
||||
|
||||
在 `"compilerOptions"` 中,把 `"module"` 改为 `"commonjs"`。
|
||||
|
||||
* Add a section for `"angularCompilerOptions"` and set `"entryModule"` to point to your `AppServerModule` instance. Use the format `importPath#symbolName`. In this example, the entry module is `app/app.server.module#AppServerModule`.
|
||||
|
||||
添加一个 `"angularCompilerOptions"` 节,并把 `"entryModule"`(入口模块)指向你的 `AppServerModule` 实例,格式为 `importPath#symbolName`。在这个例子中,这个入口模块是 `app/app.server.module#AppServerModule`。
|
||||
|
||||
|
||||
<code-example format="." language="none" linenums="false">
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
|
@ -327,8 +416,12 @@ Copy `tsconfig.app.json` to `tsconfig.server.json` and modify it as follows:
|
|||
|
||||
## Step 3: Create a new build target and build the bundle
|
||||
|
||||
## 步骤三:创建新的构建目标,并打包
|
||||
|
||||
Open the Angular configuration file, `angular.json`, for your project, and add a new target in the `"architect"` section for the server build. The following example names the new target `"server"`.
|
||||
|
||||
打开本项目的 Angular 配置文件 `angular.json`,并在 `"architect"` 节下添加一个新的目标。下面的例子中把这个新目标命名为 `"server"`。
|
||||
|
||||
<code-example format="." language="none" linenums="false">
|
||||
"architect": {
|
||||
"build": { ... }
|
||||
|
@ -345,6 +438,8 @@ Open the Angular configuration file, `angular.json`, for your project, and add a
|
|||
|
||||
To build a server bundle for your application, use the `ng run` command, with the format `projectName#serverTarget`. In our example, there are now two targets configured, `"build"` and `"server"`.
|
||||
|
||||
要想为应用程序构建服务包,请使用 `ng run` 命令,格式为 `projectName#serverTarget`。在这个例子中,目前已配置了两个目标 `"build"` 和 `"server"`。
|
||||
|
||||
<code-example format="." language="none" linenums="false">
|
||||
# This builds your project using the server target, and places the output
|
||||
# in dist/my-project-server/
|
||||
|
@ -359,10 +454,16 @@ chunk {1} styles.css (styles) 0 bytes [entry] [rendered]
|
|||
|
||||
## Step 4: Set up a server to run Universal bundles
|
||||
|
||||
## 步骤四:设置服务器环境,以运行 Universal 包
|
||||
|
||||
To run a Universal bundle, you need to send it to a server.
|
||||
|
||||
要想运行 Universal 包,你需要把它发送给服务器。
|
||||
|
||||
The following example passes `AppServerModule` (compiled with AoT) to the `PlatformServer` method `renderModuleFactory()`, which serializes the app and returns the result to the browser.
|
||||
|
||||
下面的例子中把 `AppServerModule`(用 AOT 编译的)传给了 `PlatformServer` 的 `renderModuleFactory()`,它会序列化该应用,并把结果返回给浏览器。
|
||||
|
||||
<code-example format="." language="typescript" linenums="false">
|
||||
app.engine('html', (_, options, callback) => {
|
||||
renderModuleFactory(AppServerModuleNgFactory, {
|
||||
|
@ -382,6 +483,8 @@ app.engine('html', (_, options, callback) => {
|
|||
|
||||
This technique gives you complete flexibility. For convenience, you can also use the `@nguniversal/express-engine` tool that has some built-in features.
|
||||
|
||||
该技术为你提供了完全的灵活性。方便起见,你还可以使用具有一些内置功能的 `@nguniversal/express-engine` 工具。
|
||||
|
||||
<code-example format="." language="typescript" linenums="false">
|
||||
import { ngExpressEngine } from '@nguniversal/express-engine';
|
||||
|
||||
|
@ -396,8 +499,13 @@ app.engine('html', ngExpressEngine({
|
|||
The following simple example implements a bare-bones Node Express server to fire everything up.
|
||||
(Note that this is for demonstration only. In a real production environment, you need to set up additional authentication and security.)
|
||||
|
||||
下面的简单例子实现了一个骨架级 Node Express 服务器来解决这些问题。
|
||||
(注意,它只能用于演示,在实际生产环境中,你还要设置身份验证和安全性。)
|
||||
|
||||
At the root level of your project, next to `package.json`, create a file named `server.ts` and add the following content.
|
||||
|
||||
在应用的根目录下,紧挨着 `package.json`,创建一个名叫 `server.ts` 的文件,并添加如下内容。
|
||||
|
||||
<code-example format="." language="typescript" linenums="false">
|
||||
// These are important and needed before anything else
|
||||
import 'zone.js/dist/zone-node';
|
||||
|
@ -460,10 +568,16 @@ app.listen(PORT, () => {
|
|||
|
||||
## Step 5: Pack and run the app on the server
|
||||
|
||||
## 步骤五:打包并在服务器上运行此应用
|
||||
|
||||
Set up a webpack configuration to handle the Node Express `server.ts` file and serve your application.
|
||||
|
||||
设置 webpack 配置,以处理 Node Express 的 `server.ts` 文件,并启动应用服务器。
|
||||
|
||||
In your app root directory, create a webpack configuration file (`webpack.server.config.js`) that compiles the `server.ts` file and its dependencies into `dist/server.js`.
|
||||
|
||||
在应用的根目录下,创建一个 Webpack 配置文件 `webpack.server.config.js`,它会把 `server.ts` 及其依赖编译到 `dist/server.js` 中。
|
||||
|
||||
<code-example format="." language="typescript" linenums="false">
|
||||
@NgModule({
|
||||
const path = require('path');
|
||||
|
@ -501,7 +615,9 @@ module.exports = {
|
|||
}
|
||||
</code-example>
|
||||
|
||||
The project's `dist/` folder now contains both browser and server folders.
|
||||
The project's `dist/` folder now contains both browser and server folders.
|
||||
|
||||
项目的 `dist/` 目录现在同时包含 browser 目录和 server 目录。
|
||||
|
||||
<code-example format="." language="none" linenums="false">
|
||||
dist/
|
||||
|
@ -511,15 +627,21 @@ dist/
|
|||
|
||||
To run the app on the server, type the following in a command shell.
|
||||
|
||||
要想在服务器上运行该应用,请在命令行窗口运行下列命令:
|
||||
|
||||
<code-example format="." language="bash" linenums="false">
|
||||
node dist/server.js
|
||||
</code-example>
|
||||
|
||||
### Creating scripts
|
||||
|
||||
### 创建一些脚本
|
||||
|
||||
Now let's create a few handy scripts to help us do all of this in the future.
|
||||
You can add these in the `"server"` section of the Angular configuration file, `angular.json`.
|
||||
|
||||
现在,来创建一些便利脚本,在以后帮助我们完成这些琐事。
|
||||
|
||||
<code-example format="." language="none" linenums="false">
|
||||
"architect": {
|
||||
"build": { ... }
|
||||
|
@ -539,6 +661,8 @@ You can add these in the `"server"` section of the Angular configuration file, `
|
|||
|
||||
To run a production build of your app with Universal on your local system, use the following command.
|
||||
|
||||
要想在本地系统上使用 Universal 运行应用的生产版本,请使用如下命令:
|
||||
|
||||
<code-example format="." language="bash" linenums="false">
|
||||
npm run build:ssr && npm run serve:ssr
|
||||
</code-example>
|
||||
|
@ -575,7 +699,7 @@ Universal 应用必须仅仅根据客户端过来的请求决定要渲染的内
|
|||
Because the user of a server-rendered page can't do much more than click links,
|
||||
you should swap in the real client app as quickly as possible for a proper interactive experience.
|
||||
|
||||
由于服务端渲染页面的用户只能点击链接,所以你应该尽快让它[切换到真正的客户端应用](#transition),以提供正常的交互体验。
|
||||
由于服务端渲染页面的用户只能点击链接,所以你应该尽快让它切换到真正的客户端应用,以提供正常的交互体验。
|
||||
|
||||
{@a the-example}
|
||||
|
||||
|
@ -585,7 +709,7 @@ you should swap in the real client app as quickly as possible for a proper inter
|
|||
|
||||
The [Tour of Heroes tutorial](tutorial) is the foundation for this walkthrough.
|
||||
|
||||
《英雄指南》教程是本章所讲的 Universal 范例的基础。
|
||||
[《英雄指南》教程](tutorial)是本章所讲的 Universal 范例的基础。
|
||||
|
||||
The core application files are mostly untouched, with a few exceptions described below.
|
||||
You'll add more files to support building and serving with Universal.
|
||||
|
@ -663,13 +787,14 @@ inject it into the service, and prepend the origin to the request URL.
|
|||
|
||||
Start by changing the `HeroService` constructor to take a second `origin` parameter that is optionally injected via the `APP_BASE_HREF` token.
|
||||
|
||||
先为 `HeroService` 的构造函数添加第二个 `origin` 参数,它是可选的,并通过 `APP_BASE_HREF` 令牌进行注入。
|
||||
先为 `HeroService` 的构造函数添加第二个参数 `origin`,它是可选的,并通过 `APP_BASE_HREF` 令牌进行注入。
|
||||
|
||||
<code-example path="universal/src/app/hero.service.ts" region="ctor" header="src/app/hero.service.ts (constructor with optional origin)">
|
||||
</code-example>
|
||||
|
||||
The constructor uses the `@Optional()` directive to prepend the origin to `heroesUrl` _if it exists_.
|
||||
注意,这个构造函数是如何把这个 `origin`(如果存在)添加到 `heroesUrl` 的前面的。
|
||||
|
||||
这个构造函数使用了 `@Optional()` 指令来为 `heroesUrl` 添加源(如果有的话)。
|
||||
|
||||
You don't provide `APP_BASE_HREF` in the browser version, so `heroesUrl` remains relative.
|
||||
|
||||
|
@ -687,11 +812,11 @@ You don't provide `APP_BASE_HREF` in the browser version, so `heroesUrl` remains
|
|||
|
||||
### Universal template engine
|
||||
|
||||
#### Universal 模板引擎
|
||||
### Universal 模板引擎
|
||||
|
||||
The important bit in the `server.ts` file is the `ngExpressEngine()` function.
|
||||
|
||||
这个文件中最重要的部分是 `ngExpressEngine` 函数:
|
||||
`server.ts` 文件中最重要的部分是 `ngExpressEngine()` 函数:
|
||||
|
||||
<code-example path="universal/server.ts" header="server.ts" region="ngExpressEngine">
|
||||
</code-example>
|
||||
|
@ -699,7 +824,7 @@ The important bit in the `server.ts` file is the `ngExpressEngine()` function.
|
|||
The `ngExpressEngine()` function is a wrapper around Universal's `renderModuleFactory()` function which turns a client's requests into server-rendered HTML pages.
|
||||
You'll call that function within a _template engine_ that's appropriate for your server stack.
|
||||
|
||||
`ngExpressEngine` 是对 Universal 的 `renderModuleFactory` 函数的封装。它会把客户端请求转换成服务端渲染的 HTML 页面。
|
||||
`ngExpressEngine()` 是对 Universal 的 `renderModuleFactory()` 函数的封装。它会把客户端请求转换成服务端渲染的 HTML 页面。
|
||||
你还要在某个适用于你服务端技术栈的*模板引擎*中调用这个函数。
|
||||
|
||||
* The first parameter is `AppServerModule`.
|
||||
|
@ -718,20 +843,21 @@ The required information in this case is the running server's *origin*, provided
|
|||
|
||||
The `ngExpressEngine()` function returns a `Promise` callback that resolves to the rendered page.
|
||||
|
||||
`ngExpressEngine` 函数返回了一个会解析成渲染好的页面的*承诺(Promise)*。
|
||||
`ngExpressEngine()` 函数返回了一个会解析成渲染好的页面的*承诺(Promise)*。
|
||||
|
||||
It's up to your engine to decide what to do with that page.
|
||||
This engine's `Promise` callback returns the rendered page to the web server,
|
||||
which then forwards it to the client in the HTTP response.
|
||||
|
||||
接下来你的引擎要决定拿这个页面做点什么。
|
||||
*现在这个引擎*的回调函数中,把渲染好的页面返回给了 [Web 服务器](#web-server),然后服务器通过 HTTP 响应把它转发给了客户端。
|
||||
在*这个引擎*的 `Promise` 回调函数中,把渲染好的页面返回给了 Web 服务器,然后服务器通过 HTTP 响应把它转发给了客户端。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
**Note:** These wrappers help hide the complexity of the `renderModuleFactory()` function. There are more wrappers for different backend technologies
|
||||
at the [Universal repository](https://github.com/angular/universal).
|
||||
|
||||
这个包装器对于隐藏 `renderModuleFactory` 的复杂性非常有帮助。
|
||||
**注意:** 这个包装器帮助隐藏了 `renderModuleFactory()` 的复杂性。
|
||||
在 [Universal 代码库中](https://github.com/angular/universal)还有更多针对其它后端技术的包装器。
|
||||
|
||||
</div>
|
||||
|
@ -816,7 +942,7 @@ such as JavaScript, image, and style files.
|
|||
|
||||
To ensure that clients can only download the files that they are permitted to see, put all client-facing asset files in the `/dist` folder and only honor requests for files from the `/dist` folder.
|
||||
|
||||
要保证客户端只能下载那些*允许*他们访问的文件,你应该[把所有面向客户端的资源文件都放在 `/dist` 目录下](#universal-webpack-configuration),并且只允许客户端请求来自 `/dist` 目录下的文件。
|
||||
要保证客户端只能下载那些*允许*他们访问的文件,你应该把所有面向客户端的资源文件都放在 `/dist` 目录下,并且只允许客户端请求来自 `/dist` 目录下的文件。
|
||||
|
||||
The following Node Express code routes all remaining requests to `/dist`, and returns a `404 - NOT FOUND` error if the file isn't found.
|
||||
|
||||
|
@ -840,6 +966,10 @@ Navigation via `routerLinks` works correctly.
|
|||
You can go from the Dashboard to the Heroes page and back.
|
||||
You can click a hero on the Dashboard page to display its Details page.
|
||||
|
||||
通过 `routerLinks` 进行导航可以正常工作了。
|
||||
你可以从仪表盘前往英雄列表页,也可以返回。
|
||||
也可以点击仪表盘页面上的一位英雄,并显示器详情页。
|
||||
|
||||
Notice, however, that clicks, mouse-moves, and keyboard entries are inert.
|
||||
|
||||
但要注意,点击、鼠标移动和键盘操作都是不行的。
|
||||
|
@ -868,8 +998,6 @@ and move the output into the `dist/` folder.
|
|||
除了点击 `RouterLink` 之外的用户事件都不支持。你必须等待完整的客户端应用就绪。
|
||||
直到你编译出了客户端应用,并把它们的输出移到 `dist/` 目录下之后,这个客户端应用才会就绪。
|
||||
|
||||
## 限流
|
||||
|
||||
The transition from the server-rendered app to the client app happens quickly on a development machine.
|
||||
You can simulate a slower network to see the transition more clearly and
|
||||
better appreciate the launch-speed advantage of a Universal app running on a low-powered, poorly connected device.
|
||||
|
|
|
@ -87,7 +87,7 @@ Angular 升级指南提供了自定义的升级指令,基于当前版本和你
|
|||
|
||||
For simple updates, the CLI command [`ng update`](cli/update) is all you need. Without additional arguments, `ng update` lists the updates that are available to you and provides recommended steps to update your application to the most current version.
|
||||
|
||||
对于简单的升级工作,执行[CLI 命令 `ng update`](https://github.com/angular/angular-cli/wiki/update "Angular CLI update documentation")就是你所要做的一切。不带额外参数时,`ng update` 会列出你可用的更新版本,并提供建议的升级步骤,来把你的应用升级到最新版本上来。
|
||||
对于简单的升级工作,你所要做的一切就是执行一下 CLI 命令 [`ng update`](cli/update)。不带额外参数时,`ng update` 会列出你可用的更新版本,并提供建议的升级步骤,来把你的应用升级到最新版本上来。
|
||||
|
||||
{@a resources}
|
||||
|
||||
|
@ -113,7 +113,7 @@ For simple updates, the CLI command [`ng update`](cli/update) is all you need. W
|
|||
|
||||
* Update command reference: [Angular CLI `ng update` command reference](cli/update)
|
||||
|
||||
升级命令参考文档:[Angular CLI 升级文档](https://github.com/angular/angular-cli/wiki/update "Angular CLI update documentation")
|
||||
升级命令参考文档:[Angular CLI `ng update` 命令参考手册](cli/update)
|
||||
|
||||
* Versioning, release, support, and deprecation practices: [Angular versioning and releases](guide/releases "Angular versioning and releases")
|
||||
|
||||
|
|
|
@ -1203,7 +1203,7 @@ code. For example, you might have a service called `HeroesService` in AngularJS:
|
|||
You can upgrade the service using a Angular [factory provider](guide/dependency-injection-providers#factory-providers)
|
||||
that requests the service from the AngularJS `$injector`.
|
||||
|
||||
你可以 Angular 的[工厂提供商(factory provider)](guide/dependency-injection#factory-providers)升级该服务,
|
||||
你可以 Angular 的[工厂提供商](guide/dependency-injection-providers#factory-providers)升级该服务,
|
||||
它从 AngularJS 的 `$injector` 请求服务。Angular 依赖的名称由你确定:
|
||||
|
||||
Many developers prefer to declare the factory provider in a separate `ajs-upgraded-providers.ts` file
|
||||
|
@ -1223,6 +1223,9 @@ compilation can pick it up.
|
|||
It is common in AngularJS apps to choose a service name for the token, for example "heroes",
|
||||
and append the "Service" suffix to create the class name.
|
||||
|
||||
**注意:**这个工厂中的字符串 'heroes' 指向的是 AngularJS 的 `HeroesService`。
|
||||
AngularJS 应用中通常使用服务名作为令牌,比如 'heroes',并为其追加 'Service' 后缀来创建其类名。
|
||||
|
||||
</div>
|
||||
|
||||
<code-example path="upgrade-module/src/app/ajs-to-a-providers/ajs-upgraded-providers.ts" header="ajs-upgraded-providers.ts">
|
||||
|
@ -1230,12 +1233,14 @@ and append the "Service" suffix to create the class name.
|
|||
|
||||
You can then provide the service to Angular by adding it to the `@NgModule`:
|
||||
|
||||
然后,你就可以把这个服务添加到 `@NgModule` 中来把它暴露给 Angular:
|
||||
|
||||
<code-example path="upgrade-module/src/app/ajs-to-a-providers/app.module.ts" region="register" header="app.module.ts">
|
||||
</code-example>
|
||||
|
||||
Then use the service inside your component by injecting it in the component constructor using its class as a type annotation:
|
||||
|
||||
然后你就可以使用它的类作为类型注解将其在 Angular 中进行注入了:
|
||||
然后你就可以用它的类作为类型注解把它在 Angular 中进行注入了:
|
||||
|
||||
<code-example path="upgrade-module/src/app/ajs-to-a-providers/hero-detail.component.ts" header="hero-detail.component.ts">
|
||||
</code-example>
|
||||
|
@ -2038,7 +2043,7 @@ Finally, bootstrap the `AppModule` in `app/main.ts`.
|
|||
This file has been configured as the application entrypoint in `systemjs.config.js`,
|
||||
so it is already being loaded by the browser.
|
||||
|
||||
最后,在 `src/main.ts` 中引导这个 `AppModule`。该文件在 `systemjs.config.js` 中被配置为了应用的入口,所以它已经被加载进了浏览器中。
|
||||
最后,在 `app/main.ts` 中引导这个 `AppModule`。该文件在 `systemjs.config.js` 中被配置为了应用的入口,所以它已经被加载进了浏览器中。
|
||||
|
||||
<code-example path="upgrade-phonecat-2-hybrid/app/main.ts" region="bootstrap" header="app/main.ts">
|
||||
</code-example>
|
||||
|
|
|
@ -11,7 +11,7 @@ Some developers prefer Visual Studio as their Integrated Development Environment
|
|||
This cookbook describes the steps required to set up and use the
|
||||
Angular [Getting Started](guide/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 “[快速上手](guide/quickstart)”所需的步骤。
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
|
@ -119,15 +119,15 @@ Visual Studio 将优先在当前的工作区查找外部工具,如果没有找
|
|||
While Visual Studio Update 3 ships with TypeScript support out of the box, it currently doesn’t ship with TypeScript 3.1,
|
||||
which you need to develop Angular applications.
|
||||
|
||||
Visual Studio Update 3 自带 TypeScript 支持,但是它的 TypeScript 版本开发 Angular 应用需要的不是 2.2。
|
||||
Visual Studio Update 3 自带 TypeScript 支持,但它的 TypeScript 版本不是开发 Angular 应用所需的 3.1。
|
||||
|
||||
To install TypeScript 3.1:
|
||||
|
||||
要安装 TypeScript 2.2:
|
||||
要安装 TypeScript 3.1:
|
||||
|
||||
* Download and install [TypeScript 3.1 for Visual Studio 2015](https://www.microsoft.com/en-us/download/details.aspx?id=48593),
|
||||
|
||||
下载并安装 **[TypeScript 2.2 for Visual Studio 2015](https://www.microsoft.com/en-us/download/details.aspx?id=48593)**
|
||||
下载并安装 **[TypeScript 3.1 for Visual Studio 2015](https://www.microsoft.com/en-us/download/details.aspx?id=48593)**
|
||||
|
||||
* OR install it with npm: `npm install -g typescript@3.1`.
|
||||
|
||||
|
@ -135,7 +135,7 @@ To install TypeScript 3.1:
|
|||
|
||||
You can find out more about TypeScript 3.1 support in Visual Studio **[here](https://blogs.msdn.microsoft.com/typescript/announcing-typescript-3-1/)**.
|
||||
|
||||
你可以在**[这儿](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 3.1 的支持。
|
||||
|
||||
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.
|
||||
|
@ -145,6 +145,7 @@ restart it to make sure everything is clean.
|
|||
<h2 id='download'>Step 1: Download the Angular Getting Started app</h2>
|
||||
|
||||
<h2 id='download'>第一步: 现在“快速上手”文件</h2>
|
||||
|
||||
Go to the final code review in [Getting Started](guide/quickstart) and download the solution app project. These files contain a starter Angular app.
|
||||
|
||||
从 GitHub[下载“快速上手”的源代码](https://github.com/angular/quickstart)。如果下载的是一个压缩的 zip 文件,解压它。
|
||||
|
|
|
@ -164,8 +164,8 @@
|
|||
},
|
||||
{
|
||||
"url": "guide/user-input",
|
||||
"title": "User Input",
|
||||
"tooltip": "User input triggers DOM events. Angular listens to those events with event bindings that funnel updated values back into your app's components and models."
|
||||
"title": "用户输入",
|
||||
"tooltip": "用户输入会触发 DOM 事件。Angular 会通过事件绑定来监听那些事件,并把修改后的值传回应用的组件和模型中。"
|
||||
},
|
||||
{
|
||||
"url": "guide/lifecycle-hooks",
|
||||
|
@ -480,8 +480,8 @@
|
|||
},
|
||||
{
|
||||
"url": "guide/upgrade-performance",
|
||||
"title": "Upgrading for Performance",
|
||||
"tooltip": "Upgrade from AngularJS to Angular in a more flexible way."
|
||||
"title": "提高升级效率",
|
||||
"tooltip": "用更灵活的方式把 AngularJS 升级到 Angular"
|
||||
},
|
||||
{
|
||||
"url": "guide/ajs-quick-reference",
|
||||
|
@ -494,51 +494,51 @@
|
|||
},
|
||||
|
||||
{
|
||||
"title": "Setup & Deployment",
|
||||
"tooltip": "Setup, build, testing, and deployment environment and tool information.",
|
||||
"title": "环境搭建与部署",
|
||||
"tooltip": "关于环境搭建、构建、测试、部署环境与工具的信息。",
|
||||
"children": [
|
||||
|
||||
{
|
||||
"url": "guide/setup",
|
||||
"title": "Setup for local development",
|
||||
"tooltip": "Install the Angular QuickStart seed for faster, more efficient development on your machine.",
|
||||
"title": "搭建本地开发环境",
|
||||
"tooltip": "安装 Angular 快速起步种子工程,以便在你的电脑上更快、更高效的开发。",
|
||||
"hidden": true
|
||||
},
|
||||
|
||||
{
|
||||
"url": "guide/file-structure",
|
||||
"title": "Project File Structure",
|
||||
"tooltip": "How your Angular workspace looks in your filesystem."
|
||||
"title": "项目文件结构",
|
||||
"tooltip": "Angular 工作空间在文件系统中是怎样的。"
|
||||
},
|
||||
{
|
||||
"url": "guide/npm-packages",
|
||||
"title": "Packages",
|
||||
"tooltip": "Explanation of npm packages installed into a project by default."
|
||||
"title": "npm 包",
|
||||
"tooltip": "会默认安装到项目中的 npm 包的说明。"
|
||||
},
|
||||
{
|
||||
"url": "guide/typescript-configuration",
|
||||
"title": "TypeScript Configuration",
|
||||
"tooltip": "TypeScript configuration for Angular developers."
|
||||
"title": "TypeScript 配置",
|
||||
"tooltip": "给 Angular 开发者的 TypeScript 配置。"
|
||||
},
|
||||
{
|
||||
"url": "guide/aot-compiler",
|
||||
"title": "Ahead-of-Time Compilation",
|
||||
"tooltip": "Learn why and how to use the Ahead-of-Time (AOT) compiler."
|
||||
"title": "预先(AOT)编译",
|
||||
"tooltip": "了解为何以及如何使用预先(AOT)编译器。"
|
||||
},
|
||||
{
|
||||
"url": "guide/build",
|
||||
"title": "Building & Serving",
|
||||
"tooltip": "Building and serving Angular apps."
|
||||
"title": "构建与启动开发服务器",
|
||||
"tooltip": "构建应用及为应用启动开发服务器。"
|
||||
},
|
||||
{
|
||||
"url": "guide/testing",
|
||||
"title": "Testing",
|
||||
"tooltip": "Techniques and practices for testing an Angular app."
|
||||
"title": "测试",
|
||||
"tooltip": "测试 Angular 应用的技巧与实践。"
|
||||
},
|
||||
{
|
||||
"url": "guide/deployment",
|
||||
"title": "Deployment",
|
||||
"tooltip": "Learn how to deploy your Angular app."
|
||||
"title": "发布",
|
||||
"tooltip": "了解如何部署 Angular 应用。"
|
||||
},
|
||||
{
|
||||
"url": "guide/browser-support",
|
||||
|
|
|
@ -1,38 +1,78 @@
|
|||
# The Application Shell
|
||||
|
||||
# 应用的外壳
|
||||
|
||||
You begin by creating an initial application using the Angular CLI. Throughout this tutorial, you’ll modify and extend that starter application to create the Tour of Heroes app.
|
||||
|
||||
首先,使用 Angular CLI 来创建最初的应用程序。
|
||||
在本教程中,你将修改并扩展这个入门级的应用程序,以创建出《英雄指南》应用。
|
||||
|
||||
In this part of the tutorial, you'll do the following:
|
||||
|
||||
在教程的这个部分,你要做下列工作:
|
||||
|
||||
1. Set up your environment.
|
||||
|
||||
设置开发环境。
|
||||
|
||||
2. Create a new workspace and initial app project.
|
||||
|
||||
创建新的工作空间,并初始化应用项目。
|
||||
|
||||
3. Serve the application.
|
||||
|
||||
启动开发服务器。
|
||||
|
||||
4. Make changes to the application.
|
||||
|
||||
修改此应用。
|
||||
|
||||
## Set up your environment
|
||||
|
||||
## 设置开发环境
|
||||
|
||||
To set up your development environment, follow these instructions in [Getting Started](guide/quickstart):
|
||||
|
||||
要想设置开发环境,请按照[快速上手](guide/quickstart) 中的说明进行操作:
|
||||
|
||||
* [Prerequisites](guide/quickstart#prerequisites)
|
||||
|
||||
[先决条件](guide/quickstart#prerequisites)
|
||||
|
||||
* [Install the Angular CLI](guide/quickstart#install-cli)
|
||||
|
||||
[安装 Angular CLI](guide/quickstart#install-cli)
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
**Note:**: You do not need to complete the entire Getting Started. After you complete the above two sections of Getting Started, your environment is set up. Continue below to create the Tour of Heroes workspace and an initial app project.
|
||||
|
||||
**注意:**你不用做完整个快速上手。只要完成了上面这两个部分,你的环境就已经设置好了。然后继续下面的步骤来创建一个《英雄指南》的工作空间和一个初始应用项目。
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
## Create a new workspace and an initial application
|
||||
|
||||
## 创建新的工作空间和一个初始应用
|
||||
|
||||
You develop apps in the context of an Angular [workspace](guide/glossary#workspace). A workspace contains the files for one or more [projects](guide/glossary#project). A project is the set of files that comprise an app, a library, or end-to-end (e2e) tests. For this tutorial, you will create a new workspace.
|
||||
|
||||
Angular 的[工作空间](guide/glossary#workspace)就是你开发应用所在的上下文环境。一个工作空间包含一个或多个[项目](guide/glossary#project)所需的文件。
|
||||
每个项目都是一组由应用、库或端到端(e2e)测试组成的文件集合。
|
||||
在本教程中,你将创建一个新的工作空间。
|
||||
|
||||
To create a new workspace and an initial app project:
|
||||
|
||||
要想创建一个新的工作空间和一个初始应用项目,需要:
|
||||
|
||||
1. Ensure that you are not already in an Angular workspace folder. For example, if you have previously created the Getting Started workspace, change to the parent of that folder.
|
||||
|
||||
确保你现在没有位于 Angular 工作区的文件夹中。例如,如果你之前已经创建过 "快速上手" 工作空间,请回到其父目录中。
|
||||
|
||||
2. Run the CLI command `ng new` and provide the name `angular-tour-of-heroes`, as shown here:
|
||||
|
||||
使用 CLI 命令创建一个名叫 `angular-tour-of-heroes` 的新项目。
|
||||
运行 CLI 命令 `ng new`,空间名请使用 `angular-tour-of-heroes`,如下所示:
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
ng new angular-tour-of-heroes
|
||||
|
@ -40,24 +80,43 @@ To create a new workspace and an initial app project:
|
|||
|
||||
3. The `ng new` command prompts you for information about features to include in the initial app project. Accept the defaults by pressing the Enter or Return key.
|
||||
|
||||
`ng new` 命令会提示你输入要在初始应用项目中包含哪些特性,请按 Enter 或 Return 键接受其默认值。
|
||||
|
||||
The Angular CLI installs the necessary Angular `npm` packages and other dependencies. This can take a few minutes.
|
||||
|
||||
Angular CLI 会安装必要的 Angular `npm` 包和其它依赖项。这可能需要几分钟。
|
||||
|
||||
It also creates the following workspace and starter project files:
|
||||
|
||||
它还会创建下列工作空间和初始项目的文件:
|
||||
|
||||
* A new workspace, with a root folder named `angular-tour-of-heroes`.
|
||||
|
||||
新的工作空间,其根目录名叫 `angular-tour-of-heroes`。
|
||||
|
||||
* An initial skeleton app project, also called `angular-tour-of-heroes` (in the `src` subfolder).
|
||||
|
||||
一个最初的骨架应用项目,同样叫做 `angular-tour-of-heroes`(位于 `src` 子目录下)。
|
||||
|
||||
* An end-to-end test project (in the e2e subfolder).
|
||||
|
||||
一个端到端测试项目(位于 e2e 子目录下)。
|
||||
|
||||
* Related configuration files.
|
||||
|
||||
相关的配置文件。
|
||||
|
||||
The initial app project contains a simple Welcome app, ready to run.
|
||||
|
||||
初始应用项目是一个简单的 "欢迎" 应用,随时可以运行它。
|
||||
|
||||
## Serve the application
|
||||
|
||||
## 启动应用服务器
|
||||
|
||||
Go to the workspace directory and launch the application.
|
||||
|
||||
进入项目目录,并启动这个应用。
|
||||
进入工作空间目录,并启动这个应用。
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
cd angular-tour-of-heroes
|
||||
|
@ -103,7 +162,7 @@ They display data on the screen, listen for user input, and take action based on
|
|||
|
||||
Open the project in your favorite editor or IDE and navigate to the `src/app` folder to make some changes to the starter app.
|
||||
|
||||
用你最喜欢的编辑器或 IDE 打开这个项目,并访问 `src/app` 目录。
|
||||
用你最喜欢的编辑器或 IDE 打开这个项目,并访问 `src/app` 目录,来对这个起始应用做一些修改。
|
||||
|
||||
You'll find the implementation of the shell `AppComponent` distributed over three files:
|
||||
|
||||
|
@ -112,6 +171,7 @@ You'll find the implementation of the shell `AppComponent` distributed over thre
|
|||
1. `app.component.ts`— the component class code, written in TypeScript.
|
||||
|
||||
`app.component.ts`— 组件的类代码,这是用 TypeScript 写的。
|
||||
|
||||
1. `app.component.html`— the component template, written in HTML.
|
||||
|
||||
`app.component.html`— 组件的模板,这是用 HTML 写的。
|
||||
|
@ -156,7 +216,7 @@ The browser refreshes and displays the new application title.
|
|||
|
||||
### Add application styles
|
||||
|
||||
## 添加应用样式
|
||||
### 添加应用样式
|
||||
|
||||
Most apps strive for a consistent look across the application.
|
||||
The CLI generated an empty `styles.css` for this purpose.
|
||||
|
|
|
@ -36,19 +36,35 @@ Use the Angular CLI to generate a new component named `hero-detail`.
|
|||
|
||||
The command scaffolds the following:
|
||||
|
||||
这个命令会做这些事:
|
||||
|
||||
* Creates a directory `src/app/hero-detail`.
|
||||
|
||||
创建目录 `src/app/hero-detail`。
|
||||
|
||||
Inside that directory four files are generated:
|
||||
|
||||
在这个目录中会生成四个文件:
|
||||
|
||||
* A CSS file for the component styles.
|
||||
|
||||
作为组件样式的 CSS 文件。
|
||||
|
||||
* An HTML file for the component template.
|
||||
|
||||
作为组件模板的 HTML 文件。
|
||||
|
||||
* A TypeScript file with a component class named `HeroDetailComponent`.
|
||||
|
||||
存放组件类 `HeroDetailComponent` 的 TypeScript 文件。
|
||||
|
||||
* A test file for the `HeroDetailComponent` class.
|
||||
|
||||
`HeroDetailComponent` 类的测试文件。
|
||||
|
||||
The command also adds the `HeroDetailComponent` as a declaration in the `@NgModule` decorator of the `src/app/app.module.ts` file.
|
||||
|
||||
|
||||
该命令会生成 `HeroDetailComponent` 文件的脚手架,并把它声明在 `AppModule` 中。
|
||||
该命令还会把 `HeroDetailComponent` 添加到 `src/app/app.module.ts` 文件中 `@NgModule` 的 `declarations` 列表中。
|
||||
|
||||
### Write the template
|
||||
|
||||
|
|
|
@ -350,7 +350,7 @@ The _class_ is similar to the `HeroesComponent` class.
|
|||
|
||||
This `getHeroes` returns the sliced list of heroes at positions 1 and 5, returning only four of the Top Heroes (2nd, 3rd, 4th, and 5th).
|
||||
|
||||
这个 `getHeroes` 函数把要显示的英雄的数量缩减为四个(第二、第三、第四、第五)。
|
||||
这个 `getHeroes` 函数会截取第 2 到 第 5 位英雄,也就是说只返回四个顶级英雄(第二,第三,第四和第五)。
|
||||
|
||||
<code-example path="toh-pt5/src/app/dashboard/dashboard.component.ts" region="getHeroes">
|
||||
</code-example>
|
||||
|
|
|
@ -184,7 +184,8 @@ Define the `heroesUrl` of the form `:base/:collectionName` with the address of t
|
|||
Here `base` is the resource to which requests are made,
|
||||
and `collectionName` is the heroes data object in the `in-memory-data-service.ts`.
|
||||
|
||||
把服务器上英雄数据资源的访问地址定义为 `heroesURL`。
|
||||
把服务器上英雄数据资源的访问地址 `heroesURL` 定义为 `:base/:collectionName` 的形式。
|
||||
这里的 `base` 是要请求的资源,而 `collectionName` 是 `in-memory-data-service.ts` 中的英雄数据对象。
|
||||
|
||||
<code-example
|
||||
path="toh-pt6/src/app/hero.service.ts"
|
||||
|
@ -330,7 +331,7 @@ innocuous result so that the application keeps working.
|
|||
The following `handleError()` will be shared by many `HeroService` methods
|
||||
so it's generalized to meet their different needs.
|
||||
|
||||
下面这个 `errorHandler()` 将会在很多 `HeroService` 的方法之间共享,所以要把它通用化,以支持这些彼此不同的需求。
|
||||
下面这个 `handleError()` 将会在很多 `HeroService` 的方法之间共享,所以要把它通用化,以支持这些彼此不同的需求。
|
||||
|
||||
Instead of handling the error directly, it returns an _error handler_ function to `catchError` that it
|
||||
has configured with both the name of the operation that failed and a safe return value.
|
||||
|
@ -350,7 +351,7 @@ a user friendly message and returns a safe value to the app so it can keep worki
|
|||
Because each service method returns a different kind of `Observable` result,
|
||||
`handleError()` takes a type parameter so it can return the safe value as the type that the app expects.
|
||||
|
||||
因为每个服务方法都会返回不同类型的 `Observable` 结果,因此 `errorHandler()` 也需要一个类型参数,以便它返回一个此类型的安全值,正如应用所期望的那样。
|
||||
因为每个服务方法都会返回不同类型的 `Observable` 结果,因此 `handleError()` 也需要一个类型参数,以便它返回一个此类型的安全值,正如应用所期望的那样。
|
||||
|
||||
### Tap into the _Observable_
|
||||
|
||||
|
@ -384,12 +385,14 @@ Here is the final version of `getHeroes` with the `tap` that logs the operation.
|
|||
|
||||
Most web APIs support a _get by id_ request in the form `:baseURL/:id`.
|
||||
|
||||
大多数的 Web API 都支持以 `:baseURL/:id` 的形式根据 id 进行获取。
|
||||
|
||||
Here, the _base URL_ is the `heroesURL` defined in the [Heroes and HTTP](http://localhost:4800/tutorial/toh-pt6#heroes-and-http) section (`api/heroes`) and _id_ is
|
||||
the number of the hero that you want to retrieve. For example, `api/heroes/11`.
|
||||
Add a `HeroService.getHero()` method to make that request:
|
||||
|
||||
大多数 web API 都可以通过 `api/hero/:id` 的形式(比如 `api/hero/:id` )支持*根据 id 获取单个对象*。
|
||||
添加一个 `HeroService.getHero()` 方法来发起请求:
|
||||
这里的 `baseURL` 就是在 [英雄列表与 HTTP](http://localhost:4800/tutorial/toh-pt6#heroes-and-http) 部分定义过的 `heroesURL`(`api/heroes`)。而 `id` 则是你要获取的英雄的编号,比如,`api/heroes/11`。
|
||||
添加一个 `HeroService.getHero()` 方法,以发起该请求:
|
||||
|
||||
<code-example path="toh-pt6/src/app/hero.service.ts" region="getHero" header="src/app/hero.service.ts"></code-example>
|
||||
|
||||
|
|
|
@ -1085,6 +1085,7 @@ assert@^1.1.1:
|
|||
assertion-error@^1.0.1:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b"
|
||||
integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==
|
||||
|
||||
assign-symbols@^1.0.0:
|
||||
version "1.0.0"
|
||||
|
@ -1847,6 +1848,7 @@ center-align@^0.1.1:
|
|||
chai@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/chai/-/chai-4.1.2.tgz#0f64584ba642f0f2ace2806279f4f06ca23ad73c"
|
||||
integrity sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=
|
||||
dependencies:
|
||||
assertion-error "^1.0.1"
|
||||
check-error "^1.0.1"
|
||||
|
@ -1855,16 +1857,6 @@ chai@^4.1.2:
|
|||
pathval "^1.0.0"
|
||||
type-detect "^4.0.0"
|
||||
|
||||
chalk@0.5.1:
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174"
|
||||
dependencies:
|
||||
ansi-styles "^1.1.0"
|
||||
escape-string-regexp "^1.0.0"
|
||||
has-ansi "^0.1.0"
|
||||
strip-ansi "^0.3.0"
|
||||
supports-color "^0.2.0"
|
||||
|
||||
chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
|
||||
|
@ -1967,6 +1959,11 @@ charenc@~0.0.1:
|
|||
resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
|
||||
integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=
|
||||
|
||||
check-error@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
|
||||
integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=
|
||||
|
||||
chokidar@2.0.4:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26"
|
||||
|
@ -1987,10 +1984,6 @@ chokidar@2.0.4:
|
|||
optionalDependencies:
|
||||
fsevents "^1.2.2"
|
||||
|
||||
check-error@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
|
||||
|
||||
chokidar@^1.4.1, chokidar@^1.4.2, chokidar@^1.6.0:
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
|
||||
|
@ -2116,12 +2109,6 @@ clean-css@4.2.1:
|
|||
dependencies:
|
||||
source-map "~0.6.0"
|
||||
|
||||
clean-css@4.2.x:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.1.tgz#2d411ef76b8569b6d0c84068dabe85b0aa5e5c17"
|
||||
dependencies:
|
||||
source-map "~0.6.0"
|
||||
|
||||
cli-boxes@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143"
|
||||
|
@ -2317,14 +2304,6 @@ commander@^2.12.1, commander@^2.9.0:
|
|||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f"
|
||||
integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==
|
||||
|
||||
commander@2.17.x, commander@~2.17.1:
|
||||
version "2.17.1"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
|
||||
|
||||
commander@2.6.0:
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.6.0.tgz#9df7e52fb2a0cb0fb89058ee80c3104225f37e1d"
|
||||
|
||||
commander@^2.8.1, commander@~2.11.0:
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563"
|
||||
|
@ -2963,6 +2942,7 @@ decompress-response@^3.2.0:
|
|||
deep-eql@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df"
|
||||
integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==
|
||||
dependencies:
|
||||
type-detect "^4.0.0"
|
||||
|
||||
|
@ -4583,6 +4563,7 @@ get-caller-file@^1.0.1:
|
|||
get-func-name@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41"
|
||||
integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=
|
||||
|
||||
get-stdin@^4.0.1:
|
||||
version "4.0.1"
|
||||
|
@ -5244,18 +5225,6 @@ html-entities@^1.2.0:
|
|||
resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f"
|
||||
integrity sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=
|
||||
|
||||
html-minifier@^3.5.20:
|
||||
version "3.5.20"
|
||||
resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.20.tgz#7b19fd3caa0cb79f7cde5ee5c3abdf8ecaa6bb14"
|
||||
dependencies:
|
||||
camel-case "3.0.x"
|
||||
clean-css "4.2.x"
|
||||
commander "2.17.x"
|
||||
he "1.1.x"
|
||||
param-case "2.1.x"
|
||||
relateurl "0.2.x"
|
||||
uglify-js "3.4.x"
|
||||
|
||||
html-void-elements@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/html-void-elements/-/html-void-elements-1.0.2.tgz#9d22e0ca32acc95b3f45b8d5b4f6fbdc05affd55"
|
||||
|
@ -6608,12 +6577,6 @@ kind-of@^6.0.0, kind-of@^6.0.2:
|
|||
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051"
|
||||
integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==
|
||||
|
||||
klaw-sync@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/klaw-sync/-/klaw-sync-5.0.0.tgz#b8db1249f96a82751c311ee8a626a319db119904"
|
||||
dependencies:
|
||||
graceful-fs "^4.1.11"
|
||||
|
||||
klaw@^1.0.0:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439"
|
||||
|
@ -8488,6 +8451,7 @@ path-type@^3.0.0:
|
|||
pathval@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0"
|
||||
integrity sha1-uULm1L3mUwBe9rcTYd74cn0GReA=
|
||||
|
||||
pause-stream@^0.0.11:
|
||||
version "0.0.11"
|
||||
|
@ -11262,6 +11226,7 @@ type-check@~0.3.2:
|
|||
type-detect@^4.0.0:
|
||||
version "4.0.8"
|
||||
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
|
||||
integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
|
||||
|
||||
type-is@~1.6.15:
|
||||
version "1.6.15"
|
||||
|
@ -11319,20 +11284,6 @@ uglify-es@^3.3.4:
|
|||
commander "~2.13.0"
|
||||
source-map "~0.6.1"
|
||||
|
||||
uglify-js@3.3.x:
|
||||
version "3.3.18"
|
||||
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.3.18.tgz#e16df66d71638df3c9bc61cce827e46f24bdac02"
|
||||
dependencies:
|
||||
commander "~2.15.0"
|
||||
source-map "~0.6.1"
|
||||
|
||||
uglify-js@3.4.x:
|
||||
version "3.4.9"
|
||||
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3"
|
||||
dependencies:
|
||||
commander "~2.17.1"
|
||||
source-map "~0.6.1"
|
||||
|
||||
uglify-js@^2.6:
|
||||
version "2.8.29"
|
||||
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd"
|
||||
|
|
|
@ -90,7 +90,7 @@ export function jsonpCallbackContext(): Object {
|
|||
/**
|
||||
* Configures XSRF protection support for outgoing requests.
|
||||
*
|
||||
* 一个NgModule,用于给外发请求添加 XSRF 保护。
|
||||
* 配置 XSRF 保护,以支持外发请求。
|
||||
*
|
||||
* For a server that supports a cookie-based XSRF protection system,
|
||||
* use directly to configure XSRF protection with the correct
|
||||
|
@ -190,7 +190,7 @@ export class HttpClientXsrfModule {
|
|||
* Configures the [dependency injector](guide/glossary#injector) where it is imported
|
||||
* with supporting services for HTTP communications.
|
||||
*
|
||||
* 该模块提供 `HttpClient` 自身,以及用来支持它的那些服务。
|
||||
* 配置[依赖注入器](guide/glossary#injector),其中导入了用于支持 HTTP通讯的服务。
|
||||
*/
|
||||
providers: [
|
||||
HttpClient,
|
||||
|
|
|
@ -21,7 +21,8 @@ import {COMMON_PIPES} from './pipes/index';
|
|||
* Re-exported by `BrowserModule`, which is included automatically in the root
|
||||
* `AppModule` when you create a new app with the CLI `new` command.
|
||||
*
|
||||
* 该模块包含了所有基本的 Angular 指令,如 {@link NgIf}、{@link NgForOf} 等……
|
||||
* 导出所有基本的 Angular 指令和管道,例如 `NgIf`、`NgForOf`、`DecimalPipe` 等。
|
||||
* 它会由 `BrowserModule` 进行二次导出,当你使用 CLI 的 `new` 命令创建新应用时,`BrowserModule` 会自动包含在根模块 `AppModule` 中。
|
||||
*
|
||||
* * The `providers` options configure the NgModule's injector to provide
|
||||
* localization dependencies to members.
|
||||
|
|
|
@ -60,7 +60,7 @@ const _observableStrategy = new ObservableStrategy();
|
|||
*
|
||||
* ### Examples
|
||||
*
|
||||
* ## 例子
|
||||
* ### 例子
|
||||
*
|
||||
* This example binds a `Promise` to the view. Clicking the `Resolve` button resolves the
|
||||
* promise.
|
||||
|
|
|
@ -45,7 +45,7 @@ import {invalidPipeArgumentError} from './invalid_pipe_argument_error';
|
|||
*
|
||||
* produces the following:
|
||||
*
|
||||
* * 生成下列内容:
|
||||
* 生成下列内容:
|
||||
*
|
||||
* ```html
|
||||
* <li>b</li>
|
||||
|
@ -54,7 +54,7 @@ import {invalidPipeArgumentError} from './invalid_pipe_argument_error';
|
|||
*
|
||||
* ### String Examples
|
||||
*
|
||||
* ## 字符串范例
|
||||
* ### 字符串范例
|
||||
*
|
||||
* {@example common/pipes/ts/slice_pipe.ts region='SlicePipe_string'}
|
||||
*
|
||||
|
|
|
@ -63,8 +63,17 @@ export abstract class TemplateRef<C> {
|
|||
|
||||
/**
|
||||
* Creates a view object and attaches it to the view container of the parent view.
|
||||
*
|
||||
* 创建一个视图对象,并把它附着到父视图的视图容器上。
|
||||
*
|
||||
* @param context The context for the new view, inherited from the anchor element.
|
||||
*
|
||||
* 这个新视图的上下文环境,继承自所附着的元素。
|
||||
*
|
||||
* @returns The new view object.
|
||||
*
|
||||
* 这个新的视图对象。
|
||||
*
|
||||
*/
|
||||
abstract createEmbeddedView(context: C): EmbeddedViewRef<C>;
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ import {EmbeddedViewRef, ViewRef} from './view_ref';
|
|||
/**
|
||||
* Represents a container where one or more views can be attached to a component.
|
||||
*
|
||||
* 代表一个容器,可以在里面附加一个或多个视图。
|
||||
* 表示可以将一个或多个视图附着到组件中的容器。
|
||||
*
|
||||
* Can contain *host views* (created by instantiating a
|
||||
* component with the `createComponent()` method), and *embedded views*
|
||||
|
@ -35,9 +35,6 @@ import {EmbeddedViewRef, ViewRef} from './view_ref';
|
|||
* @see `ComponentRef`
|
||||
* @see `EmbeddedViewRef`
|
||||
*
|
||||
* 要想访问元素的 `ViewContainerRef`,你可以放一个 {@link Directive},并把该元素的 `ViewContainerRef` 注入进去,
|
||||
* 也可以通过 {@link ViewChild} 查询来取到它。
|
||||
*
|
||||
*/
|
||||
export abstract class ViewContainerRef {
|
||||
/**
|
||||
|
@ -64,6 +61,8 @@ export abstract class ViewContainerRef {
|
|||
|
||||
/**
|
||||
* The [dependency injector](guide/glossary#injector) for this view container.
|
||||
*
|
||||
* 该视图容器的[依赖注入器](guide/glossary#injector)。
|
||||
*/
|
||||
abstract get injector(): Injector;
|
||||
|
||||
|
@ -79,10 +78,16 @@ export abstract class ViewContainerRef {
|
|||
|
||||
/**
|
||||
* Retrieves a view from this container.
|
||||
*
|
||||
* 从该容器中获取一个视图
|
||||
*
|
||||
* @param index The 0-based index of the view to retrieve.
|
||||
*
|
||||
* 所要获取视图的从 0 开始的索引。
|
||||
*
|
||||
* @returns The `ViewRef` instance, or null if the index is out of range.
|
||||
*
|
||||
* 返回本容器中指定序号的视图的 {@link ViewRef}。
|
||||
* `ViewRef` 实例,如果索引超出范围则为 0。
|
||||
*/
|
||||
abstract get(index: number): ViewRef|null;
|
||||
|
||||
|
|
|
@ -54,9 +54,11 @@ export interface Form {
|
|||
* @description
|
||||
* The control directive from which to get the `FormControl`.
|
||||
*
|
||||
* 根据表单控件指令找到相应的 `FormControl`。
|
||||
*
|
||||
* @param dir: The control directive.
|
||||
*
|
||||
* 查找与指定的 `NgControl` 相关的 `FormControl`。
|
||||
* 表单控件指令。
|
||||
*/
|
||||
getControl(dir: NgControl): FormControl;
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@ function _extractId(valueString: string): string {
|
|||
*
|
||||
* ### Syntax
|
||||
*
|
||||
* #### 语法
|
||||
* ### 语法
|
||||
*
|
||||
* ```
|
||||
* <select [compareWith]="compareFn" [(ngModel)]="selectedCountries">
|
||||
|
@ -119,7 +119,8 @@ function _extractId(valueString: string): string {
|
|||
* https://bugzilla.mozilla.org/show_bug.cgi?id=1024350
|
||||
* https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/4660045/
|
||||
*
|
||||
* * **npm package**: `@angular/forms`
|
||||
* @ngModule FormsModule
|
||||
* @ngModule ReactiveFormsModule
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
@ -200,7 +201,10 @@ export class SelectControlValueAccessor implements ControlValueAccessor {
|
|||
*
|
||||
* See docs for `SelectControlValueAccessor` for usage examples.
|
||||
*
|
||||
* 参见 `SelectControlValueAccessor` 的文档查看使用范例。
|
||||
*
|
||||
* @ngModule FormsModule
|
||||
* @ngModule ReactiveFormsModule
|
||||
*/
|
||||
@Directive({selector: 'option'})
|
||||
export class NgSelectOption implements OnDestroy {
|
||||
|
|
|
@ -27,16 +27,18 @@ export type ValidationErrors = {
|
|||
* @description
|
||||
* An interface implemented by classes that perform synchronous validation.
|
||||
*
|
||||
* @usageNotes
|
||||
*
|
||||
* 一个接口,实现了它的类可以扮演验证器的角色。
|
||||
*
|
||||
* @usageNotes
|
||||
*
|
||||
* ### Provide a custom validator
|
||||
*
|
||||
* ### 提供一个自定义的验证器
|
||||
*
|
||||
* The following example implements the `Validator` interface to create a
|
||||
* validator directive with a custom error key.
|
||||
*
|
||||
* ## 用法
|
||||
* 下面的例子实现了 `Validator` 接口,以便用一个自定义的错误键来创建验证器指令。
|
||||
*
|
||||
* ```typescript
|
||||
* @Directive({
|
||||
|
|
|
@ -51,11 +51,16 @@ export class FormsModule {
|
|||
/**
|
||||
* Exports the required infrastructure and directives for reactive forms,
|
||||
* making them available for import by NgModules that import this module.
|
||||
*
|
||||
* 导出响应式表单所需的基础设施和指令,使其能用于任何导入了本模块的 NgModule 中。
|
||||
*
|
||||
* @see [Forms](guide/reactive-forms)
|
||||
*
|
||||
* [表单](guide/reactive-forms)
|
||||
*
|
||||
* @see [Reactive Forms Guide](/guide/reactive-forms)
|
||||
*
|
||||
* 响应式表单的 NgModule。
|
||||
* [响应式表单](/guide/reactive-forms)
|
||||
*
|
||||
*/
|
||||
@NgModule({
|
||||
|
@ -68,9 +73,17 @@ export class ReactiveFormsModule {
|
|||
* @description
|
||||
* Provides options for configuring the reactive forms module.
|
||||
*
|
||||
* 提供了一些选项,供配置响应式表单模块。
|
||||
*
|
||||
* @param opts An object of configuration options
|
||||
*
|
||||
* 一个配置选项对象
|
||||
*
|
||||
* * `warnOnNgModelWithFormControl` Configures when to emit a warning when an `ngModel`
|
||||
* binding is used with reactive form directives.
|
||||
*
|
||||
* `warnOnNgModelWithFormControl` 配置了当 `ngModel` 绑定与响应式表单指令一起使用时,发出警告的时机。
|
||||
*
|
||||
*/
|
||||
static withConfig(opts: {
|
||||
/** @deprecated as of v6 */ warnOnNgModelWithFormControl: 'never' | 'once' | 'always'
|
||||
|
|
|
@ -100,7 +100,8 @@ export const BROWSER_MODULE_PROVIDERS: StaticProvider[] = [
|
|||
* Re-exports `CommonModule` and `ApplicationModule`, making their
|
||||
* exports and providers available to all apps.
|
||||
*
|
||||
* 供浏览器使用的 NgModule。
|
||||
* 导出所有 Angular 应用都需要的基础设施。默认包含在用 CLI 的 `new` 命令创建的所有 Angular 应用中。
|
||||
* 它二次导出了 `CommonModule` 和 `ApplicationModule`,以便它们的导出物和提供商能用于所有应用中。
|
||||
*
|
||||
*/
|
||||
@NgModule({providers: BROWSER_MODULE_PROVIDERS, exports: [CommonModule, ApplicationModule]})
|
||||
|
@ -116,13 +117,18 @@ export class BrowserModule {
|
|||
* Configures a browser-based app to transition from a server-rendered app, if
|
||||
* one is present on the page.
|
||||
*
|
||||
* @param params An object containing an identifier for the app to transition.
|
||||
* The ID must match between the client and server versions of the app.
|
||||
* @returns The reconfigured `BrowserModule` to import into the app's root `AppModule`.
|
||||
*
|
||||
* 配置基于浏览器的应用,使其可以从当前页面上的服务端渲染(SSR)应用过渡而来。
|
||||
* 指定的参数必须包含一个应用 id,在客户端应用和服务端应用之间它必须一致。
|
||||
*
|
||||
* @param params An object containing an identifier for the app to transition.
|
||||
* The ID must match between the client and server versions of the app.
|
||||
*
|
||||
* 包含要迁移的应用 id 的对象。在应用的客户端版本和服务端版本中这个 ID 必须匹配。
|
||||
*
|
||||
* @returns The reconfigured `BrowserModule` to import into the app's root `AppModule`.
|
||||
*
|
||||
* 重新配置过的 `BrowserModule`,可供导入到应用的根模块 `AppModule` 中。
|
||||
*
|
||||
* @experimental
|
||||
*/
|
||||
static withServerTransition(params: {appId: string}): ModuleWithProviders<BrowserModule> {
|
||||
|
|
|
@ -910,7 +910,9 @@ export class Router {
|
|||
* in the second parameter (the `NavigationExtras`) that would change the
|
||||
* provided URL.
|
||||
*
|
||||
* 与 `navigate` 不同,`navigateByUrl` 只接收完整的 URL,而不会管当前 URL。
|
||||
* 由于 `navigateByUrl()` 要求必须用绝对地址作为第一个参数,所以它不会在当前 URL 上做增量修改,
|
||||
* 并且会忽略第二个参数 `NavigationExtras` 中所有可能会更改 URL 的属性。
|
||||
*
|
||||
*/
|
||||
navigateByUrl(url: string|UrlTree, extras: NavigationExtras = {skipLocationChange: false}):
|
||||
Promise<boolean> {
|
||||
|
@ -964,6 +966,8 @@ export class Router {
|
|||
* The first parameter of `navigate()` is a delta to be applied to the current URL
|
||||
* or the one provided in the `relativeTo` property of the second parameter (the
|
||||
* `NavigationExtras`).
|
||||
*
|
||||
* `navigate()` 的第一个参数是相对于当前 URL 或第二参数 `NavigationExtras` 中 `relativeTo` 属性所指定的 URL 的增量修改。
|
||||
*/
|
||||
navigate(commands: any[], extras: NavigationExtras = {skipLocationChange: false}):
|
||||
Promise<boolean> {
|
||||
|
|
|
@ -430,7 +430,7 @@ export interface ExtraOptions {
|
|||
* When navigating forward, the scroll position will be set to [0, 0], or to the anchor
|
||||
* if one is provided.
|
||||
*
|
||||
* 当启用时,路由器会在向前导航时保存滚动位置,导航回来(popstate)时则恢复所保存的位置。当向前导航时,滚动位置会设置为 [0, 0],如果指定了锚点,则跳转到那个锚点。
|
||||
* 当启用时,路由器会在导航时保存和恢复滚动位置。当向前导航时,滚动位置会设置为 [0, 0],如果指定了锚点,则跳转到那个锚点。
|
||||
*
|
||||
* You can implement custom scroll restoration behavior as follows.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue