fix: 合并第一版的翻译
This commit is contained in:
parent
fc58e0eee0
commit
964266f4b0
@ -1613,7 +1613,7 @@ also encapsulate a style sheet within a specific component.
|
||||
|
||||
### Link tag
|
||||
|
||||
### Link 标签
|
||||
### Link标签
|
||||
|
||||
<code-example hideCopy>
|
||||
|
||||
@ -1639,8 +1639,8 @@ also encapsulate a style sheet within a specific component.
|
||||
With the Angular CLI, you can configure your global styles in the `.angular-cli.json` file.
|
||||
You can rename the extension to `.scss` to use sass.
|
||||
|
||||
在Angular2中,我们可以继续在`index.html`中使用link标签来为应用程序定义样式。
|
||||
但是也能在组件中封装样式。
|
||||
使用 Angular CLI,我们可以在 `.angular-cli.json` 文件中配置全局样式。
|
||||
也可以把扩展名改为 `.scss` 来使用 sass。
|
||||
|
||||
### StyleUrls
|
||||
|
||||
|
@ -12,7 +12,7 @@ This guide explains how to build with the AOT compiler using different compiler
|
||||
|
||||
<a href="https://www.youtube.com/watch?v=kW9cJsvcsGo">Watch compiler author Tobias Bosch explain the Angular Compiler</a> at AngularConnect 2016.
|
||||
|
||||
<a href="https://www.youtube.com/watch?v=kW9cJsvcsGo">观看 Angular 编译器的作者Tobias Bosch 在 AngularConnect 2016 上对编译器的解释。</a>
|
||||
观看编译器作者Tobias Bosch在AngularConnect 2016大会里,对<a href="http://v.youku.com/v_show/id_XMTc1NTE4NTkwOA==.html?from=y1.7-1.4" target="_blank">Angular编译器</a>的演讲。
|
||||
|
||||
</div>
|
||||
|
||||
@ -20,7 +20,7 @@ This guide explains how to build with the AOT compiler using different compiler
|
||||
|
||||
## Angular compilation
|
||||
|
||||
## 概览
|
||||
## Angular 中的编译
|
||||
|
||||
An Angular application consists largely of components and their HTML templates.
|
||||
Before the browser can render the application,
|
||||
|
@ -307,11 +307,11 @@ template for our `HeroListComponent`:
|
||||
Although this template uses typical HTML elements like `<h2>` and `<p>`, it also has some differences. Code like `*ngFor`, `{{hero.name}}`, `(click)`, `[hero]`, and `<app-hero-detail>` uses Angular's [template syntax](guide/template-syntax).
|
||||
|
||||
模板除了可以使用像`<h2>`和`<p>`这样的典型的 HTML 元素,还能使用其它元素。
|
||||
例如,像`*ngFor`、`{{hero.name}}`、`(click)`、`[hero]`和`<hero-detail>`这样的代码使用了 Angular 的[模板语法](guide/template-syntax)。
|
||||
例如,像`*ngFor`、`{{hero.name}}`、`(click)`、`[hero]`和`<app-hero-detail>`这样的代码使用了 Angular 的[模板语法](guide/template-syntax)。
|
||||
|
||||
In the last line of the template, the `<app-hero-detail>` tag is a custom element that represents a new component, `HeroDetailComponent`.
|
||||
|
||||
在模板的最后一行,`<hero-detail>`标签就是一个用来表示新组件`HeroDetailComponent`的自定义元素。
|
||||
在模板的最后一行,`<app-hero-detail>`标签就是一个用来表示新组件`HeroDetailComponent`的自定义元素。
|
||||
|
||||
The `HeroDetailComponent` is a *different* component than the `HeroListComponent` you've been reviewing.
|
||||
The `HeroDetailComponent` (code not shown) presents facts about a particular hero, the
|
||||
@ -326,7 +326,7 @@ The `HeroDetailComponent` is a **child** of the `HeroListComponent`.
|
||||
|
||||
Notice how `<app-hero-detail>` rests comfortably among native HTML elements. Custom components mix seamlessly with native HTML in the same layouts.
|
||||
|
||||
注意到了吗?`<hero-detail>`舒适地躺在原生 HTML 元素之间。
|
||||
注意到了吗?`<app-hero-detail>`舒适地躺在原生 HTML 元素之间。
|
||||
自定义组件和原生 HTML 在同一布局中融合得天衣无缝。
|
||||
|
||||
<hr class="clear"/>
|
||||
@ -384,8 +384,8 @@ where it finds a `<app-hero-list>` tag in *parent* HTML.
|
||||
For example, if an app's HTML contains `<app-hero-list></app-hero-list>`, then
|
||||
Angular inserts an instance of the `HeroListComponent` view between those tags.
|
||||
|
||||
`selector`: CSS 选择器,它告诉 Angular 在*父级* HTML 中查找`<hero-list>`标签,创建并插入该组件。
|
||||
例如,如果应用的 HTML 包含`<hero-list></hero-list>`, Angular 就会把`HeroListComponent`的一个实例插入到这个标签中。
|
||||
`selector`: CSS 选择器,它告诉 Angular 在*父级* HTML 中查找`<app-hero-list>`标签,创建并插入该组件。
|
||||
例如,如果应用的 HTML 包含`<app-hero-list></app-hero-list>`, Angular 就会把`HeroListComponent`的一个实例插入到这个标签中。
|
||||
|
||||
* `templateUrl`: module-relative address of this component's HTML template, shown [above](guide/architecture#templates).
|
||||
|
||||
|
@ -180,6 +180,8 @@ This first implementation sets the background color of the host element to yello
|
||||
|
||||
## Apply the attribute directive
|
||||
|
||||
## 使用属性型指令
|
||||
|
||||
To use the new `HighlightDirective`, add a paragraph (`<p>`) element to the template of the root `AppComponent` and apply the directive as an attribute.
|
||||
|
||||
运行应用,就会看到我们的指令确实高亮了段落中的文本。
|
||||
@ -216,7 +218,7 @@ The directive could be more dynamic.
|
||||
It could detect when the user mouses into or out of the element
|
||||
and respond by setting or clearing the highlight color.
|
||||
|
||||
当前,`myHighlight`只是简单的设置元素的颜色。
|
||||
当前,`appHighlight`只是简单的设置元素的颜色。
|
||||
这个指令应该在用户鼠标悬浮一个元素时,设置它的颜色。
|
||||
|
||||
Begin by adding `HostListener` to the list of imported symbols.
|
||||
@ -352,8 +354,8 @@ and sets the directive's highlight color with a property binding.
|
||||
You're re-using the directive's attribute selector (`[appHighlight]`) to do both jobs.
|
||||
That's a crisp, compact syntax.
|
||||
|
||||
`[myHighlight]`属性同时做了两件事:把这个高亮指令应用到了`<p>`元素上,并且通过属性绑定设置了该指令的高亮颜色。
|
||||
我们复用了该指令的属性选择器`[myHighlight]`来同时完成它们。
|
||||
`[appHighlight]`属性同时做了两件事:把这个高亮指令应用到了`<p>`元素上,并且通过属性绑定设置了该指令的高亮颜色。
|
||||
我们复用了该指令的属性选择器`[appHighlight]`来同时完成它们。
|
||||
这是清爽、简约的语法。
|
||||
|
||||
You'll have to rename the directive's `highlightColor` property to `appHighlight` because that's now the color property binding name.
|
||||
@ -364,7 +366,7 @@ You'll have to rename the directive's `highlightColor` property to `appHighlight
|
||||
|
||||
This is disagreeable. The word, `appHighlight`, is a terrible property name and it doesn't convey the property's intent.
|
||||
|
||||
这可不好。因为`myHighlight`是一个糟糕的属性名,而且不能反映该属性的意图。
|
||||
这可不好。因为`appHighlight`是一个糟糕的属性名,而且不能反映该属性的意图。
|
||||
|
||||
{@a input-alias}
|
||||
|
||||
@ -385,7 +387,7 @@ Restore the original property name and specify the selector as the alias in the
|
||||
_Inside_ the directive the property is known as `highlightColor`.
|
||||
_Outside_ the directive, where you bind to it, it's known as `appHighlight`.
|
||||
|
||||
在指令内部,该属性叫`highlightColor`,在外部,当我们绑定到它时,它叫`myHighlight`。
|
||||
在指令内部,该属性叫`highlightColor`,在外部,当我们绑定到它时,它叫`appHighlight`。
|
||||
|
||||
You get the best of both worlds: the property name you want and the binding syntax you want:
|
||||
|
||||
@ -397,7 +399,7 @@ Now that you're binding via the alias to the `highlightColor`, modify the `onMou
|
||||
If someone neglects to bind to `appHighlightColor`, highlight the host element in red:
|
||||
|
||||
现在,我们绑定到了`highlightColor`属性,并修改`onMouseEnter()`方法来使用它。
|
||||
如果有人忘了绑定到`highlightColor`,那就用红色进行高亮。
|
||||
如果有人忘了绑定到`appHighlightColor`,那就用红色进行高亮。
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.3.ts" linenums="false" title="src/app/highlight.directive.ts (mouse enter)" region="mouse-enter"></code-example>
|
||||
|
||||
@ -469,7 +471,7 @@ then with the `defaultColor`, and falls back to "red" if both properties are und
|
||||
|
||||
How do you bind to a second property when you're already binding to the `appHighlight` attribute name?
|
||||
|
||||
当已经绑定过`myHighlight`属性时,要如何绑定到第二个属性呢?
|
||||
当已经绑定过`appHighlight`属性时,要如何绑定到第二个属性呢?
|
||||
|
||||
As with components, you can add as many directive property bindings as you need by stringing them along in the template.
|
||||
The developer should be able to write the following template HTML to both bind to the `AppComponent.color`
|
||||
@ -623,5 +625,5 @@ Now apply that reasoning to the following example:
|
||||
Therefore, the directive property must carry the `@Input` decorator.
|
||||
|
||||
|
||||
`myHighlight`属性位于左侧,它引用了`MyHighlightDirective`中一个*带别名的*属性,它不是模板所属组件的一部分,因此存在信任问题。
|
||||
`appHighlight`属性位于左侧,它引用了`HighlightDirective`中一个*带别名的*属性,它不是模板所属组件的一部分,因此存在信任问题。
|
||||
所以,该属性必须带`@Input`装饰器。
|
||||
|
@ -59,6 +59,8 @@ The `@NgModule` decorator identifies `AppModule` as an `NgModule` class.
|
||||
* **_bootstrap_**—the _root_ component that Angular creates and inserts
|
||||
into the `index.html` host web page.
|
||||
|
||||
**_bootstrap_** — _根_组件,Angular 创建它并插入`index.html`宿主页面。
|
||||
|
||||
The default CLI application only has one component, `AppComponent`, so it
|
||||
is in both the `declarations` and the `bootstrap` arrays.
|
||||
|
||||
|
@ -790,7 +790,7 @@ computed with the <a href="http://closure-compiler.appspot.com/home">closure com
|
||||
|
||||
## Polyfills for non-CLI users
|
||||
|
||||
## 不使用 CLI 的用户的腻子脚本
|
||||
## 非 CLI 的用户的腻子脚本
|
||||
|
||||
If you are not using the CLI, you should add your polyfill scripts directly to the host web page (`index.html`), perhaps like this.
|
||||
|
||||
|
@ -952,6 +952,8 @@ so the <code>@Directive</code> configuration applies to components as well</p>
|
||||
|
||||
</p>
|
||||
|
||||
<p>由类的方法实现。</p>
|
||||
|
||||
</th>
|
||||
|
||||
</tr>
|
||||
|
@ -337,6 +337,8 @@ inside `<style>` tags.
|
||||
|
||||
### Template link tags
|
||||
|
||||
### 模板中的link标签
|
||||
|
||||
You can also write `<link>` tags into the component's HTML template.
|
||||
|
||||
我们也可以在组件的 HTML 模板中写`<link>`标签。
|
||||
@ -474,7 +476,7 @@ in most cases.
|
||||
|
||||
## Inspecting generated CSS
|
||||
|
||||
## 附录 1:查看仿真 (Emulated) 模式下生成的 CSS
|
||||
## 查看仿真 (Emulated) 模式下生成的 CSS
|
||||
|
||||
When using emulated view encapsulation, Angular preprocesses
|
||||
all component styles so that they approximate the standard shadow CSS scoping rules.
|
||||
|
@ -1242,7 +1242,7 @@ This isn't necessarily good design.
|
||||
This example is examining *whether a component can
|
||||
inject its parent via the parent's base class*.
|
||||
|
||||
*.这并不是好的设计。问题是*一个组件是否能通过它父组件的基类来注入它的父组件呢*?
|
||||
这并不是好的设计。问题是*一个组件是否能通过它父组件的基类来注入它的父组件呢*?
|
||||
|
||||
The sample's `CraigComponent` explores this question. [Looking back](guide/dependency-injection-in-action#alex),
|
||||
you see that the `Alex` component *extends* (*inherits*) from a class named `Base`.
|
||||
|
@ -15,9 +15,13 @@ the [Angular Dependency Injection](guide/dependency-injection) guide to see how
|
||||
|
||||
## Why dependency injection?
|
||||
|
||||
## 为什么需要依赖注入?
|
||||
|
||||
To understand why dependency injection is so important, consider an example without it.
|
||||
Imagine writing the following code:
|
||||
|
||||
要理解为什么依赖注入这么重要,不妨先考虑不使用它的一个例子。想象下列代码:
|
||||
|
||||
<code-example path="dependency-injection/src/app/car/car-no-di.ts" region="car" title="src/app/car/car.ts (without DI)">
|
||||
|
||||
</code-example>
|
||||
@ -30,6 +34,9 @@ This `Car` needs an engine and tires. Instead of asking for them,
|
||||
the `Car` constructor instantiates its own copies from
|
||||
the very specific classes `Engine` and `Tires`.
|
||||
|
||||
`Car`类需要一个引擎 (engine) 和一些轮胎 (tire),它没有去请求现成的实例,
|
||||
而是在构造函数中用具体的`Engine`和`Tires`类实例化出自己的副本。
|
||||
|
||||
What if the `Engine` class evolves and its constructor requires a parameter?
|
||||
That would break the `Car` class and it would stay broken until you rewrote it along the lines of
|
||||
`this.engine = new Engine(theNewParameter)`.
|
||||
@ -39,33 +46,62 @@ But you'll *have* to start caring because
|
||||
when the definition of `Engine` changes, the `Car` class must change.
|
||||
That makes `Car` brittle.
|
||||
|
||||
如果`Engine`类升级了,它的构造函数要求传入一个参数,这该怎么办?
|
||||
这个`Car`类就被破坏了,在把创建引擎的代码重写为`this.engine = new Engine(theNewParameter)`之前,它都是坏的。
|
||||
当第一次写`Car`类时,我们不关心`Engine`构造函数的参数,现在也不想关心。
|
||||
但是,当`Engine`类的定义发生变化时,就不得不在乎了,`Car`类也不得不跟着改变。
|
||||
这就会让`Car`类过于脆弱。
|
||||
|
||||
What if you want to put a different brand of tires on your `Car`? Too bad.
|
||||
You're locked into whatever brand the `Tires` class creates. That makes the
|
||||
`Car` class inflexible.
|
||||
|
||||
如果想在`Car`上使用不同品牌的轮胎会怎样?太糟了。
|
||||
我们被锁定在`Tires`类创建时使用的那个品牌上。这让`Car`类缺乏弹性。
|
||||
|
||||
Right now each new car gets its own `engine`. It can't share an `engine` with other cars.
|
||||
While that makes sense for an automobile engine,
|
||||
surely you can think of other dependencies that should be shared, such as the onboard
|
||||
wireless connection to the manufacturer's service center. This `Car` lacks the flexibility
|
||||
to share services that have been created previously for other consumers.
|
||||
|
||||
现在,每辆车都有它自己的引擎。它不能和其它车辆共享引擎。
|
||||
虽然这对于汽车来说还算可以理解,但是设想一下那些应该被共享的依赖,比如用来联系厂家服务中心的车载无线电。
|
||||
我们的车缺乏必要的弹性,无法共享当初给其它消费者创建的车载无线电。
|
||||
|
||||
When you write tests for `Car` you're at the mercy of its hidden dependencies.
|
||||
Is it even possible to create a new `Engine` in a test environment?
|
||||
What does `Engine` depend upon? What does that dependency depend on?
|
||||
Will a new instance of `Engine` make an asynchronous call to the server?
|
||||
You certainly don't want that going on during tests.
|
||||
|
||||
当给`Car`类写测试的时候,我们就会受制于它背后的那些依赖。
|
||||
能在测试环境中成功创建新的`Engine`吗?
|
||||
`Engine`自己又依赖什么?那些依赖本身又依赖什么?
|
||||
`Engine`的新实例会发起到服务器的异步调用吗?
|
||||
我们当然不想在测试期间这么一层层追下去。
|
||||
|
||||
What if the `Car` should flash a warning signal when tire pressure is low?
|
||||
How do you confirm that it actually does flash a warning
|
||||
if you can't swap in low-pressure tires during the test?
|
||||
|
||||
如果`Car`应该在轮胎气压低的时候闪动警示灯该怎么办?
|
||||
如果没法在测试期间换上一个低气压的轮胎,那该如何确认它能正确的闪警示灯?
|
||||
|
||||
You have no control over the car's hidden dependencies.
|
||||
When you can't control the dependencies, a class becomes difficult to test.
|
||||
|
||||
我们没法控制这辆车背后隐藏的依赖。
|
||||
当不能控制依赖时,类就会变得难以测试。
|
||||
|
||||
How can you make `Car` more robust, flexible, and testable?
|
||||
|
||||
该如何让`Car`更强壮、有弹性以及可测试?
|
||||
|
||||
{@a ctor-injection}
|
||||
|
||||
答案非常简单。把`Car`的构造函数改造成使用 DI 的版本:
|
||||
|
||||
That's super easy. Change the `Car` constructor to a version with DI:
|
||||
|
||||
<code-tabs>
|
||||
@ -83,15 +119,23 @@ now in the constructor.
|
||||
The `Car` class no longer creates an `engine` or `tires`.
|
||||
It just consumes them.
|
||||
|
||||
发生了什么?我们把依赖的定义移到了构造函数中。
|
||||
`Car`类不再创建引擎`engine`或者轮胎`tires`。
|
||||
它仅仅“消费”它们。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
This example leverages TypeScript's constructor syntax for declaring
|
||||
parameters and properties simultaneously.
|
||||
|
||||
这个例子又一次借助 TypeScript 的构造器语法来同时定义参数和属性。
|
||||
|
||||
</div>
|
||||
|
||||
Now you can create a car by passing the engine and tires to the constructor.
|
||||
|
||||
现在,通过往构造函数中传入引擎和轮胎来创建一辆车。
|
||||
|
||||
<code-example path="dependency-injection/src/app/car/car-creations.ts" region="car-ctor-instantiation" linenums="false">
|
||||
|
||||
</code-example>
|
||||
@ -102,13 +146,20 @@ decoupled from the `Car` class.
|
||||
You can pass in any kind of `engine` or `tires` you like, as long as they
|
||||
conform to the general API requirements of an `engine` or `tires`.
|
||||
|
||||
酷!引擎和轮胎这两个依赖的定义与`Car`类本身解耦了。
|
||||
只要喜欢,可以传入任何类型的引擎或轮胎,只要它们能满足引擎或轮胎的通用 API 需求。
|
||||
|
||||
Now, if someone extends the `Engine` class, that is not `Car`'s problem.
|
||||
|
||||
这样一来,如果有人扩展了`Engine`类,那就不再是`Car`类的烦恼了。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
The _consumer_ of `Car` has the problem. The consumer must update the car creation code to
|
||||
something like this:
|
||||
|
||||
`Car`的_消费者_也有这个问题。消费者必须更新创建这辆车的代码,就像这样:
|
||||
|
||||
<code-example path="dependency-injection/src/app/car/car-creations.ts" region="car-ctor-instantiation-with-param" linenums="false">
|
||||
|
||||
</code-example>
|
||||
@ -116,6 +167,8 @@ something like this:
|
||||
The critical point is this: the `Car` class did not have to change.
|
||||
You'll take care of the consumer's problem shortly.
|
||||
|
||||
这里的要点是:`Car`本身不必变化。下面就来解决消费者的问题。
|
||||
|
||||
</div>
|
||||
|
||||
The `Car` class is much easier to test now because you are in complete control
|
||||
@ -123,23 +176,37 @@ of its dependencies.
|
||||
You can pass mocks to the constructor that do exactly what you want them to do
|
||||
during each test:
|
||||
|
||||
`Car`类非常容易测试,因为现在我们对它的依赖有了完全的控制权。
|
||||
在每个测试期间,我们可以往构造函数中传入 mock 对象,做想让它们做的事:
|
||||
|
||||
<code-example path="dependency-injection/src/app/car/car-creations.ts" region="car-ctor-instantiation-with-mocks" linenums="false">
|
||||
|
||||
</code-example>
|
||||
|
||||
**You just learned what dependency injection is**.
|
||||
|
||||
**刚刚学习了什么是依赖注入**
|
||||
|
||||
It's a coding pattern in which a class receives its dependencies from external
|
||||
sources rather than creating them itself.
|
||||
|
||||
它是一种编程模式,可以让类从外部源中获得它的依赖,而不必亲自创建它们。
|
||||
|
||||
Cool! But what about that poor consumer?
|
||||
Anyone who wants a `Car` must now
|
||||
create all three parts: the `Car`, `Engine`, and `Tires`.
|
||||
The `Car` class shed its problems at the consumer's expense.
|
||||
You need something that takes care of assembling these parts.
|
||||
|
||||
酷!但是,可怜的消费者怎么办?
|
||||
那些希望得到一个`Car`的人们现在必须创建所有这三部分了:`Car`、`Engine`和`Tires`。
|
||||
`Car`类把它的快乐建立在了消费者的痛苦之上。
|
||||
需要某种机制为我们把这三个部分装配好。
|
||||
|
||||
You _could_ write a giant class to do that:
|
||||
|
||||
可以写一个巨型类来做这件事:
|
||||
|
||||
<code-example path="dependency-injection/src/app/car/car-factory.ts" title="src/app/car/car-factory.ts">
|
||||
|
||||
</code-example>
|
||||
@ -149,15 +216,27 @@ But maintaining it will be hairy as the application grows.
|
||||
This factory is going to become a huge spiderweb of
|
||||
interdependent factory methods!
|
||||
|
||||
现在只需要三个创建方法,这还不算太坏。
|
||||
但是当应用规模变大之后,维护它将变得惊险重重。
|
||||
这个工厂类将变成由相互依赖的工厂方法构成的巨型蜘蛛网。
|
||||
|
||||
Wouldn't it be nice if you could simply list the things you want to build without
|
||||
having to define which dependency gets injected into what?
|
||||
|
||||
如果能简单的列出想建造的东西,而不用定义该把哪些依赖注入到哪些对象中,那该多好!
|
||||
|
||||
This is where the dependency injection framework comes into play.
|
||||
Imagine the framework had something called an _injector_.
|
||||
You register some classes with this injector, and it figures out how to create them.
|
||||
|
||||
到了依赖注入框架一展身手的时候了!
|
||||
想象框架中有一个叫做_注入器 (injector)_ 的东西。
|
||||
用这个注入器注册一些类,它会弄明白如何创建它们。
|
||||
|
||||
When you need a `Car`, you simply ask the injector to get it for you and you're good to go.
|
||||
|
||||
当需要一个`Car`时,就简单的找注入器取车就可以了。
|
||||
|
||||
<code-example path="dependency-injection/src/app/car/car-injector.ts" region="injector-call" title="src/app/car/car-injector.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
@ -167,7 +246,14 @@ The consumer knows nothing about creating a `Car`.
|
||||
You don't have a gigantic factory class to maintain.
|
||||
Both `Car` and consumer simply ask for what they need and the injector delivers.
|
||||
|
||||
皆大欢喜。`Car`不需要知道如何创建`Engine`和`Tires`。
|
||||
消费者不需要知道如何创建`Car`。
|
||||
开发人员不需要维护巨大的工厂类。
|
||||
`Car`和消费者只要简单地请求想要什么,注入器就会交付它们。
|
||||
|
||||
This is what a **dependency injection framework** is all about.
|
||||
|
||||
这就是“**依赖注入框架**”存在的原因。
|
||||
|
||||
Now that you know what dependency injection is and appreciate its benefits,
|
||||
turn to the [Angular Dependency Injection](guide/dependency-injection) guide to see how it is implemented in Angular.
|
||||
|
@ -820,7 +820,7 @@ There is no `AppConfig` class.
|
||||
The `HERO_DI_CONFIG` constant conforms to the `AppConfig` interface.
|
||||
Unfortunately, you cannot use a TypeScript interface as a token:
|
||||
|
||||
`CONFIG`常量有一个接口:`AppConfig`。不幸的是,不能把 TypeScript 接口用作令牌:
|
||||
`HERO_DI_CONFIG`常量有一个接口:`AppConfig`。不幸的是,不能把 TypeScript 接口用作令牌:
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-9-interface" linenums="false">
|
||||
|
||||
|
@ -70,6 +70,8 @@ It might be good enough for sharing your progress and ideas internally with mana
|
||||
|
||||
## 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`.
|
||||
@ -204,13 +206,23 @@ 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" target="_blank" title="Chrome DevTools Network Performance">
|
||||
Chrome开发工具的网络性能页</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
|
||||
@ -270,19 +282,30 @@ For example, given the `<base href="/my/app/">`, the browser resolves a URL such
|
||||
into a server request for `my/app/some/place/foo.jpg`.
|
||||
During navigation, the Angular router uses the _base href_ as the base path to component, template, and module files.
|
||||
|
||||
HTML中的[_<base href="..."/>_](https://angular.io/docs/ts/latest/guide/router.html#!)用于指定一个解析相对路径的基地址,如图片、脚本和样式表。
|
||||
比如,指定`<base href="/my/app/">`时,浏览器就会把`some/place/foo.jpg`这样的URL解析成到`my/app/some/place/foo.jpg`的服务端请求。
|
||||
在浏览期间,Angular路由器会使用*base href*作为组件、模板和模块文件的基地址。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
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`.
|
||||
|
||||
但是在共享服务器或生产服务器上,我们可能得从子目录下启动服务器。
|
||||
比如,当加载本应用的URL是`http://www.mysite.com/my/app/`时,子目录就是`my/app/`,而我们就要在服务器版的`index.html`中添加`<base href="/my/app/">`。
|
||||
|
||||
When the `base` tag is mis-configured, the app fails to load and the browser console displays `404 - Not Found` errors
|
||||
for the missing files. Look at where it _tried_ to find those files and adjust the base tag appropriately.
|
||||
|
||||
|
@ -46,7 +46,7 @@ With interpolation, you put the property name in the view template, enclosed in
|
||||
Follow the [quickstart](guide/quickstart) instructions for creating a new project
|
||||
named <code>displaying-data</code>.
|
||||
|
||||
按照[开发环境](guide/setup)的说明,创建一个新项目,名为<code>displaying-data</code>。
|
||||
按照[快速起步](guide/quickstart)的说明,创建一个新项目,名为<code>displaying-data</code>。
|
||||
|
||||
Delete the <code>app.component.html</code> file. It is not needed for this example.
|
||||
|
||||
|
@ -160,8 +160,8 @@ The `<app-question>` tag matches the `DynamicFormQuestionComponent`,
|
||||
the component responsible for rendering the details of each _individual_
|
||||
question based on values in the data-bound question object.
|
||||
|
||||
它代表了问卷问题列表,每个问题都被绑定到一个`<df-question>`组件元素。
|
||||
`<df-question>`标签匹配到的是组件`DynamicFormQuestionComponent`,该组件的职责是根据各个问卷问题对象的值来动态渲染表单控件。
|
||||
它代表了问卷问题列表,每个问题都被绑定到一个`<app-question>`组件元素。
|
||||
`<app-question>`标签匹配到的是组件`DynamicFormQuestionComponent`,该组件的职责是根据各个问卷问题对象的值来动态渲染表单控件。
|
||||
|
||||
<code-tabs>
|
||||
|
||||
|
@ -325,7 +325,7 @@ Update it with the following:
|
||||
|
||||
There are two changes:
|
||||
|
||||
有三处更改
|
||||
有两处更改
|
||||
|
||||
1. You import `FormsModule`.
|
||||
|
||||
@ -358,7 +358,7 @@ Update it with the following:
|
||||
|
||||
Replace the contents of its template with the following:
|
||||
|
||||
把“快速上手”的版本内容替换成下列代码:
|
||||
把模板中的内容替换成如下代码:
|
||||
|
||||
<code-example path="forms/src/app/app.component.html" title="src/app/app.component.html">
|
||||
|
||||
|
@ -129,6 +129,8 @@ of some of the things they contain:
|
||||
|
||||
<code>RouterModule</code>
|
||||
|
||||
<code>RouterModule</code>(路由器模块)
|
||||
|
||||
</td>
|
||||
|
||||
<td>
|
||||
|
@ -163,12 +163,12 @@ between a "token"—also referred to as a "key"—and a dependency [prov
|
||||
|
||||
You launch an Angular application by "bootstrapping" it using the application root NgModule (`AppModule`).
|
||||
|
||||
通过应用程序根 Angular 模块(`AppModule`)来启动 Angular 应用程序。
|
||||
|
||||
Bootstrapping identifies an application's top level "root" [component](guide/glossary#component),
|
||||
which is the first component that is loaded for the application.
|
||||
|
||||
通过应用程序根 Angular 模块来启动 Angular 应用程序。
|
||||
启动过程标识应用的顶级“根”[组件 (component)](guide/glossary#component),也就是应用加载的第一个组件。
|
||||
更多信息,见[设置](guide/setup)。
|
||||
启动过程标识应用的顶级“根”[组件 (component)](guide/glossary#component),也就是应用加载的第一个组件。
|
||||
|
||||
You can bootstrap multiple apps in the same `index.html`, each app with its own top-level root.
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
# Internationalization (i18n)
|
||||
|
||||
# 国际化(i18n)
|
||||
|
||||
Application internationalization is a many-faceted area of development, focused on making
|
||||
applications available and user-friendly to a worldwide audience. This page describes Angular's
|
||||
internationalization (i18n) tools, which can help you make your app available in multiple languages.
|
||||
@ -7,7 +9,7 @@ internationalization (i18n) tools, which can help you make your app available in
|
||||
See the <live-example downloadOnly name="i18n">i18n Example</live-example> for a simple example of
|
||||
an AOT-compiled app, translated into French.
|
||||
|
||||
可以把这个翻译为法语版的 AOT 应用<live-example name="i18n">i18n 例子</live-example>作为一个简单的例子。
|
||||
可以把这个翻译为法语版的 AOT 应用<live-example downloadOnly name="i18n">i18n 例子</live-example>作为一个简单的例子。
|
||||
|
||||
{@a angular-i18n}
|
||||
|
||||
@ -143,6 +145,8 @@ The i18n template translation process has four phases:
|
||||
|
||||
1. Mark static text messages in your component templates for translation.
|
||||
|
||||
在组件模板中标记需要翻译的静态文本信息。
|
||||
|
||||
2. An Angular i18n tool extracts the marked text into an industry standard translation source file.
|
||||
|
||||
3. A translator edits that file, translating the extracted text into the target language,
|
||||
@ -454,6 +458,8 @@ Pluralization categories include (depending on the language):
|
||||
|
||||
* other
|
||||
|
||||
other(其它)
|
||||
|
||||
After the pluralization category, put the default English text in braces (`{}`).
|
||||
|
||||
把默认的*英语*翻译结果放在复数类别之后的括号(`{}`)中。
|
||||
@ -512,7 +518,7 @@ You can also nest different ICU expressions together, as shown in this example:
|
||||
|
||||
## Create a translation source file with _ng xi18n_
|
||||
|
||||
## 使用_ng-xi18n_工具创建翻译源文件
|
||||
## 使用*ng-xi18n*工具创建翻译源文件
|
||||
|
||||
Use the `ng xi18n` command provided by the CLI to extract the text messages marked with `i18n` into
|
||||
a translation source file.
|
||||
@ -749,6 +755,8 @@ must be just below the translation unit for the logo.
|
||||
|
||||
### Translate _plural_
|
||||
|
||||
### 翻译*复数*
|
||||
|
||||
To translate a `plural`, translate its ICU format match values:
|
||||
|
||||
要翻译一个复数,就要翻译它的ICU格式中匹配的值:
|
||||
@ -911,6 +919,8 @@ options with the `ng serve` or `ng build` commands:
|
||||
|
||||
* `--i18nFile`: the path to the translation file.
|
||||
|
||||
`--i18nFile`: 翻译文件的路径
|
||||
|
||||
* `--i18nFormat`: the format of the translation file.
|
||||
|
||||
* `--locale`: the locale id.
|
||||
@ -984,6 +994,8 @@ Then provide the `LOCALE_ID` in the main module:
|
||||
|
||||
### Report missing translations
|
||||
|
||||
### 汇报缺失的翻译
|
||||
|
||||
By default, when a translation is missing, the build succeeds but generates a warning such as
|
||||
`Missing translation for message "foo"`. You can configure the level of warning that is generated by
|
||||
the Angular compiler:
|
||||
|
@ -114,6 +114,9 @@ The following table summarizes the `@NgModule` metadata properties.
|
||||
Components, directives, and pipes must belong to _exactly_ one module.
|
||||
The compiler emits an error if you try to declare the same class in more than one module.
|
||||
|
||||
组件、指令和管道*只能*属于一个模块。
|
||||
如果尝试把同一个类声明在多个模块中,编译器就会报告一个错误。
|
||||
|
||||
Don't re-declare a class imported from another module.
|
||||
|
||||
</td>
|
||||
@ -198,6 +201,8 @@ The following table summarizes the `@NgModule` metadata properties.
|
||||
A list of declarations—*component*, *directive*, and *pipe* classes—that
|
||||
an importing module can use.
|
||||
|
||||
可供导入了自己的模块使用的可声明对象(**组件**、**指令**、**管道类**)的列表。
|
||||
|
||||
Exported declarations are the module's _public API_.
|
||||
A component in another module can [use](guide/ngmodule-faq#q-template-reference) _this_
|
||||
module's `UserComponent` if it imports this module and this module exports `UserComponent`.
|
||||
@ -213,6 +218,8 @@ The following table summarizes the `@NgModule` metadata properties.
|
||||
A module can list another module among its `exports`, in which case
|
||||
all of that module's public components, directives, and pipes are exported.
|
||||
|
||||
一个模块可以把另一个模块加入自己的`exports`列表中,这时,另一个模块的所有公开组件、指令和管道都会被导出。
|
||||
|
||||
[Re-export](guide/ngmodule-faq#q-reexport) makes module transitivity explicit.
|
||||
If Module 'A' re-exports `CommonModule` and Module 'B' imports Module 'A',
|
||||
Module 'B' components can use `ngIf` even though 'B' itself didn't import `CommonModule`.
|
||||
|
@ -149,7 +149,7 @@ The "x" class isn't visible to other modules until you add it to the `exports` l
|
||||
Import NgModules whose public (exported) [declarable classes](guide/bootstrapping#the-declarations-array)
|
||||
you need to reference in this module's component templates.
|
||||
|
||||
一句话:导入你需要在当前模块的组件模板中使用的那些公开的(被导出的)[可声明类](guide/ngmodule-faq#q-declarable)。
|
||||
导入你需要在当前模块的组件模板中使用的那些公开的(被导出的)[可声明类](guide/ngmodule-faq#q-declarable)。
|
||||
|
||||
This always means importing `CommonModule` from `@angular/common` for access to
|
||||
the Angular directives such as `NgIf` and `NgFor`.
|
||||
@ -339,18 +339,18 @@ Its only purpose is to add http service providers to the application as a whole.
|
||||
|
||||
## What is the `forRoot()` method?
|
||||
|
||||
## *forRoot*方法是什么?
|
||||
## *forRoot()*方法是什么?
|
||||
|
||||
The `forRoot()` static method is a convention that makes it easy for developers to configure the module's providers.
|
||||
|
||||
静态方法`forRoot`是一个约定,它可以让开发人员更轻松的配置模块的提供商。
|
||||
静态方法`forRoot()`是一个约定,它可以让开发人员更轻松的配置模块的提供商。
|
||||
|
||||
The `RouterModule.forRoot()` method is a good example.
|
||||
Apps pass a `Routes` object to `RouterModule.forRoot()` in order to configure the app-wide `Router` service with routes.
|
||||
`RouterModule.forRoot()` returns a [ModuleWithProviders](api/core/ModuleWithProviders).
|
||||
You add that result to the `imports` list of the root `AppModule`.
|
||||
|
||||
`RouterModule.forRoot`就是一个很好的例子。
|
||||
`RouterModule.forRoot()`就是一个很好的例子。
|
||||
应用把一个`Routes`对象传给`RouterModule.forRoot`,为的就是使用路由配置全应用级的`Router`服务。
|
||||
`RouterModule.forRoot`返回一个[ModuleWithProviders](api/core/ModuleWithProviders)对象。
|
||||
我们把这个结果添加到根模块`AppModule`的`imports`列表中。
|
||||
|
@ -73,6 +73,8 @@ you list the module's classes in the `@NgModule.declarations` list.
|
||||
* An NgModule can only export the [declarable classes](guide/ngmodule-faq#q-declarable)
|
||||
it owns or imports from other modules. It doesn't declare or export any other kind of class.
|
||||
|
||||
Angular模块只能导出[_可声明的类_](guide/ngmodule-faq#q-declarable)。这可能是它自己拥有的也可能是从其它模块中导入的。它不会声明或导出任何其它类型的类。
|
||||
|
||||
* Unlike JavaScript modules, an NgModule can extend the _entire_ application with services
|
||||
by adding providers to the `@NgModule.providers` list.
|
||||
|
||||
|
@ -32,6 +32,8 @@ section.
|
||||
|
||||
Modules are a great way to organize an application and extend it with capabilities from external libraries.
|
||||
|
||||
模块是组织应用和使用外部库扩展应用的最佳途径。
|
||||
|
||||
Angular libraries are NgModules, such as `FormsModule`, `HttpClientModule`, and `RouterModule`.
|
||||
Many third-party libraries are available as NgModules such as
|
||||
<a href="https://material.angular.io/">Material Design</a>,
|
||||
|
@ -319,7 +319,7 @@ read the [Form Validation](guide/form-validation) guide.
|
||||
|
||||
Now update the component's template, with the following markup.
|
||||
|
||||
现在,在创建组件的模板文件`src/app/hero-detail.component.html`,内容如下:
|
||||
现在,修改组件的模板文件`src/app/hero-detail.component.html`,内容如下:
|
||||
|
||||
<code-example path="reactive-forms/src/app/hero-detail/hero-detail-1.component.html" region="simple-control" title="src/app/hero-detail/hero-detail.component.html" linenums="false">
|
||||
|
||||
|
@ -3496,7 +3496,7 @@ The `Crisis Detail` route is a child of the `Crisis List`. Since the router [reu
|
||||
by default, the `Crisis Detail` component will be re-used as you select different crises.
|
||||
In contrast, back in the `Hero Detail` route, the component was recreated each time you selected a different hero.
|
||||
|
||||
`Crisis Detail`路由是`Crisis List`的子路由。由于路由器默认会[复用组件](guide/router#reuse),因此当我们选择了另一个危机时,`CrisisDetailComponent`会被复用。
|
||||
`Crisis Detail`路由是`Crisis List`的子路由。由于路由器默认会[复用组件](#reuse),因此当我们选择了另一个危机时,`CrisisDetailComponent`会被复用。
|
||||
作为对比,回到`Hero Detail`路由时,每当我们选择了不同的英雄时,该组件都会被重新创建。
|
||||
|
||||
At the top level, paths that begin with `/` refer to the root of the application.
|
||||
|
@ -101,4 +101,6 @@ This can be useful when scanning through code and looking for observable values.
|
||||
|
||||
For example:
|
||||
|
||||
比如:
|
||||
|
||||
<code-example path="rx-library/src/naming-convention.ts" title="Naming observables"></code-example>
|
||||
|
@ -53,6 +53,8 @@ Note the following:
|
||||
|
||||
* It re-exports the `CommonModule` and `FormsModule`.
|
||||
|
||||
它重新导出了`CommonModule`和`FormsModule`
|
||||
|
||||
By re-exporting `CommonModule` and `FormsModule`, any other module that imports this
|
||||
`SharedModule`, gets access to directives like `NgIf` and `NgFor` from `CommonModule`
|
||||
and can bind to component properties with `[(ngModel)]`, a directive in the `FormsModule`.
|
||||
|
@ -173,6 +173,11 @@ a _child_ of the root injector.
|
||||
Of course it finds the instance imported by the root `AppModule`.
|
||||
Now `parentModule` exists and the constructor throws the error.
|
||||
|
||||
Angular 创建一个惰性加载模块,它具有自己的注入器,它是根注入器的*子注入器*。
|
||||
`@SkipSelf`让 Angular 在其父注入器中查找`CoreModule`,这次,它的父注入器却是根注入器了(而上次父注入器是空)。
|
||||
当然,这次它找到了由根模块`AppModule`导入的实例。
|
||||
该构造函数检测到存在`parentModule`,于是抛出一个错误。
|
||||
|
||||
Here are the two files in their entirety for reference:
|
||||
|
||||
<code-tabs linenums="false">
|
||||
|
@ -836,13 +836,13 @@ You inject both in the directive constructor as private variables of the class.
|
||||
|
||||
### The _appUnless_ property
|
||||
|
||||
### *myUnless* 属性
|
||||
### *appUnless* 属性
|
||||
|
||||
The directive consumer expects to bind a true/false condition to `[appUnless]`.
|
||||
That means the directive needs an `appUnless` property, decorated with `@Input`
|
||||
|
||||
该指令的使用者会把一个true/false条件绑定到`[myUnless]`属性上。
|
||||
也就是说,该指令需要一个带有`@Input`的`myUnless`属性。
|
||||
该指令的使用者会把一个true/false条件绑定到`[appUnless]`属性上。
|
||||
也就是说,该指令需要一个带有`@Input`的`appUnless`属性。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
@ -859,7 +859,7 @@ Read about `@Input` in the [_Template Syntax_](guide/template-syntax#inputs-outp
|
||||
Angular sets the `appUnless` property whenever the value of the condition changes.
|
||||
Because the `appUnless` property does work, it needs a setter.
|
||||
|
||||
一旦该值的条件发生了变化,Angular 就会去设置 `myUnless` 属性,这时候,我们就需要为它定义一个设置器(setter)。
|
||||
一旦该值的条件发生了变化,Angular 就会去设置 `appUnless` 属性,这时候,我们就需要为它定义一个设置器(setter)。
|
||||
|
||||
* If the condition is falsy and the view hasn't been created previously,
|
||||
tell the _view container_ to create the _embedded view_ from the template.
|
||||
@ -873,7 +873,7 @@ clear the container which also destroys the view.
|
||||
|
||||
Nobody reads the `appUnless` property so it doesn't need a getter.
|
||||
|
||||
没有人会读取`myUnless`属性,因此它不需要定义设置器(getter)。
|
||||
没有人会读取`appUnless`属性,因此它不需要定义设置器(getter)。
|
||||
|
||||
The completed directive code looks like this:
|
||||
|
||||
|
@ -248,6 +248,8 @@ region="ng-imports">
|
||||
|
||||
When the browser refreshes, the app should work again. You can edit the hero's name and see the changes reflected immediately in the `<h2>` above the textbox.
|
||||
|
||||
浏览器刷新。又见到我们的英雄了。我们可以编辑英雄的名字,也能看到这个改动立刻体现在`<h2>`中。
|
||||
|
||||
### Declare _HeroesComponent_
|
||||
|
||||
Every component must be declared in _exactly one_ [NgModule](guide/ngmodules).
|
||||
|
@ -3,6 +3,9 @@
|
||||
In this page, you'll expand the Tour of Heroes app to display a list of heroes, and
|
||||
allow users to select a hero and display the hero's details.
|
||||
|
||||
我们需要管理多个英雄。我们将扩展《英雄指南》应用,让它显示一个英雄列表,
|
||||
允许用户选择一个英雄,查看该英雄的详细信息。
|
||||
|
||||
## Create mock heroes
|
||||
|
||||
You'll need some heroes to display.
|
||||
@ -21,6 +24,8 @@ title="src/app/mock-heroes.ts">
|
||||
|
||||
## Displaying heroes
|
||||
|
||||
## 显示我们的英雄
|
||||
|
||||
You're about to display the list of heroes at the top of the `HeroesComponent`.
|
||||
|
||||
Open the `HeroesComponent` class file and import the mock `HEROES`.
|
||||
@ -82,6 +87,8 @@ After the browser refreshes, the list of heroes appears.
|
||||
|
||||
### Style the heroes
|
||||
|
||||
### 给我们的英雄们“美容”
|
||||
|
||||
The heroes list should be attractive and should respond visually when users
|
||||
hover over and select a hero from the list.
|
||||
|
||||
@ -129,6 +136,8 @@ and update the hero detail.
|
||||
|
||||
Add a click event binding to the `<li>` like this:
|
||||
|
||||
我们再往`<li>`元素上插入一句点击事件的绑定代码:
|
||||
|
||||
<code-example path="toh-pt2/src/app/heroes/heroes.component.1.html" region="selectedHero-click" title="heroes.component.html (template excerpt)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
@ -215,6 +224,8 @@ When the user picks a hero, `selectedHero` has a value and
|
||||
|
||||
### Style the selected hero
|
||||
|
||||
### 给所选英雄添加样式
|
||||
|
||||
It's difficult to identify the _selected hero_ in the list when all `<li>` elements look alike.
|
||||
|
||||
If the user clicks "Magneta", that hero should render with a distinctive but subtle background color like this:
|
||||
@ -251,6 +262,8 @@ The finished `<li>` looks like this:
|
||||
|
||||
Your app should look like this <live-example></live-example>.
|
||||
|
||||
我们的应用现在变成了这样:<live-example></live-example>。
|
||||
|
||||
Here are the code files discussed on this page, including the `HeroesComponent` styles.
|
||||
|
||||
<code-tabs>
|
||||
|
@ -119,6 +119,8 @@ The browser refreshes and the app starts working again as it did before.
|
||||
|
||||
## What changed?
|
||||
|
||||
## 有哪些变化?
|
||||
|
||||
As [before](tutorial/toh-pt2), whenever a user clicks on a hero name,
|
||||
the hero detail appears below the hero list.
|
||||
Now the `HeroDetailComponent` is presenting those details instead of the `HeroesComponent`.
|
||||
|
@ -2,16 +2,28 @@
|
||||
|
||||
There are new requirements for the Tour of Heroes app:
|
||||
|
||||
我们收到了《英雄指南》的一些新需求:
|
||||
|
||||
* Add a *Dashboard* view.
|
||||
|
||||
添加一个*仪表盘*视图。
|
||||
|
||||
* Add the ability to navigate between the *Heroes* and *Dashboard* views.
|
||||
|
||||
在*英雄列表*和*仪表盘*视图之间导航。
|
||||
|
||||
* When users click a hero name in either view, navigate to a detail view of the selected hero.
|
||||
|
||||
无论在哪个视图中点击一个英雄,都会导航到该英雄的详情页。
|
||||
|
||||
* When users click a *deep link* in an email, open the detail view for a particular hero.
|
||||
|
||||
在邮件中点击一个*深链接*,会直接打开一个特定英雄的详情视图。
|
||||
|
||||
When you’re done, users will be able to navigate the app like this:
|
||||
|
||||
完成时,用户就能像这样在应用中导航:
|
||||
|
||||
<figure>
|
||||
|
||||
<img src='generated/images/guide/toh/nav-diagram.png' alt="View navigations">
|
||||
@ -300,6 +312,8 @@ After the browser refreshes you can navigate freely between the two views by cli
|
||||
|
||||
## Navigating to hero details
|
||||
|
||||
## 导航到英雄详情
|
||||
|
||||
The `HeroDetailsComponent` displays details of a selected hero.
|
||||
At the moment the `HeroDetailsComponent` is only visible at the bottom of the `HeroesComponent`
|
||||
|
||||
@ -440,6 +454,8 @@ The `HeroDetailComponent` needs a new way to obtain the _hero-to-display_.
|
||||
|
||||
Add the following imports:
|
||||
|
||||
先添加下列导入语句:
|
||||
|
||||
<code-example
|
||||
path="toh-pt5/src/app/hero-detail/hero-detail.component.ts"
|
||||
region="added-imports"
|
||||
@ -452,6 +468,8 @@ Add the following imports:
|
||||
Inject the `ActivatedRoute`, `HeroService`, and `Location` services
|
||||
into the constructor, saving their values in private fields:
|
||||
|
||||
然后注入`ActivatedRoute`和`HeroService`服务到构造函数中,将它们的值保存到私有变量中:
|
||||
|
||||
<code-example
|
||||
path="toh-pt5/src/app/hero-detail/hero-detail.component.ts" region="ctor">
|
||||
|
||||
@ -492,6 +510,8 @@ Add it now.
|
||||
|
||||
### Add *HeroService.getHero()*
|
||||
|
||||
### 添加 *HeroService.getHero()*
|
||||
|
||||
Open `HeroService` and add this `getHero()` method
|
||||
|
||||
<code-example
|
||||
@ -528,6 +548,8 @@ the router navigates to the detail view for the hero with `id: 11`, "Mr. Nice".
|
||||
|
||||
### Find the way back
|
||||
|
||||
### 回到原路
|
||||
|
||||
By clicking the browser's back button,
|
||||
you can go back to the hero list or dashboard view,
|
||||
depending upon which sent you to the detail view.
|
||||
@ -556,8 +578,14 @@ Refresh the browser and start clicking.
|
||||
Users can navigate around the app, from the dashboard to hero details and back,
|
||||
from heroes list to the mini detail to the hero details and back to the heroes again.
|
||||
|
||||
刷新浏览器,并开始点击。
|
||||
我们能在应用中导航:从仪表盘到英雄详情再回来,从英雄列表到 mini 版英雄详情到英雄详情,再回到英雄列表。
|
||||
我们可以在仪表盘和英雄列表之间跳来跳去。
|
||||
|
||||
You've met all of the navigational requirements that propelled this page.
|
||||
|
||||
我们已经满足了在本章开头设定的所有导航需求。
|
||||
|
||||
## Final code review
|
||||
|
||||
Here are the code files discussed on this page and your app should look like this <live-example></live-example>.
|
||||
@ -667,6 +695,8 @@ Here are the code files discussed on this page and your app should look like thi
|
||||
|
||||
* You added the Angular router to navigate among different components.
|
||||
|
||||
添加了 Angular *路由器*在各个不同组件之间导航。
|
||||
|
||||
* You turned the `AppComponent` into a navigation shell with `<a>` links and a `<router-outlet>`.
|
||||
|
||||
* You configured the router in an `AppRoutingModule`
|
||||
@ -680,3 +710,6 @@ Here are the code files discussed on this page and your app should look like thi
|
||||
* You used router link parameters to navigate to the detail view of a user-selected hero.
|
||||
|
||||
* You shared the `HeroService` among multiple components.
|
||||
|
||||
|
||||
在多个组件之间共享了`HeroService`服务。
|
||||
|
@ -1,5 +1,7 @@
|
||||
# HTTP
|
||||
|
||||
# HTTP 服务
|
||||
|
||||
In this tutorial, you'll add the following data persistence features with help from
|
||||
Angular's `HttpClient`.
|
||||
|
||||
@ -11,6 +13,8 @@ Angular's `HttpClient`.
|
||||
|
||||
When you're done with this page, the app should look like this <live-example></live-example>.
|
||||
|
||||
当我们完成这一章时,应用会变成这样:<live-example></live-example>。
|
||||
|
||||
## Enable HTTP services
|
||||
|
||||
`HttpClient` is Angular's mechanism for communicating with a remote server over HTTP.
|
||||
@ -93,6 +97,8 @@ Now back to the `HttpClient` story.
|
||||
|
||||
## Heroes and HTTP
|
||||
|
||||
## 英雄与 HTTP
|
||||
|
||||
Import some HTTP symbols that you'll need:
|
||||
|
||||
<code-example
|
||||
@ -150,6 +156,8 @@ Convert that method to use `HttpClient`
|
||||
Refresh the browser. The hero data should successfully load from the
|
||||
mock server.
|
||||
|
||||
刷新浏览器后,英雄数据就会从模拟服务器被成功读取。
|
||||
|
||||
You've swapped `of` for `http.get` and the app keeps working without any other changes
|
||||
because both functions return an `Observable<Hero[]>`.
|
||||
|
||||
@ -256,6 +264,8 @@ Here is the final version of `getHeroes` with the `tap` that logs the operation.
|
||||
|
||||
### Get hero by id
|
||||
|
||||
### 通过id获取英雄
|
||||
|
||||
Most web APIs support a _get by id_ request in the form `api/hero/:id`
|
||||
(such as `api/hero/11`).
|
||||
Add a `HeroService.getHero()` method to make that request:
|
||||
@ -283,6 +293,8 @@ the server.
|
||||
At the end of the hero detail template, add a save button with a `click` event
|
||||
binding that invokes a new component method named `save()`.
|
||||
|
||||
我们先来确保对英雄名字的编辑不会丢失。先在英雄详情模板的底部添加一个保存按钮,它绑定了一个`click`事件,事件绑定会调用组件中一个名叫`save()`的新方法:
|
||||
|
||||
<code-example path="toh-pt6/src/app/hero-detail/hero-detail.component.html" region="save" title="src/app/hero-detail/hero-detail.component.html (save)"></code-example>
|
||||
|
||||
Add the following `save()` method, which persists hero name changes using the hero service
|
||||
@ -339,6 +351,8 @@ the heading:
|
||||
In response to a click event, call the component's click handler and then
|
||||
clear the input field so that it's ready for another name.
|
||||
|
||||
当点击事件触发时,我们调用组件的点击处理器,然后清空这个输入框,以便用来输入另一个名字。
|
||||
|
||||
<code-example path="toh-pt6/src/app/heroes/heroes.component.ts" region="add" title="src/app/heroes/heroes.component.ts (add)"></code-example>
|
||||
|
||||
When the given name is non-blank, the handler creates a `Hero`-like object
|
||||
@ -422,6 +436,8 @@ Note that
|
||||
|
||||
Refresh the browser and try the new delete functionality.
|
||||
|
||||
刷新浏览器,并试一下这个新的删除功能。
|
||||
|
||||
## Search by name
|
||||
|
||||
In this last exercise, you learn to chain `Observable` operators together
|
||||
@ -488,6 +504,8 @@ as listed in the [final code review](#herosearchcomponent) below.
|
||||
As the user types in the search box, a *keyup* event binding calls the component's `search()`
|
||||
method with the new search box value.
|
||||
|
||||
当用户在搜索框中输入时,一个 *keyup* 事件绑定会调用该组件的`search()`方法,并传入新的搜索框的值。
|
||||
|
||||
{@a asyncpipe}
|
||||
|
||||
### _AsyncPipe_
|
||||
@ -564,11 +582,20 @@ Here's the code.
|
||||
* `debounceTime(300)` waits until the flow of new string events pauses for 300 milliseconds
|
||||
before passing along the latest string. You'll never make requests more frequently than 300ms.
|
||||
|
||||
在传出最终字符串之前,`debounceTime(300)`将会等待,直到新增字符串的事件暂停了 300 毫秒。
|
||||
我们实际发起请求的间隔永远不会小于 300ms。
|
||||
|
||||
* `distinctUntilChanged` ensures that a request is sent only if the filter text changed.
|
||||
|
||||
`distinctUntilChanged`确保只在过滤条件变化时才发送请求,
|
||||
这样就不会重复请求同一个搜索词了。
|
||||
|
||||
* `switchMap()` calls the search service for each search term that makes it through `debounce` and `distinctUntilChanged`.
|
||||
It cancels and discards previous search observables, returning only the latest search service observable.
|
||||
|
||||
`switchMap()`会为每个从`debounce`和`distinctUntilChanged`中通过的搜索词调用搜索服务。
|
||||
它会取消并丢弃以前的搜索可观察对象,只保留最近的。
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
With the [switchMap operator](http://www.learnrxjs.io/operators/transformation/switchmap.html),
|
||||
@ -601,6 +628,8 @@ If you enter characters that match any existing hero names, you'll see something
|
||||
|
||||
Your app should look like this <live-example></live-example>.
|
||||
|
||||
我们的应用现在变成了这样:<live-example></live-example>。
|
||||
|
||||
Here are the code files discussed on this page (all in the `src/app/` folder).
|
||||
|
||||
{@a heroservice}
|
||||
@ -693,18 +722,32 @@ Here are the code files discussed on this page (all in the `src/app/` folder).
|
||||
|
||||
You're at the end of your journey, and you've accomplished a lot.
|
||||
|
||||
旅程即将结束,不过我们已经收获颇丰。
|
||||
|
||||
* You added the necessary dependencies to use HTTP in the app.
|
||||
|
||||
我们添加了在应用程序中使用 HTTP 的必备依赖。
|
||||
|
||||
* You refactored `HeroService` to load heroes from a web API.
|
||||
|
||||
我们重构了`HeroService`,以通过 web API 来加载英雄数据。
|
||||
|
||||
* You extended `HeroService` to support `post()`, `put()`, and `delete()` methods.
|
||||
|
||||
我们扩展了`HeroService`来支持 `post()`、`put()` 和 `delete()` 方法。
|
||||
|
||||
* You updated the components to allow adding, editing, and deleting of heroes.
|
||||
|
||||
我们更新了组件,以允许用户添加、编辑和删除英雄。
|
||||
|
||||
* You configured an in-memory web API.
|
||||
|
||||
我们配置了一个内存 Web API。
|
||||
|
||||
* You learned how to use Observables.
|
||||
|
||||
我们学会了如何使用“可观察对象”。
|
||||
|
||||
This concludes the "Tour of Heroes" tutorial.
|
||||
You're ready to learn more about Angular development in the fundamentals section,
|
||||
starting with the [Architecture](guide/architecture "Architecture") guide.
|
||||
|
Loading…
x
Reference in New Issue
Block a user