1012 lines
45 KiB
Plaintext
1012 lines
45 KiB
Plaintext
block includes
|
||
include ../_util-fns
|
||
- var _library_module = 'library module'
|
||
- var _at_angular = '@angular'
|
||
|
||
:marked
|
||
Angular is a framework for building client applications in HTML and
|
||
either JavaScript or a language (like Dart or TypeScript) that compiles to JavaScript.
|
||
|
||
Angular 2是一个用HTML和JavaScript或者一个可以编译成JavaScript的语言(比如Dart或者TypeScript),来构建客户端应用的框架。
|
||
|
||
block angular-parts
|
||
:marked
|
||
The framework consists of several libraries, some of them core and some optional.
|
||
|
||
该框架包括一系列库文件,有些是核心库,有些是可选库。
|
||
|
||
:marked
|
||
You write Angular applications by composing HTML *templates* with Angularized markup,
|
||
writing *component* classes to manage those templates, adding application logic in *services*,
|
||
and boxing components and services in *modules*.
|
||
|
||
我们是这样写Angular应用的:用带Angular扩展语法的HTML写*模板*,
|
||
用*组件*类管理这些模板,用*服务*添加应用逻辑,
|
||
并在*模块*中打包发布组件与服务。
|
||
|
||
Then you launch the app by *bootstrapping* the _root module_.
|
||
Angular takes over, presenting your application content in a browser and
|
||
responding to user interactions according to the instructions you've provided.
|
||
|
||
然后,我们通过*引导*_根模块_来启动该应用。
|
||
Angular在浏览器中接管、展现应用的内容,并根据我们提供的操作指令响应用户的交互。
|
||
|
||
Of course, there is more to it than this.
|
||
You'll learn the details in the pages that follow. For now, focus on the big picture.
|
||
|
||
当然,这只是冰山一角。在以后的页面中,我们还会学到更多细节知识。不过,目前我们还是先关注全景图吧。
|
||
|
||
figure
|
||
img(src="/resources/images/devguide/architecture/overview2.png" alt="overview" style="margin-left:-40px;" width="700")
|
||
|
||
:marked
|
||
The architecture diagram identifies the eight main building blocks of an Angular application:
|
||
|
||
这个架构图展现了Angular应用中的8个主要构造块:
|
||
|
||
* [Modules](#modules)
|
||
|
||
* [模块(Modules)](#modules)
|
||
|
||
* [Components](#components)
|
||
|
||
* [组件(Components)](#components)
|
||
|
||
* [Templates](#templates)
|
||
|
||
* [模板(Templates)](#templates)
|
||
|
||
* [Metadata](#metadata)
|
||
|
||
* [元数据(Metadata)](#metadata)
|
||
|
||
* [Data binding](#data-binding)
|
||
|
||
* [数据绑定(Data Binding)](#data-binding)
|
||
|
||
* [Directives](#directives)
|
||
|
||
* [指令(Directives)](#directives)
|
||
|
||
* [Services](#services)
|
||
|
||
* [服务(Services)](#services)
|
||
|
||
* [Dependency injection](#dependency-injection)
|
||
|
||
* [依赖注入(Dependency Injection)](#dependency-injection)
|
||
|
||
Learn these building blocks, and you're on your way.
|
||
|
||
掌握这些构造块,我们就可以开始使用Angular 2编写应用程序了。
|
||
|
||
|
||
.l-sub-section
|
||
p The code referenced on this page is available as a <live-example></live-example>.
|
||
|
||
p 本章所引用的代码可以从这个<live-example>在线例子</live-example>。
|
||
|
||
.l-main-section
|
||
:marked
|
||
## Modules
|
||
|
||
## 模块
|
||
|
||
figure
|
||
img(src="/resources/images/devguide/architecture/module.png" alt="模块" align="left" style="width:240px; margin-left:-40px;margin-right:10px" )
|
||
:marked
|
||
Angular apps are modular and Angular has its own modularity system called _Angular modules_ or _NgModules_.
|
||
|
||
Angular应用是模块化的,并且Angular有自己的模块系统,它被称为_Angular模块_或_NgModules_。
|
||
|
||
_Angular modules_ are a big deal.
|
||
This page introduces modules; the [Angular modules](ngmodule.html) page covers them in depth.
|
||
|
||
_Angular模块_很重要。
|
||
这里我们只做一个简介,在[Angular模块](ngmodule.html)中会做深入讲解。
|
||
|
||
<br clear="all"><br>
|
||
:marked
|
||
Every Angular app has at least one module, the _root module_, conventionally named `AppModule`.
|
||
|
||
每个Angular应用至少有一个模块(_根模块_),习惯上命名为`AppModule`。
|
||
|
||
While the _root module_ may be the only module in a small application, most apps have many more
|
||
_feature modules_, each a cohesive block of code dedicated to an application domain,
|
||
a workflow, or a closely related set of capabilities.
|
||
|
||
_根模块_在一些小型应用中可能是唯一的模块,不过大多数应用可能会有很多_特性模块_,它们由一组领域类、工作流、或紧密相关的功能聚合而成。
|
||
|
||
An Angular module, whether a _root_ or _feature_, is a class with an `@NgModule` decorator.
|
||
|
||
Angular模块(无论是_根_模块还是_特性模块_)都是一个带有`@NgModule`装饰器的类。
|
||
|
||
.l-sub-section
|
||
:marked
|
||
Decorators are functions that modify JavaScript classes.
|
||
Angular has many decorators that attach metadata to classes so that it knows
|
||
what those classes mean and how they should work.
|
||
<a href="https://medium.com/google-developers/exploring-es7-decorators-76ecb65fb841#.x5c2ndtx0" target="_blank">
|
||
Learn more</a> about decorators on the web.
|
||
|
||
装饰器是用来修饰JavaScript类的函数。
|
||
Angular有很多装饰器,它们负责把元数据附加到类上,以了解那些类的设计意图以及如何使用它们。
|
||
点此<a href="https://medium.com/google-developers/exploring-es7-decorators-76ecb65fb841#.x5c2ndtx0" target="_blank">学习更多知识</a>。
|
||
|
||
:marked
|
||
`NgModule` is a decorator function that takes a single metadata object whose properties describe the module.
|
||
The most important properties are:
|
||
|
||
`NgModule`是一个装饰器函数,它接收一个用来描述模块属性的元数据对象。其中最重要的属性是:
|
||
|
||
* `declarations` - the _view classes_ that belong to this module.
|
||
Angular has three kinds of view classes: [components](#components), [directives](#directives), and [pipes](pipes.html).
|
||
|
||
* `declarations`(声明) - 本模块中拥有的视图类。
|
||
Angular有三种视图类:[组件](#components)、[指令](#directives)和[管道](pipes.html)。
|
||
|
||
* `exports` - the subset of declarations that should be visible and usable in the component [templates](#templates) of other modules.
|
||
|
||
* `exports` - 声明(declaration)的子集,它可用于其它模块中的组件[模板](#templates)。
|
||
|
||
* `imports` - other modules whose exported classes are needed by component templates declared in _this_ module.
|
||
|
||
* `imports` - _本_模块组件模板中需要由其它模块导出的类。
|
||
|
||
* `providers` - creators of [services](#services) that this module contributes to
|
||
the global collection of services; they become accessible in all parts of the app.
|
||
|
||
* `providers` - [服务](#services)的创建者。本模块把它们加入全局的服务表中,让它们在应用中的任何部分都可被访问到。
|
||
|
||
* `bootstrap` - the main application view, called the _root component_,
|
||
that hosts all other app views. Only the _root module_ should set this `bootstrap` property.
|
||
|
||
* `bootstrap` - 标识出应用的主视图(被称为_根组件_),它是所有其它视图的宿主。只有_根模块_才能设置`bootstrap`属性。
|
||
|
||
Here's a simple root module:
|
||
|
||
下面是一个最简单的根模块:
|
||
|
||
+makeExample('app/mini-app.ts', 'module', 'app/app.module.ts')(format='.')
|
||
|
||
.l-sub-section
|
||
:marked
|
||
The `export` of `AppComponent` is just to show how to export; it isn't actually necessary in this example. A root module has no reason to _export_ anything because other components don't need to _import_ the root module.
|
||
|
||
`AppComponent`的`export`语句只是用于演示“如何导出”的,它在这个例子中并无必要。
|
||
根模块不需要_导出_任何东西,因为其它组件不需要导入根模块。
|
||
|
||
:marked
|
||
Launch an application by _bootstrapping_ its root module.
|
||
During development you're likely to bootstrap the `AppModule` in a `main.ts` file like this one.
|
||
|
||
我们通过_引导_根模块来启动应用。
|
||
在开发期间,我们通常在一个`main.ts`文件中来引导`AppModule`,就像这样:
|
||
|
||
|
||
+makeExample('app/main.ts', '', 'app/main.ts')(format='.')
|
||
|
||
:marked
|
||
### Angular modules vs. JavaScript modules
|
||
|
||
### Angular模块 vs. JavaScript模块
|
||
|
||
The Angular module — a class decorated with `@NgModule` — is a fundamental feature of Angular.
|
||
|
||
Angular模块(一个用`@NgModule`装饰的类)是Angular的基础特性。
|
||
|
||
JavaScript also has its own module system for managing collections of JavaScript objects.
|
||
It's completely different and unrelated to the Angular module system.
|
||
|
||
JavaScript还有自己的模块系统,它用来管理一组JavaScript对象。
|
||
它和Angular的模块体系是完全不同而且完全无关的。
|
||
|
||
In JavaScript each _file_ is a module and all objects defined in the file belong to that module.
|
||
The module declares some objects to be public by marking them with the `export` key word.
|
||
Other JavaScript modules use *import statements* to access public objects from other modules.
|
||
|
||
在JavaScript中,每个_文件_就是一个模块,并且该文件中定义的所有对象都从属于那个模块。
|
||
通过`export`关键字,模块可以把它的某些对象声明为公开的。
|
||
别的JavaScript模块中可以使用*import语句*来访问这些公开对象。
|
||
|
||
+makeExample('app/app.module.ts', 'imports', '')(format='.')
|
||
+makeExample('app/app.module.ts', 'export', '')(format='.')
|
||
|
||
.l-sub-section
|
||
:marked
|
||
<a href="http://exploringjs.com/es6/ch_modules.html" target="_blank">Learn more about the JavaScript module system on the web.</a>
|
||
|
||
<a href="http://exploringjs.com/es6/ch_modules.html" target="_blank">可到其它网站深入学习关于JavaScript模块的知识。</a>
|
||
|
||
:marked
|
||
These are two different and _complementary_ module systems. Use them both to write your apps.
|
||
|
||
这两个模块化系统是互补的,我们在写程序时都会用到。
|
||
|
||
### Angular libraries
|
||
|
||
### 模块库
|
||
figure
|
||
img(src="/resources/images/devguide/architecture/library-module.png" alt="Component" align="left" style="width:240px; margin-left:-40px;margin-right:10px" )
|
||
|
||
:marked
|
||
Angular ships as a collection of JavaScript modules. You can think of them as library modules.
|
||
|
||
Angular发布了一组JavaScript模块。我们可以把它们看做库模块。
|
||
|
||
Each Angular library name begins with the `!{_at_angular}` prefix.
|
||
|
||
每个Angular库的名字都带有`!{_at_angular}`前缀。
|
||
|
||
You install them with the **npm** package manager and import parts of them with JavaScript `import` statements.
|
||
|
||
我们可以用**npm**包管理工具安装它们,并且用JavaScript的`import`语句导入它们的某些部件。
|
||
|
||
<br clear="all"><br>
|
||
:marked
|
||
For example, import Angular's `Component` decorator from the `@angular/core` library like this.
|
||
|
||
比如,我们从`@angular/core`库中导入`Component`装饰器,就像这样:
|
||
|
||
+makeExample('app/app.component.ts', 'import', '')(format='.')
|
||
|
||
:marked
|
||
You also import Angular _modules_ from Angular _libraries_ using JavaScript import statements:
|
||
|
||
我们还使用JavaScript的导入语句从Angular_库_中导入Angular的_某些模块_。
|
||
|
||
+makeExample('app/mini-app.ts', 'import-browser-module', '')(format='.')
|
||
|
||
:marked
|
||
In the example of the simple root module above, the application module needs material from within that `BrowserModule`. To access that material, add it to the `@NgModule` metadata `imports` like this.
|
||
|
||
在上面这个关于根模块的小例子中,应用模块需要来自`BrowserModule`的某些素材。要访问这些素材,我们就得把它加入`@NgModule`元数据的`imports`中去,就像这样:
|
||
|
||
+makeExample('app/mini-app.ts', 'ngmodule-imports', '')(format='.')
|
||
|
||
:marked
|
||
In this way you're using both the Angular and JavaScript module systems _together_.
|
||
|
||
这种情况下,我们正在同时使用Angular和JavaScript的模块化系统。
|
||
|
||
It's easy to confuse the two systems because they share the common vocabulary of "imports" and "exports".
|
||
Hang in there. The confusion yields to clarity with time and experience.
|
||
|
||
这两个系统比较容易混淆,因为它们共享相同的词汇(“imports”和“exports”)。
|
||
先放一放,随着时间和经验的增长,自然就会澄清了。
|
||
|
||
.l-sub-section
|
||
:marked
|
||
Learn more from the [Angular modules](ngmodule.html) page.
|
||
|
||
要了解更多,参见[Angular模块](ngmodule.html)页。
|
||
|
||
.l-hr
|
||
|
||
.l-main-section
|
||
:marked
|
||
<a id="components"></a>
|
||
## Components
|
||
|
||
## 组件
|
||
|
||
figure
|
||
img(src="/resources/images/devguide/architecture/hero-component.png" alt="组件" align="left" style="width:200px; margin-left:-40px;margin-right:10px" )
|
||
|
||
:marked
|
||
A _component_ controls a patch of screen called a *view*.
|
||
|
||
_组件_负责控制屏幕上的一小块地方,我们称之为*视图*。
|
||
|
||
For example, the following views are controlled by components:
|
||
|
||
例如,下列视图都是由组件控制的:
|
||
|
||
* The app root with the navigation links.
|
||
|
||
* 带有导航链接的应用根组件。
|
||
|
||
* The list of heroes.
|
||
|
||
* 英雄列表。
|
||
|
||
* The hero editor.
|
||
|
||
* 英雄编辑器。
|
||
|
||
|
||
You define a component's application logic—what it does to support the view—inside a class.
|
||
The class interacts with the view through an API of properties and methods.
|
||
|
||
我们在类中定义组件的应用逻辑(它被用来为视图提供支持)。
|
||
组件通过一些由属性和方法组成的API与视图交互。
|
||
|
||
<a id="component-code"></a>
|
||
For example, this `HeroListComponent` has a `heroes` property that returns !{_an} !{_array} of heroes that it acquires from a service. `HeroListComponent` also has a `selectHero()` method that sets a `selectedHero` property when the user clicks to choose a hero from that list.
|
||
|
||
<a id="component-code"></a>
|
||
例如,`HeroListComponent`有一个`heroes`属性,它返回一个“英雄”数组,这个数组是由一个服务提供的。`HeroListComponent`还有一个`selectHero()`方法,当用户从列表中点选一个英雄时,就把它/她设置到`selectedHero`属性。
|
||
|
||
+makeExcerpt('app/hero-list.component.ts', 'class')
|
||
:marked
|
||
Angular creates, updates, and destroys components as the user moves through the application.
|
||
Your app can take action at each moment in this lifecycle through optional [lifecycle hooks](lifecycle-hooks.html), like `ngOnInit()` declared above.
|
||
|
||
当用户在这个应用中“移动”时,Angular会创建、更新和销毁组件。
|
||
本应用可以通过[生命周期钩子](lifecycle-hooks.html)在组件生命周期的各个时间点上插入自己的操作,比如上面声明的`ngOnInit()`。
|
||
|
||
.l-hr
|
||
|
||
.l-main-section
|
||
:marked
|
||
## Templates
|
||
|
||
## 模板
|
||
|
||
figure
|
||
img(src="/resources/images/devguide/architecture/template.png" alt="模板" align="left" style="width:200px; margin-left:-40px;margin-right:10px" )
|
||
:marked
|
||
You define a component's view with its companion **template**. A template is a form of HTML
|
||
that tells Angular how to render the component.
|
||
|
||
我们通过组件的自带的**模板**来定义视图。模板以HTML形式存在,用来告诉Angular如何渲染组件(视图)。
|
||
|
||
A template looks like regular HTML, except for a few differences. Here is a
|
||
template for our `HeroListComponent`:
|
||
|
||
多数情况下,模板看起来很像标准HTML……当然也有一点奇怪的地方。下面是`HeroListComponent`组件的一个模板。
|
||
|
||
+makeExample('app/hero-list.component.html')
|
||
|
||
:marked
|
||
Although this template uses typical HTML elements like `<h2>` and `<p>`, it also has some differences. Code like `*ngFor`, `{{hero.name}}`, `(click)`, `[hero]`, and `<hero-detail>` uses Angular's [template syntax](template-syntax.html).
|
||
|
||
虽然这个模板使用的是典型的HTML元素,比如`<h2>`和`<p>`,但它也能使用别的。比如`*ngFor`、`{{hero.name}}`、`(click)`、`[hero]`和`<hero-detail>`使用的就是Angular的[模板语法](template-syntax.html)。
|
||
|
||
In the last line of the template, the `<hero-detail>` tag is a custom element that represents a new component, `HeroDetailComponent`.
|
||
|
||
在模板的最后一行,`<hero-detail>`标签就是一个用来表示新组件`HeroDetailComponent`的自定义元素。
|
||
|
||
The `HeroDetailComponent` is a *different* component than the `HeroListComponent` you've been reviewing.
|
||
The `HeroDetailComponent` (code not shown) presents facts about a particular hero, the
|
||
hero that the user selects from the list presented by the `HeroListComponent`.
|
||
The `HeroDetailComponent` is a **child** of the `HeroListComponent`.
|
||
|
||
`HeroDetailComponent`跟以前见到过的`HeroListComponent`是*不同*的组件。
|
||
`HeroDetailComponent`(未展示代码)用于展现一个特定英雄的情况,这个英雄是用户从`HeroListComponent`列表中选择的。
|
||
`HeroDetailComponent`是`HeroListComponent`的*子组件*。
|
||
|
||
figure
|
||
img(src="/resources/images/devguide/architecture/component-tree.png" alt="组件树" align="left" style="width:300px; margin-left:-40px;margin-right:10px" )
|
||
:marked
|
||
Notice how `<hero-detail>` rests comfortably among native HTML elements. Custom components mix seamlessly with native HTML in the same layouts.
|
||
|
||
注意:`<hero-detail>`竟如此和谐的出现在那些原生HTML元素中。
|
||
在同一个格局中,自定义组件和原生HTML融合得天衣无缝。
|
||
|
||
<br clear="all">
|
||
|
||
.l-hr
|
||
|
||
.l-main-section
|
||
:marked
|
||
## Metadata
|
||
|
||
## 元数据
|
||
|
||
figure
|
||
img(src="/resources/images/devguide/architecture/metadata.png" alt="元数据" align="left" style="width:150px; margin-left:-40px;margin-right:10px" )
|
||
|
||
:marked
|
||
<p style="padding-top:10px">Metadata tells Angular how to process a class.</p>
|
||
<p style="padding-top:10px">元数据告诉Angular如何处理一个类。</p>
|
||
<br clear="all">
|
||
:marked
|
||
[Looking back at the code](#component-code) for `HeroListComponent`, you can see that it's just a class.
|
||
There is no evidence of a framework, no "Angular" in it at all.
|
||
|
||
[回头看看](#component-code)`HeroListComponent`就会明白:它只是一个类。
|
||
一点框架的痕迹也没有,里面完全没有出现"Angular"的字样。
|
||
|
||
In fact, `HeroListComponent` really is *just a class*. It's not a component until you *tell Angular about it*.
|
||
|
||
实际上,`HeroListComponent`真的*只是一个类*。直到我们*告诉Angular*这是一个组件为止。
|
||
|
||
To tell Angular that `HeroListComponent` is a component, attach **metadata** to the class.
|
||
|
||
只要把**元数据**附加到这个类,就相当于告诉Angular:`HeroListComponent`是个组件。
|
||
|
||
In !{_Lang}, you attach metadata by using !{_a} **!{_decorator}**.
|
||
Here's some metadata for `HeroListComponent`:
|
||
|
||
在!{_Lang}中,我们用**装饰器(!{_decorator})**来附加元数据。
|
||
下面就是`HeroListComponent`的一些元数据。
|
||
|
||
+makeExcerpt('app/hero-list.component.ts', 'metadata')
|
||
|
||
:marked
|
||
Here is the `@Component` !{_decorator}, which identifies the class
|
||
immediately below it as a component class.
|
||
|
||
这里看到`@Component`!{_decoratorCn}(毫无悬念的)把紧随其后的类标记成了组件类。
|
||
|
||
block ts-decorator
|
||
:marked
|
||
The `@Component` decorator takes a required configuration object with the
|
||
information Angular needs to create and present the component and its view.
|
||
|
||
`@Component`!{_decoratorCn}能接受一个配置对象,Angular会基于这些信息创建和展示组件及其视图。
|
||
|
||
Here are a few of the possible `@Component` configuration options:
|
||
|
||
来看下`@Component`中的一些配置项:
|
||
|
||
:marked
|
||
- `moduleId: module.id`: sets the base for module-relative loading of the `templateUrl`.
|
||
|
||
- `moduleId`: 为与模块相关的URL(如`templateUrl`)提供基地址。
|
||
|
||
- `selector`: CSS selector that tells Angular to create and insert an instance of this component
|
||
where it finds a `<hero-list>` tag in *parent* HTML.
|
||
For example, if an app's HTML contains `<hero-list></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`的一个实例插入到这个标签中。
|
||
|
||
- `templateUrl`: module-relative address of this component's HTML template, shown [above](#templates).
|
||
|
||
- `templateUrl`:组件HTML模板的模块相对地址,我们在[前面](#templates)展示过它。
|
||
|
||
- `providers`: !{_array} of **dependency injection providers** for services that the component requires.
|
||
This is one way to tell Angular that the component's constructor requires a `HeroService`
|
||
so it can get the list of heroes to display.
|
||
|
||
- `providers` - 一个数组,包含组件所依赖的服务所需要的*依赖注入提供商*。
|
||
这是在告诉Angular:该组件的构造函数需要一个`HeroService`服务,这样组件就可以从服务中获得用来显示英雄列表的那些数据。
|
||
|
||
|
||
figure
|
||
img(src="/resources/images/devguide/architecture/template-metadata-component.png" alt="元数据" align="left" style="height:200px; margin-left:-40px;margin-right:10px" )
|
||
:marked
|
||
The metadata in the `@Component` tells Angular where to get the major building blocks you specify for the component.
|
||
|
||
`@Component`里面的元数据会告诉Angular如何取得你为组件指定的元数据。
|
||
|
||
The template, metadata, and component together describe a view.
|
||
|
||
模板、元数据和组件共同描绘出这个视图。
|
||
|
||
Apply other metadata !{_decorator}s in a similar fashion to guide Angular behavior.
|
||
`@Injectable`, `@Input`, and `@Output` are a few of the more popular !{_decorator}s.
|
||
|
||
我们也会沿用类似的风格,用其它元数据!{_decoratorCn}来指导Angular的行为。
|
||
比如`@Injectable`、`@Input`和`@Output`等是一些最常用的!{_decoratorCn}。
|
||
|
||
<br clear="all">
|
||
:marked
|
||
The architectural takeaway is that you must add metadata to your code
|
||
so that Angular knows what to do.
|
||
|
||
这种架构所决定的是:必须往代码中添加元数据,以便Angular知道该做什么。
|
||
|
||
.l-hr
|
||
|
||
.l-main-section
|
||
:marked
|
||
## Data binding
|
||
|
||
## 数据绑定
|
||
|
||
Without a framework, you would be responsible for pushing data values into the HTML controls and turning user responses
|
||
into actions and value updates. Writing such push/pull logic by hand is tedious, error-prone, and a nightmare to
|
||
read as any experienced jQuery programmer can attest.
|
||
|
||
如果没有框架,我们就得自己把数据值推送到HTML控件中,并把用户的反馈转换成动作和值更新。
|
||
如果手工写代码来实现这些推/拉逻辑,肯定会枯燥乏味、容易出错,读起来简直是噩梦 —— 写过jQuery的程序员大概都对此深有体会。
|
||
|
||
figure
|
||
img(src="/resources/images/devguide/architecture/databinding.png" alt="数据绑定" style="width:220px; float:left; margin-left:-40px;margin-right:20px" )
|
||
:marked
|
||
Angular supports **data binding**,
|
||
a mechanism for coordinating parts of a template with parts of a component.
|
||
Add binding markup to the template HTML to tell Angular how to connect both sides.
|
||
|
||
Angular支持**数据绑定**,一种让模板的各部分与组件的各部分相互合作的机制。
|
||
我们往模板HTML中添加绑定标记,来告诉Angular如何连接两者。
|
||
|
||
As the diagram shows, there are four forms of data binding syntax. Each form has a direction — to the DOM, from the DOM, or in both directions.
|
||
|
||
如图所示,数据绑定的语法有四种形式。每种形式都有一个方向 —— 从DOM来、到DOM去、双向,就像图中的箭头所示意的。
|
||
|
||
<br clear="all">
|
||
:marked
|
||
The `HeroListComponent` [example](#templates) template has three forms:
|
||
|
||
`HeroListComponent`[范例](#templates)的模板中包含了三种形式:
|
||
|
||
+makeExcerpt('app/hero-list.component.1.html', 'binding')
|
||
|
||
:marked
|
||
* The `{{hero.name}}` [*interpolation*](displaying-data.html#interpolation)
|
||
displays the component's `hero.name` property value within the `<li>` tags.
|
||
|
||
* `{{hero.name}}`[*插值表达式*](displaying-data.html#interpolation):在`<li>`标签中显示了组件的`hero.name`属性的值。
|
||
|
||
* The `[hero]` [*property binding*](template-syntax.html#property-binding) passes the value of `selectedHero` from
|
||
the parent `HeroListComponent` to the `hero` property of the child `HeroDetailComponent`.
|
||
|
||
* `[hero]`[*属性绑定*](template-syntax.html#property-binding):把父组件`HeroListComponent`的`selectedHero`的值传到子组件`HeroDetailComponent`的`hero`属性中。
|
||
|
||
* The `(click)` [*event binding*](user-input.html#click) calls the component's `selectHero` method when the user clicks
|
||
on a hero's name
|
||
|
||
* `(click)`[*事件绑定*](user-input.html#click):当用户点击英雄的名字时,调用组件的`selectHero`方法。
|
||
|
||
**Two-way data binding** is an important fourth form
|
||
that combines property and event binding in a single notation, using the `ngModel` directive.
|
||
Here's an example from the `HeroDetailComponent` template:
|
||
|
||
**双向数据绑定**:这是很重要的第四种绑定形式,它在`ngModel`指令这个单一标记中同时实现了属性绑定和事件绑定的功能。
|
||
下面是一个来自`HeroDetailComponent`模板的范例:
|
||
|
||
+makeExcerpt('app/hero-detail.component.html', 'ngModel')
|
||
|
||
:marked
|
||
In two-way binding, a data property value flows to the input box from the component as with property binding.
|
||
The user's changes also flow back to the component, resetting the property to the latest value,
|
||
as with event binding.
|
||
|
||
在双向绑定中,数据属性的值会从具有属性绑定的组件传到输入框。通过事件绑定,用户的修改被传回到组件,把属性值设置为最新的值。
|
||
|
||
Angular processes *all* data bindings once per JavaScript event cycle,
|
||
from the root of the application component tree through all child components.
|
||
|
||
Angular在每个JavaScript事件周期中一次性处理*所有的*数据绑定,它会从组件树的根部开始,递归处理全部子组件。
|
||
|
||
figure
|
||
img(src="/resources/images/devguide/architecture/component-databinding.png" alt="数据绑定" style="float:left; width:300px; margin-left:-40px;margin-right:10px" )
|
||
:marked
|
||
Data binding plays an important role in communication
|
||
between a template and its component.
|
||
|
||
数据绑定在模板与对应组件的交互中扮演了一个很重要的角色。
|
||
|
||
<br clear="all">
|
||
figure
|
||
img(src="/resources/images/devguide/architecture/parent-child-binding.png" alt="父/子绑定" style="float:left; width:300px; margin-left:-40px;margin-right:10px" )
|
||
:marked
|
||
Data binding is also important for communication between parent and child components.
|
||
|
||
数据绑定在父组件与子组件的通讯中***也同样重要***。
|
||
|
||
<br clear="all">
|
||
|
||
.l-hr
|
||
|
||
.l-main-section
|
||
:marked
|
||
## Directives
|
||
|
||
## 指令
|
||
|
||
figure
|
||
img(src="/resources/images/devguide/architecture/directive.png" alt="父与子" style="float:left; width:150px; margin-left:-40px;margin-right:10px" )
|
||
:marked
|
||
Angular templates are *dynamic*. When Angular renders them, it transforms the DOM
|
||
according to the instructions given by **directives**.
|
||
|
||
Angular模板是*动态的*。当Angular渲染它们时,它会根据**指令**提供的操作指南对DOM进行修改。
|
||
|
||
A directive is a class with directive metadata. In !{_Lang}, apply the `@Directive` !{_decorator}
|
||
to attach metadata to the class.
|
||
|
||
指令是一个带有“指令元数据”的类。在!{_Lang}中,要通过`@Directive`!{_decoratorCn}把元数据附加到类上。
|
||
|
||
<br clear="all">
|
||
:marked
|
||
A component is a *directive-with-a-template*;
|
||
a `@Component` !{_decorator} is actually a `@Directive` !{_decorator} extended with template-oriented features.
|
||
|
||
我们已经遇到过指令的形式之一:组件。组件是一个*带模板的指令*,而且`@Component`!{_decoratorCn}实际上就是一个`@Directive`!{_decoratorCn},只是扩展了一些面向模板的属性。
|
||
|
||
.l-sub-section
|
||
:marked
|
||
While **a component is technically a directive**,
|
||
components are so distinctive and central to Angular applications that this architectural overview separates components from directives.
|
||
|
||
虽然**严格来说组件就是一个指令**,但是组件非常独特,并在Angular中位于中心地位,所以在架构概览中,我们把组件从指令中独立了出来。
|
||
|
||
:marked
|
||
Two *other* kinds of directives exist: _structural_ and _attribute_ directives.
|
||
|
||
有两种*其它*类型的指令,我们称之为“结构型”指令和“属性(attribute)型”指令。
|
||
|
||
They tend to appear within an element tag as attributes do,
|
||
sometimes by name but more often as the target of an assignment or a binding.
|
||
|
||
它们往往像属性(attribute)一样出现在元素标签中,偶尔会以名字的形式出现但多数时候还是作为赋值目标或绑定目标出现。
|
||
|
||
**Structural** directives alter layout by adding, removing, and replacing elements in DOM.
|
||
|
||
**结构型指令**通过在DOM中添加、移除和替换元素来修改布局。
|
||
|
||
The [example template](#templates) uses two built-in structural directives:
|
||
|
||
我们在[范例模板](#templates)中用到了两个内置的结构型指令。
|
||
|
||
+makeExcerpt('app/hero-list.component.1.html', 'structural')
|
||
:marked
|
||
* [`*ngFor`](displaying-data.html#ngFor) tells Angular to stamp out one `<li>` per hero in the `heroes` list.
|
||
|
||
* [`*ngFor`](displaying-data.html#ngFor)告诉Angular为`heroes`列表中的每个英雄生成一个`<li>`标签。
|
||
|
||
* [`*ngIf`](displaying-data.html#ngIf) includes the `HeroDetail` component only if a selected hero exists.
|
||
|
||
* [`*ngIf`](displaying-data.html#ngIf)表示只有在选择的英雄存在时,才会包含`HeroDetail`组件。
|
||
|
||
block dart-bool
|
||
//- N/A
|
||
|
||
:marked
|
||
**Attribute** directives alter the appearance or behavior of an existing element.
|
||
In templates they look like regular HTML attributes, hence the name.
|
||
|
||
**属性型指令** 修改一个现有元素的外观或行为。在模板中,它们看起来就像是标准的HTML属性,故名。
|
||
|
||
The `ngModel` directive, which implements two-way data binding, is
|
||
an example of an attribute directive. `ngModel` modifies the behavior of
|
||
an existing element (typically an `<input>`)
|
||
by setting its display value property and responding to change events.
|
||
|
||
`ngModel`指令就是属性型指令的一个例子,它实现了双向数据绑定。它修改了现有元素(一般是`<input>`)的行为:它设置了显示属性值,并对change事件做出相应回应。
|
||
|
||
+makeExcerpt('app/hero-detail.component.html', 'ngModel')
|
||
:marked
|
||
Angular has a few more directives that either alter the layout structure
|
||
(for example, [ngSwitch](template-syntax.html#ngSwitch))
|
||
or modify aspects of DOM elements and components
|
||
(for example, [ngStyle](template-syntax.html#ngStyle) and [ngClass](template-syntax.html#ngClass)).
|
||
|
||
Angular还有少量指令,它们或者修改结构布局(如[ngSwitch](template-syntax.html#ngSwitch)),或者修改DOM元素和组件的各个方面
|
||
(如[ngStyle](template-syntax.html#ngStyle)和[ngClass](template-syntax.html#ngClass))。
|
||
|
||
Of course, you can also write your own directives. Components such as
|
||
`HeroListComponent` are one kind of custom directive.
|
||
<!-- PENDING: link to where to learn more about other kinds! -->
|
||
|
||
当然,我们也能编写自己的指令。像`HeroListComponent`这样的组件就是一种自定义指令。
|
||
|
||
.l-hr
|
||
|
||
.l-main-section
|
||
:marked
|
||
## Services
|
||
|
||
## 服务
|
||
|
||
figure
|
||
img(src="/resources/images/devguide/architecture/service.png" alt="服务" style="float:left; margin-left:-40px;margin-right:10px" )
|
||
:marked
|
||
_Service_ is a broad category encompassing any value, function, or feature that your application needs.
|
||
|
||
*服务*分为很多种,包括:值、函数,以及应用所需的特性。
|
||
|
||
Almost anything can be a service.
|
||
A service is typically a class with a narrow, well-defined purpose. It should do something specific and do it well.
|
||
|
||
几乎任何东西都可以是一个服务。
|
||
典型的服务是一个类,具有专注的、良好定义的用途。它应该做一件具体的事情,把它做好。
|
||
<br clear="all">
|
||
:marked
|
||
Examples include:
|
||
|
||
例如:
|
||
|
||
* logging service
|
||
|
||
* 日志服务
|
||
|
||
* data service
|
||
|
||
* 数据服务
|
||
|
||
* message bus
|
||
|
||
* 消息总线
|
||
|
||
* tax calculator
|
||
|
||
* 税款计算器
|
||
|
||
* application configuration
|
||
|
||
* 应用程序配置
|
||
|
||
There is nothing specifically _Angular_ about services. Angular has no definition of a service.
|
||
There is no service base class, and no place to register a service.
|
||
|
||
服务没有什么特别属于*Angular*的特性。Angular对于服务也没有什么定义。
|
||
它甚至都没有定义服务的基类(Base Class),也没有地方注册一个服务。
|
||
|
||
Yet services are fundamental to any Angular application. Components are big consumers of services.
|
||
|
||
即便如此,服务仍然是任何Angular应用的基础。组件就是最大的*服务*消费者。
|
||
|
||
Here's an example of a service class that logs to the browser console:
|
||
|
||
这里是一个“服务”类的范例,用于把日志记录到浏览器的控制台:
|
||
|
||
+makeExcerpt('app/logger.service.ts', 'class')
|
||
|
||
:marked
|
||
Here's a `HeroService` that fetches heroes and returns them in a resolved !{_PromiseLinked}.
|
||
The `HeroService` depends on the `Logger` service and another `BackendService` that handles the server communication grunt work.
|
||
|
||
下面是`HeroService`类,用于获取英雄数据,并通过一个已解析的[承诺(Promise)](http://exploringjs.com/es6/ch_promises.html)返回它们。
|
||
`HeroService`还依赖于`Logger`服务和另一个用来处理服务器通讯工作的`BackendService`服务。
|
||
|
||
+makeExcerpt('app/hero.service.ts', 'class')
|
||
|
||
:marked
|
||
Services are everywhere.
|
||
|
||
服务无处不在。
|
||
|
||
Component classes should be lean. They don't fetch data from the server,
|
||
validate user input, or log directly to the console.
|
||
They delegate such tasks to services.
|
||
|
||
我们更倾向于让组件保持精简。组件不需要从服务器获得数据、不需要验证输入,也不需要直接往控制台写日志。
|
||
它们把这些任务委托给了服务。
|
||
|
||
A component's job is to enable the user experience and nothing more. It mediates between the view (rendered by the template)
|
||
and the application logic (which often includes some notion of a _model_).
|
||
A good component presents properties and methods for data binding.
|
||
It delegates everything nontrivial to services.
|
||
|
||
组件的任务就是提供用户体验,仅此而已。它介于视图(由模板渲染)和应用逻辑(通常包括_模型(model)_的观念)之间。
|
||
设计良好的组件为数据绑定提供属性和方法,把那些其它对它们不重要的事情都委托给服务。
|
||
|
||
Angular doesn't *enforce* these principles.
|
||
It won't complain if you write a "kitchen sink" component with 3000 lines.
|
||
|
||
Angular不会*强制要求*我们遵循这些原则。
|
||
即使我们花3000行代码写了一个“厨房洗碗槽”组件,它也不会抱怨什么。
|
||
|
||
Angular does help you *follow* these principles by making it easy to factor your
|
||
application logic into services and make those services available to components through *dependency injection*.
|
||
|
||
Angular帮助我们*追随*这些原则 —— 它让我们能更轻易的把应用逻辑拆分到服务,并通过*依赖注入*来在组件中使用这些服务。
|
||
|
||
.l-hr
|
||
|
||
.l-main-section
|
||
:marked
|
||
## Dependency Injection
|
||
|
||
## 依赖注入
|
||
|
||
figure
|
||
img(src="/resources/images/devguide/architecture/dependency-injection.png" alt="服务" style="float:left; width:200px; margin-left:-40px;margin-right:10px" )
|
||
:marked
|
||
_Dependency injection_ is a way to supply a new instance of a class
|
||
with the fully-formed dependencies it requires. Most dependencies are services.
|
||
Angular uses dependency injection to provide new components with the services they need.
|
||
|
||
“依赖注入”是提供类的新实例的一种方式,还负责处理好类所需的全部依赖。大多数依赖都是服务。
|
||
Angular也使用依赖注入提供我们需要的组件以及这些组件所需的服务。
|
||
|
||
<br clear="all">
|
||
:marked
|
||
Angular can tell which services a component needs by looking at the types of its constructor parameters.
|
||
For example, the constructor of your `HeroListComponent` needs a `HeroService`:
|
||
|
||
Angular能通过查看构造函数的参数类型,来得知组件需要哪些服务。
|
||
例如,`HeroListComponent`组件的构造函数需要一个`HeroService`:
|
||
|
||
+makeExcerpt('app/hero-list.component.ts (constructor)', 'ctor')
|
||
|
||
:marked
|
||
When Angular creates a component, it first asks an **injector** for
|
||
the services that the component requires.
|
||
|
||
当Angular创建组件时,会首先为组件所需的服务找一个**注入器(Injector)**。
|
||
|
||
An `injector` maintains a container of service instances that it has previously created.
|
||
If a requested service instance is not in the container, the injector makes one and adds it to the container
|
||
before returning the service to Angular.
|
||
When all requested services have been resolved and returned,
|
||
Angular can call the component's constructor with those services as arguments.
|
||
This is *dependency injection*.
|
||
|
||
注入器是一个维护服务实例的容器,存放着以前创建的实例。
|
||
如果容器中还没有所请求的服务实例,注入器就会创建一个服务实例,并且添加到容器中,然后把这个服务返回给Angular。
|
||
当所有的服务都被解析完并返回时,Angular会以这些服务为参数去调用组件的构造函数。
|
||
这就是*依赖注入* 。
|
||
|
||
The process of `HeroService` injection looks a bit like this:
|
||
|
||
`HeroService`注入的过程看起来有点像这样:
|
||
|
||
figure
|
||
img(src="/resources/images/devguide/architecture/injector-injects.png" alt="服务" )
|
||
:marked
|
||
If the injector doesn't have a `HeroService`, how does it know how to make one?
|
||
|
||
如果注入器还没有`HeroService`,它怎么知道该如何创建一个呢?
|
||
|
||
In brief, you must have previously registered a **provider** of the `HeroService` with the injector.
|
||
A provider is something that can create or return a service, typically the service class itself.
|
||
|
||
简单的说,必须在要求注入`HeroService`之前,把一个叫`HeroService`的**提供商Provider**到注入器。
|
||
提供商可以创建并返回服务,通常返回的就是这个“服务类”本身。
|
||
|
||
You can register providers in modules or in components.
|
||
|
||
我们可以在模块上或组件上注册提供商。
|
||
|
||
In general, add providers to the [root module](#module) so that
|
||
the same instance of a service is available everywhere.
|
||
|
||
我们通常会把提供商添加到[根模块](#module)上,以便任何地方使用的都是服务的同一个实例。
|
||
|
||
+makeExample('app/app.module.ts', 'providers', 'app/app.module.ts (module providers)')(format='.')
|
||
|
||
:marked
|
||
Alternatively, register at a component level in the `providers` property of the `@Component` metadata:
|
||
|
||
或者,也可以在`@Component`元数据中的`providers`属性中把它注册在组件层:
|
||
|
||
+makeExample('app/hero-list.component.ts', 'providers', 'app/hero-list.component.ts (component providers)')(format='.')
|
||
|
||
:marked
|
||
Registering at a component level means you get a new instance of the
|
||
service with each new instance of that component.
|
||
|
||
把它注册在组件级表示该组件的每一个新实例都会有一个(在该组件注册的)服务的新实例。
|
||
|
||
<!-- We've vastly oversimplified dependency injection for this overview.
|
||
The full story is in the [dependency injection](dependency-injection.html) page. -->
|
||
|
||
<!--在这个概览中,我们过度简化了依赖注入机制。
|
||
完整的故事出现在[依赖注入](dependency-injection.html)页 -->
|
||
|
||
Points to remember about dependency injection:
|
||
|
||
需要记住的关于依赖注入的要点是:
|
||
|
||
* Dependency injection is wired into the Angular framework and used everywhere.
|
||
|
||
* 依赖注入渗透在整个Angular框架中,并且被到处使用。
|
||
|
||
* The *injector* is the main mechanism.
|
||
|
||
* **注入器(Injector)**是本机制的核心。
|
||
|
||
* An injector maintains a *container* of service instances that it created.
|
||
|
||
* 注入器负责维护一个*容器*,用于存放它创建过的服务实例。
|
||
|
||
* An injector can create a new service instance from a *provider*.
|
||
|
||
* 注入器能使用*提供商*创建一个新的服务实例。
|
||
|
||
* A *provider* is a recipe for creating a service.
|
||
|
||
* *提供商*是一个用于创建服务的“配方”。
|
||
|
||
* Register *providers* with injectors.
|
||
|
||
* 把*提供商*注册到注入器。
|
||
|
||
.l-hr
|
||
|
||
.l-main-section
|
||
:marked
|
||
## Wrap up
|
||
|
||
## 总结
|
||
|
||
You've learned the basics about the eight main building blocks of an Angular application:
|
||
|
||
我们学到的这些只是关于Angular应用程序的八个主要构造块的基础知识:
|
||
|
||
* [Modules](#modules)
|
||
|
||
* [模块](#modules)
|
||
|
||
* [Components](#components)
|
||
|
||
* [组件](#components)
|
||
|
||
* [Templates](#templates)
|
||
|
||
* [模板](#templates)
|
||
|
||
* [Metadata](#metadata)
|
||
|
||
* [元数据](#metadata)
|
||
|
||
* [Data binding](#data-binding)
|
||
|
||
* [数据绑定](#data-binding)
|
||
|
||
* [Directives](#directives)
|
||
|
||
* [指令](#directives)
|
||
|
||
* [Services](#services)
|
||
|
||
* [服务](#services)
|
||
|
||
* [Dependency injection](#dependency-injection)
|
||
|
||
* [依赖注入](#dependency-injection)
|
||
|
||
|
||
That's a foundation for everything else in an Angular application
|
||
and it's more than enough to get going.
|
||
But it doesn't include everything you need to know.
|
||
|
||
这是Angular应用程序中所有其它东西的基础,要使用Angular 2,以这些作为开端就绰绰有余了。
|
||
但它仍然没有包含我们需要知道的全部。
|
||
|
||
Here is a brief, alphabetical list of other important Angular features and services.
|
||
Most of them are covered in this documentation (or soon will be).
|
||
|
||
这里是一个简短的、按字母排序的列表,列出了其它重要的Angular特性和服务。
|
||
它们大多数已经(或即将)包括在这份开发文档中:
|
||
|
||
> [**Animations**](animations.html): Animate component behavior
|
||
without deep knowledge of animation techniques or CSS with Angular's animation library.
|
||
|
||
> [**动画**](animations.html):用Angular的动画库让组件动起来,而不需要对动画技术或CSS有深入的了解。
|
||
|
||
> **Change detection**: The change detection documentation will cover how Angular decides that a component property value has changed,
|
||
when to update the screen, and how it uses **zones** to intercept asynchronous activity and run its change detection strategies.
|
||
|
||
> **变更检测**:“变更检测”文档会告诉你Angular是如何决定组件的属性值变化和什么时候该更新到屏幕的。
|
||
以及它是如何用**zones**来拦截异步行为并执行变更检测策略。
|
||
|
||
> **Events**: The events documentation will cover how to use components and services to raise events with mechanisms for
|
||
publishing and subscribing to events.
|
||
|
||
> **事件**:“事件”文档会告诉你如何使用组件和服务触发支持发布和订阅的事件。
|
||
|
||
> [**Forms**](forms.html): Support complex data entry scenarios with HTML-based validation and dirty checking.
|
||
|
||
> [**表单**](forms.html):通过基于HTML的验证和脏检查机制支持复杂的数据输入场景。
|
||
|
||
> [**HTTP**](server-communication.html): Communicate with a server to get data, save data, and invoke server-side actions with an HTTP client.
|
||
|
||
> [**HTTP**](server-communication.html):通过这个HTTP客户端,可以与服务器通讯,以获得数据、保存数据和触发服务端动作。
|
||
|
||
> [**Lifecycle hooks**](lifecycle-hooks.html): Tap into key moments in the lifetime of a component, from its creation to its destruction,
|
||
by implementing the lifecycle hook interfaces.
|
||
|
||
> [**生命周期钩子**](lifecycle-hooks.html):通过实现生命周期钩子接口,可以切入组件生命中的几个关键点:从创建到销毁。
|
||
|
||
> [**Pipes**](pipes.html): Use pipes in your templates to improve the user experience by transforming values for display. Consider this `currency` pipe expression:
|
||
|
||
> [**管道**](pipes.html):在模板中使用管道转换成可显示的值,以增强用户体验。比如这个`currency`管道表达式:
|
||
|
||
<div style="margin-left:40px">
|
||
code-example().
|
||
price | currency:'USD':true
|
||
</div>
|
||
:marked
|
||
> It displays a price of "42.33" as `$42.33`.
|
||
|
||
> 它把"42.33"显示为`$42.33`。
|
||
|
||
> [**Router**](router.html): Navigate from page to page within the client
|
||
application and never leave the browser.
|
||
|
||
> [**路由器**](router.html):在应用程序客户端导航,并且不离开浏览器。
|
||
|
||
> [**Testing**](testing.html): Run unit tests on your application parts as they interact with the Angular framework
|
||
using the _Angular Testing Platform_.
|
||
|
||
> [**测试**](testing.html):使用Angular测试工具运行单元测试,在你的应用与Angular框架交互时进行测试。
|