Merge remote-tracking branch 'remotes/angular.io/master'

# Conflicts:
#	harp.json
#	public/_includes/_hero-home.jade
#	public/_includes/_scripts-include.jade
#	public/docs/_examples/quickstart/js/package.1.json
#	public/docs/_includes/_side-nav.jade
#	public/docs/js/latest/cookbook/ts-to-js.jade
#	public/docs/ts/latest/_data.json
#	public/docs/ts/latest/api/_data.json
#	public/docs/ts/latest/cookbook/_data.json
#	public/docs/ts/latest/cookbook/aot-compiler.jade
#	public/docs/ts/latest/cookbook/ngmodule-faq.jade
#	public/docs/ts/latest/cookbook/rc4-to-rc5.jade
#	public/docs/ts/latest/glossary.jade
#	public/docs/ts/latest/guide/_data.json
#	public/docs/ts/latest/guide/attribute-directives.jade
#	public/docs/ts/latest/guide/browser-support.jade
#	public/docs/ts/latest/guide/forms.jade
#	public/docs/ts/latest/guide/lifecycle-hooks.jade
#	public/docs/ts/latest/guide/ngmodule.jade
#	public/docs/ts/latest/guide/router.jade
#	public/docs/ts/latest/guide/style-guide.jade
#	public/docs/ts/latest/guide/template-syntax.jade
#	public/docs/ts/latest/guide/testing.jade
#	public/docs/ts/latest/guide/upgrade.jade
#	public/docs/ts/latest/quickstart.jade
#	public/docs/ts/latest/tutorial/_data.json
#	public/docs/ts/latest/tutorial/toh-pt5.jade
#	public/docs/ts/latest/tutorial/toh-pt6.jade
This commit is contained in:
rexebin 2016-10-17 22:48:30 +01:00
parent ce3930b2c0
commit ef1eb67ceb
2 changed files with 163 additions and 346 deletions

View File

@ -10,24 +10,21 @@ block includes
:marked
# Contents
# 目录
* [Directives overview](#directive-overview)
* [指令概览](#directive-overview)
* [Build a simple attribute directive](#write-directive)
* [创建简单的属性型指令](#write-directive)
* [Apply the attribute directive to an element in a template](#apply-directive)
* [Respond to user-initiated events](#respond-to-user)
* [Pass values into the directive using data binding](#bindings)
* [Bind to a second property](#second-property)
In this chapter we will
本章中我们将:
* [write an attribute directive to change the background color](#write-directive)
* [写一个用来改变背景色的属性型指令](#write-directive)
* [apply the attribute directive to an element in a template](#apply-directive)
* [把这个属性型指令应用到模板中的元素](#apply-directive)
* [respond to user-initiated events](#respond-to-user)
* [Respond to user-initiated events](#respond-to-user)
* [响应用户引发的事件](#respond-to-user)
* [pass values into the directive using data binding](#bindings)
* [Pass values into the directive using data binding](#bindings)
* [使用数据绑定把值传到指令中](#bindings)
* [Bind to a second property](#second-property)
* [绑定第二个属性](#second-property)
试试<live-example>在线例子</live-example>。
@ -39,77 +36,39 @@ a#directive-overview
## 指令概览
There are three kinds of directives in Angular:
1. Components&mdash;directives with a template.
1. Structural directives&mdash;change the DOM layout by adding and removing DOM elements.
1. Attribute directives&mdash;change the appearance or behavior of an element.
在Angular中有三种类型的指令
在Angular中有三种类型的指令
1. Components
1. 组件
1. Structural directives
1. 结构型指令
1. Attribute directives
1. 属性型指令
1. Components&mdash;directives with a template.
1. 组件 - 拥有模板的指令
1. Structural directives&mdash;change the DOM layout by adding and removing DOM elements.
1. 结构型指令 - 通过添加和移除DOM元素改变DOM格局的指令
1. Attribute directives&mdash;change the appearance or behavior of an element.
1. 属性型指令 - 改变元素显示和行为的指令。
*Components* are the most common of the three directives. Read more about creating them
in step three of [QuickStart](../quickstart.html#root-component).
*组件*是这三种指令中最常用的,我们在构建应用程序时会写大量组件。参见[快速开始](../quickstart.html#root-component)第三步,了解更多创建组件的信息。
*Structural Directives* change the structure of the view. Two examples are [NgFor](template-syntax.html#ngFor) and [NgIf](template-syntax.html#ngIf)
in the [Template Syntax](template-syntax.html) page.
*结构型*指令会通过添加/删除DOM元素来更改DOM树布局。[NgFor](template-syntax.html#ngFor)和[NgIf](template-syntax.html#ngIf)就是两个最熟悉的例子。
*Attribute directives* are used as attributes of elements. The built-in [NgStyle](template-syntax.html#ngStyle) directive in the [Template Syntax](template-syntax.html) page, for example,
*组件*其实是一个带模板的指令。
它是这三种指令中最常用的,我们在构建应用程序时会写大量组件。
[*Structural* directives](structural-directives.html) can change the DOM layout by adding and removing DOM elements.
[NgFor](template-syntax.html#ngFor) and [NgIf](template-syntax.html#ngIf) are two familiar examples.
[*结构型*指令](structural-directives.html)会通过添加/删除DOM元素来更改DOM树布局。
[NgFor](template-syntax.html#ngFor)和[NgIf](template-syntax.html#ngIf)就是两个最熟悉的例子。
An *Attribute* directive can change the appearance or behavior of an element.
The built-in [NgStyle](template-syntax.html#ngStyle) directive, for example,
can change several element styles at the same time.
*属性型*指令改变一个元素的外观或行为。
比如,内置的[NgStyle](template-syntax.html#ngStyle)指令可以同时修改元素的多种样式。
We are going to write our own attribute directive to set an element's background color
when the user hovers over that element.
我们准备写一个自己的属性型指令,当用户把鼠标悬浮在元素上时,它会设置元素的背景色。
.l-sub-section
:marked
We don't need *any* directive to simply set the background color.
We can set it with the special [Style Binding](template-syntax.html#style-binding) like this:
其实我们并不需要*任何*指令来设置背景色。
可以通过[样式绑定](template-syntax.html#style-binding)来设置它,就像这样:
+makeExample('attribute-directives/ts/app/app.component.1.html','p-style-background')
:marked
That wouldn't be nearly as much fun as creating our own directive.
但这样的话就没法享受创建自定义指令的乐趣了。
Besides, we're not just *setting* the color; we'll be *changing* the color
in response to a user action, a mouse hover.
再说,我们不仅要*设置*颜色,还要响应用户的动作(鼠标悬浮),来*更改*这个颜色。
*属性型*指令改变一个元素的外观或行为。比如,内置的[NgStyle](template-syntax.html#ngStyle)指令可以同时修改元素的多种样式。
.l-main-section
a#write-directive
:marked
## Build a simple attribute directive
## 创建一个简单的属性型指令
An attribute directive minimally requires building a controller class annotated with
`@Directive`, which specifies the selector that identifies
the attribute.
## 创建一个简单的属性型指令
An attribute directive minimally requires building a controller class annotated with
`@Directive`, which specifies the selector identifying
the attribute associated with the directive.
The controller class implements the desired directive behavior.
属性型指令至少需要一个带有`@Directive`装饰器的控制器类。该装饰器指定了一个选择器,用于指出与此指令相关联的属性名字。
@ -118,36 +77,37 @@ a#write-directive
This page demonstrates building a simple attribute
directive to set an element's background color
when the user hovers over that element.
本章展示了如何创建简单的属性型指令,在用户鼠标悬浮在一个元素上时,改变它的背景色
.l-sub-section
:marked
Technically, a directive isn't necessary to simply set the background color. Style binding can set styles as follows:
实际上,指令并不一定只是简单的设置背景颜色。样式绑定可以像下面这样设置样式:
+makeExample('attribute-directives/ts/app/app.component.1.html','p-style-background')
:marked
Read more about [style binding](template-syntax.html#style-binding) on the [Template Syntax](template-syntax.html) page.
参见[模板语法](template-syntax.html)章的[样式绑定](template-syntax.html#style-binding)。
For a simple example, though, this will demonstrate how attribute directives work.
Let's build a small illustrative example together.
让我们构建一个小例子来说明它。
作为一个简单的例子,它展示了属性型指令是如何工作的。
:marked
### Write the directive code
Create a new project folder (`attribute-directives`) and follow the steps in [QuickStart](../quickstart.html).
### Our first draft
### 第一个草稿
Create a new project folder (`attribute-directives`) and follow the steps in the [QuickStart](../quickstart.html).
### 编写指令代码
Create a new project folder (`attribute-directives`) and follow the steps in [QuickStart](../quickstart.html).
创建一个项目文件夹(`attribute-directives`)并按照[快速起步](../quickstart.html)中的步骤进行初始化。
include ../_quickstart_repo
:marked
Create the following source file in the indicated folder with the following code:
Create the following source file in the indicated folder with the given code:
在指定的文件夹下创建下列源码文件:
+makeExample('app/highlight.directive.1.ts')
@ -155,88 +115,78 @@ include ../_quickstart_repo
block highlight-directive-1
:marked
The `import` statement specifies symbols from the Angular `core`:
`import`语句指定了从Angular的`core`库导入的一些符号。
1. `Directive` provides the functionality of the `@Directive` decorator.
1. `Directive`提供`@Directive`装饰器功能。
1. `ElementRef` [injects](dependency-injection.html) into the directive's constructor
1. `ElementRef` [注入](dependency-injection.html)到指令构造函数中。
so the code can access the DOM element.
这样代码可以访问DOM元素。
1. `Input` allows data to flow from the binding expression into the directive.
1. `Input`将数据从绑定表达式传达到指令中。
1. `Renderer` allows the code to change the DOM element's style.
1. `Renderer` 让代码可以改变DOM元素的样式。
Next, the `@Directive` decorator function contains the directive metadata in a configuration object
as an argument.
We begin by importing some symbols from the Angular `core`.
We need the `Directive` symbol for the `@Directive` decorator.
We need the `ElementRef` to [inject](dependency-injection.html) into the directive's constructor
so we can access the DOM element.
We also need `Renderer` so we can change the DOM element's style.
We don't need `Input` immediately but we will need it later in the chapter.
我们先从Angular的`core`库中导入一些符号。
然后需要为`@Directive`装饰器导入`Directive`。
然后需要导入[注入](dependency-injection.html)到指令构造函数中的`ElementRef`这样我们才能访问DOM元素。
还需要注入`Renderer`服务以便更改DOM元素的样式。
虽然眼下还不需要`Input`,但在稍后的章节中很快就会用到它。
Then we define the directive metadata in a configuration object passed
as an argument to the `@Directive` decorator function.
然后,通过给`@Directive`装饰器函数传入一个“配置对象”来定义指令的元数据。
然后,`@Directive`装饰器函数以“配置对象”参数的形式,包含了指令的元数据。
:marked
`@Directive` requires a CSS selector to identify
the HTML in the template that is associated with the directive.
A `@Directive` decorator for an attribute directive requires a css selector to identify
the HTML in the template that is associated with our directive.
属性型指令的`@Directive`装饰器需要一个css选择器以便从模板中识别出关联到这个指令的HTML。
The [CSS selector for an attribute](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors)
is the attribute name in square brackets.
Here, the directive's selector is `[myHighlight]`.
Angular will locate all elements in the template that have an attribute named `myHighlight`.
属性型指令的`@Directive`装饰器需要一个css选择器以便从模板中识别出关联到这个指令的HTML。
[css中的attribute选择器](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors)就是属性名称加方括号
[css中的attribute选择器](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors)就是属性名称加方括号。
这里,指令的选择器是`[myHighlight]`Angular将会在模板中找到带有`myHighlight`这个属性的元素。
Our directive's selector is `[myHighlight]`.
Angular will locate all elements in the template that have an attribute named `myHighlight`.
这个指令的选择器是`[myHighlight]`于是Angular就会在模板中找到带有`myHighlight`这个属性的元素。
.l-sub-section
:marked
### Why not call it "highlight"?
### 为什么不直接叫做"highlight"
Though *highlight* is a more concise name than *myHighlight* and would work,
a best practice is to prefix selector names to ensure
they don't conflict with standard HTML attributes.
This also reduces the risk colliding with third-party directive names.
### 为什么不直接叫做"highlight"
*highlight* is a nicer name than *myHighlight* and, technically, it would work if we called it that.
理论上,*highlight*是一个比*myHighlight*更好的名字,而且在这里它确实能工作。
However, we recommend picking a selector name with a prefix to ensure
that it cannot conflict with any standard HTML attribute, now or in the future.
There is also less risk of colliding with a third-party directive name when we give ours a prefix.
不过我们还是建议选择一个带前缀的选择器名称以保证无论现在还是未来它都不会和任何标准HTML属性发生冲突。
当使用自己的前缀时,也会减少和第三方指令发生命名冲突的风险。
但是最佳实践是在选择器名字前面添加前缀以确保它们不会与标准HTML属性冲突。
它同时减少了与第三方指令名字发生冲突的危险。
Make sure you do **not** prefix the `highlight` directive name with **`ng`** because
that prefix is reserved for Angular and using it could cause bugs that are difficult to diagnose. For a simple demo, the short prefix, `my`, helps distinguish your custom directive.
We do **not** prefix our `highlight` directive name with **`ng`**.
That prefix belongs to Angular.
我们**不能**给自己的`highlight`指令添加**`ng`**前缀。
那个前缀属于Angular。
We need a prefix of our own, preferably short, and `my` will do for now.
我们需要一个自己的前缀,最好短点,目前用的这个`my`前缀就不错。
确认你**不会**给自己的`highlight`指令添加**`ng`**前缀。
那个前缀属于Angular使用它可能导致无法检测的问题。比如这个简短的前缀`my`可以帮助你区分自定义指令。
p
| After the #[code @Directive] metadata comes the directive's controller class, called #[code HighlightDirective], which contains the logic for the directive.
p
| #[code @Directive]元数据的后面就是指令的控制器类,叫做#[code HighlightDirective],它包括了指令的工作逻辑。
+ifDocsFor('ts')
| Exporting #[code HighlightDirective] makes it accessible to other components.
| We export `HighlightDirective` to make it accessible to other components.
p
| `@Directive`元数据的后面就是指令的控制器类,它包括了指令的工作逻辑。
+ifDocsFor('ts')
| 我们导出`HighlightDirective`以便让它可以被其它组件访问。
| 导出#[code HighlightDirective]以便让它可以被其它组件访问。
:marked
Angular creates a new instance of the directive's controller class for
each matching element, injecting an Angular `ElementRef` and `Renderer`
@ -244,9 +194,6 @@ p
`ElementRef` is a service that grants direct access to the DOM element
through its `nativeElement` property and `Renderer` allows the code to set the element style.
`ElementRef` is a service that grants us direct access to the DOM element
through its `nativeElement` property and with `Renderer` we can set the element style.
Angular会为每个被指令匹配上的元素创建一个该指令控制器类的实例并把Angular的`ElementRef`和`Renderer`注入进它的构造函数。
`ElementRef`是一个服务它赋予我们直接访问DOM元素的能力。通过它的`nativeElement`属性和`Renderer`服务,我们可以设置元素的样式。
@ -254,15 +201,14 @@ p
a#apply-directive
:marked
## Apply the attribute directive
To use the new `HighlightDirective`, create a template that
## 使用属性型指令
The `AppComponent` in this sample is a test harness for our `HighlightDirective`.
Let's give it a new template that
To use the new `HighlightDirective`, create a template that
applies the directive as an attribute to a paragraph (`p`) element.
In Angular terms, the `<p>` element will be the attribute **host**.
这个例子中,`AppComponent`是用来测试`HighlightDirective`的一个壳。
我们来给它一个新的模板,把这个指令作为属性应用到一个段落(`p`)元素上。
要使用这个新的`HighlightDirective`,创建一个模板,把这个指令作为属性应用到一个段落(`p`)元素上。
用Angular的话说`<p>`元素就是这个属性型指令的**宿主**。
p
| Put the template in its own
@ -275,23 +221,14 @@ p
+makeExample('attribute-directives/ts/app/app.component.1.html',null,'app/app.component.html')(format=".")
:marked
Now reference this template in the `AppComponent`:
A separate template file is clearly overkill for a 2-line template.
Hang in there; we're going to expand it later.
Meanwhile, we'll revise the `AppComponent` to reference this template.
对于一个只有两行的模板来说,使用一个独立的模板文件确实有点过分了。
先别管它,我们后面很快就会扩展它。
同时,要修改`AppComponent`,使其引用这个模板。
现在,引用`AppComponent`的模板:
+makeExample('attribute-directives/ts/app/app.component.ts',null,'app/app.component.ts')
:marked
Next, add an `import` statement to fetch the `Highlight` directive and
add that class to the `declarations` NgModule metadata. This way Angular
recognizes the directive when it encounters `myHighlight` in the template.
We'll add an `import` statement to fetch the 'Highlight' directive and,
added that class to the `declarations` NgModule metadata so that Angular
will recognize our directive when it encounters `myHighlight` in the template.
我们添加了一个`import`语句来获得'Highlight'指令类,并把这个类添加到`AppComponent`组件的`declarations`数组中。
接下来,添加了一个`import`语句来获得'Highlight'指令类,并把这个类添加到`AppComponent`组件的`declarations`数组中。
这样当Angular在模板中遇到`myHighlight`时,就能认出这是指令了。
+makeExample('attribute-directives/ts/app/app.module.ts',null,'app/app.module.ts')
@ -299,8 +236,6 @@ p
:marked
Now when the app runs, the `myHighlight` directive highlights the paragraph text.
We run the app and see that our directive highlights the paragraph text.
运行应用,就会看到我们的指令确实高亮了段落中的文本。
figure.image-display
@ -308,7 +243,7 @@ figure.image-display
.l-sub-section
:marked
### Your directive isn't working?
### Your directive isn't working?
### 你的指令没生效?
Did you remember to add the directive to the the `declarations` attribute of `@NgModule`? It is easy to forget!
@ -329,27 +264,16 @@ figure.image-display
in the array, Angular knows to check the import statements and from there,
to go to `highlight.directive.ts` to find out what `myHighlight` does.
Angular detects that we're trying to bind to *something* but it doesn't know what.
We have to tell it by listing `HighlightDirective` in the `declarations` metadata array.
这是因为Angular检测到我们正在尝试绑定到*某些东西*,但它不认识。
我们必需把`HighlightDirective`列在元数据的`declarations`数组中,来告诉它有这样一个指令。
Angular检测到你正在尝试绑定到*某些东西*,但它不认识。所以它在`declarations`元数据数组中查找。
把`HighlightDirective`列在元数据的这个数组中Angular就会检查对应的导入语句从而找到`highlight.directive.ts`,并了解`myHightlight`的功能。
:marked
To summarize, Angular found the `myHighlight` attribute on the `<p>` element. It created
an instance of the `HighlightDirective` class,
injecting a reference to the element into the constructor
where the `<p>` element's background style is set to yellow.
Let's recap what happened.
我们来概括一下发生了什么。
Angular found the `myHighlight` attribute on the `<p>` element. It created
an instance of the `HighlightDirective` class,
injecting a reference to the element into the constructor
where we set the `<p>` element's background style to yellow.
Angular在`<p>`元素上发现了一个`myHighlight`属性。
总结Angular在`<p>`元素上发现了一个`myHighlight`属性。
然后它创建了一个`HighlightDirective`类的实例,并把所在元素的引用注入到了指令的构造函数中。
在构造函数中,我们把`<p>`元素的背景设置为了黄色。
@ -357,76 +281,60 @@ figure.image-display
a#respond-to-user
:marked
## Respond to user-initiated events
## Respond to user action
## 响应用户的操作
## 响应用户引发的事件
Currently, `myHighlight` simply sets an element color.
The directive should set the color when the user hovers over an element.
当前,`myHighlight`只是简单的设置元素的颜色。
这个指令应该在用户鼠标悬浮一个元素时,设置它的颜色。
This requires two things:
1. detecting when the user hovers into and out of the element.
2. responding to those actions by setting and clearing the highlight color.
To do this, you can apply the `@HostListener` !{_decorator} to methods which are called when an event is raised.
We are not satisfied to simply set an element color.
Our directive should set the color in response to a user action.
Specifically, we want to set the color when the user hovers over an element.
我们不能满足于设置元素的颜色。
我们的指令要响应用户的操作而设置颜色。
确切的说,希望在用户的鼠标滑过当前元素时设置颜色。
We'll need to
我们需要:
1. detecting when the user hovers into and out of the element.
1. detect when the user hovers into and out of the element,
1. 检测用户的鼠标啥时候进入和离开这个元素。
2. respond to those actions by setting and clearing the highlight color, respectively.
2. 通过设置和清除高亮色来响应这些操作。
We apply the `@HostListener` !{_decorator} to methods which are called when an event is raised.
2. responding to those actions by setting and clearing the highlight color.
2. 通过设置和清除高亮色来响应这些操作。
To do this, you can apply the `@HostListener` !{_decorator} to methods which are called when an event is raised.
从事件检测开始吧。
把`host`属性加入指令的元数据中,并给它一个配置对象,用来指定两个鼠标事件,并在它们被触发时,调用指令中的方法:
+makeExample('attribute-directives/ts/app/highlight.directive.2.ts','host')(format=".")
.l-sub-section
:marked
The `@HostListener` !{_decorator} refers to the DOM element that hosts an attribute directive, the `<p>` in this case.
It is possible to attach event listeners by manipulating the host DOM element directly, but
The `@HostListener` !{_decorator} refers to the DOM element that hosts our attribute directive, the `<p>` in our case.
`@HostListener`装饰器引用的是我们这个属性型指令的宿主元素,在这个例子中就是`<p>`。
We could have attached event listeners by manipulating the host DOM element directly, but
It is possible to attach event listeners by manipulating the host DOM element directly, but
可以通过直接操纵DOM元素的方式给宿主DOM元素挂上一个事件监听器但是
there are at least three problems with such an approach:
但这种方法至少有三个问题:
1. You have to write the listeners correctly.
1. 必须正确的书写事件监听器。
1. The code must *detach* the listener when the directive is destroyed to avoid memory leaks.
1. 当指令被销毁的时候,必须*摘掉*事件监听器,否则就会导致内存泄露。
1. Talking to DOM API directly isn't a best practice.
可以通过直接操纵DOM元素的方式给宿主DOM元素挂上一个事件监听器。
但这种方法至少有三个问题:
1. We have to write the listeners correctly.
1. 必须正确的书写事件监听器。
1. We must *detach* our listener when the directive is destroyed to avoid memory leaks.
1. 当指令被销毁的时候,必须*摘掉*事件监听器,否则就会导致内存泄露。
1. We'd be talking to DOM API directly which, we learned, is something to avoid.
1. 必须直接和DOM API打交道但正如我们学过的那样应该避免这样做。
Let's roll with the `@HostListener` !{_decorator}.
我们还是围绕`@HostListener`装饰器来吧。
1. 必须直接和DOM API打交道但正如我们学过的那样应该避免这样做。
:marked
Now implement the two mouse event handlers:
Now we implement the two mouse event handlers:
现在,我们实现那两个鼠标事件处理器:
@ -440,7 +348,6 @@ a#respond-to-user
我们要修改构造函数,来把`ElementRef.nativeElement`存进这个私有变量。
+makeExample('attribute-directives/ts/app/highlight.directive.2.ts','ctor')(format=".")
:marked
Here's the updated directive:
@ -461,20 +368,17 @@ figure.image-display
a#bindings
:marked
## Pass values into the directive using data binding
## Configure the directive with binding
## 通过绑定来配置指令
## 通过绑定来传递值到指令中
Currently the highlight color is hard-coded within the directive. That's inflexible.
A better practice is to set the color externally with a binding as follows:
We should set the color externally with a binding like this:
现在的高亮颜色是在指令中硬编码进去的。这样没有弹性。
我们应该通过绑定从外部设置这个颜色。就像这样:
+makeExample('attribute-directives/ts/app/app.component.html','pHost')
:marked
You can extend the directive class with a bindable **input** `highlightColor` property and use it to highlight text.
We'll extend our directive class with a bindable **input** `highlightColor` property and use it when we highlight text.
我们将给指令类增加一个可绑定**输入**属性`highlightColor`,当需要高亮文本的时候,就用它。
@ -499,10 +403,6 @@ a#input
property binding under the `myHighlight` alias.
Without this input metadata Angular rejects the binding.
See the [appendix](#why-input) below for more information.
`@Input` adds metadata to the class that makes the `highlightColor` property available for
property binding under the `myHighlight` alias.
We must add this input metadata or Angular will reject the binding.
See the [appendix](#why-input) below to learn why.
`@Input`把元数据添加到了类上,这让`highlightColor`能被以`myHighlight`为别名进行绑定。
必须添加这个input元数据否则Angular会拒绝绑定。
@ -510,113 +410,72 @@ a#input
.l-sub-section
:marked
### @Input(_alias_)
Currently, the code **aliases** the `highlightColor` property with the attribute name by
### @Input(_alias_)
### @Input(_别名_)
The developer who uses this directive expects to bind to the attribute name, `myHighlight`.
The directive property name is `highlightColor`. That's a disconnect.
使用这个指令的开发人员会期望绑定到属性名`myHighlight`上,
而指令中的属性名是`highlightColor`。两者联系不起来。
We could resolve the discrepancy by renaming the property to `myHighlight` and define it as follows:
我们可以通过把属性名改为`myHighlight`来解决这个矛盾,就像这样:
+makeExcerpt('app/highlight.directive.ts', 'highlight', '')
:marked
Maybe we don't want that property name inside the directive perhaps because it
doesn't express our intention well.
We can **alias** the `highlightColor` property with the attribute name by
Currently, the code **aliases** the `highlightColor` property with the attribute name by
passing `myHighlight` into the `@Input` #{_decorator}:
但我们可能在指令中不想要那样一个属性名,因为它不能很好的表示我们的意图。
可以通过把`myHighlight`传给`@Input`#{_decoratorCn}来把这个属性名作为`highlightColor`属性的别名。
当前,代码通过将`myHighlight`传递到`@Input`装饰器,把`myHighlight`属性**别名**到属性名字上。
+makeExcerpt('app/highlight.directive.ts', 'color', '')
:marked
The code binds to the attribute name, `myHighlight`, but the
the directive property name is `highlightColor`. That's a disconnect.
代码绑定到`myHighlight`属性名,但是指令属性名为`highlightColor`。这是一个断点。
You can resolve the discrepancy by renaming the property to `myHighlight` and define it as follows:
你可以通过重命名属性名到`myHighlight`来移除这个区别,像这样:
+makeExcerpt('app/highlight.directive.ts', 'highlight', '')
:marked
Now that you're getting the highlight color as an input, modify the `onMouseEnter()` method to use
it instead of the hard-coded color name and define red as the default color.
Now that we're getting the highlight color as an input, we modify the `onMouseEnter()` method to use
it instead of the hard-coded color name.
We also define red as the default color to fallback on in case
the user neglects to bind with a color.
现在,通过输入型属性得到了高亮的颜色,然后修改`onMouseEnter()`来使用它代替硬编码的那个颜色名。
我们还把红色定义为默认颜色,以便在用户忘了绑定颜色时作为备用。
+makeExcerpt('attribute-directives/ts/app/highlight.directive.ts', 'mouse-enter', '')
:marked
To let users pick the highlight color and bind their choice to the directive,
update `app.component.html` as follows:
Now we'll update our `AppComponent` template to let
users pick the highlight color and bind their choice to our directive.
我们这就更新`AppComponent`的模板,来让用户选择一个高亮颜色,并把选择结果绑定到指令上。
Here is the updated template:
这里是更新后的模板:
更新`AppComponent`的模板,来让用户选择一个高亮颜色,并把选择结果绑定到指令上:
+makeExcerpt('attribute-directives/ts/app/app.component.html', 'v2', '')
.l-sub-section
:marked
### Where is the templated *color* property?
### 模板的*color*属性在哪里?
You may notice that the radio button click handlers in the template set a `color` property
and the code is binding that `color` to the directive.
However, you never defined a color property for the host `AppComponent`.
Yet this code works. Where is the template `color` value going?
你可能注意到,模板中的单选按钮的点击事件处理器设置了一个`color`属性,而且把`color`绑定到指令上。
但是,你从未在这个宿主`AppComponent`中定义`color`属性,代码仍然工作正常。模板的`color`值去哪儿了?
Browser debugging reveals that Angular dynamically added a `color` property
### 模板的*color*属性在哪里?
The eagle-eyed may notice that the radio button click handlers in the template set a `color` property
and we are binding that `color` to the directive.
We should expect to find a `color` on the host `AppComponent`.
眼尖的读者可能发现了,模板中的单选按钮的点击事件处理器设置了一个`color`属性,而且把`color`绑定到指令上。
我们会期望在这个宿主`AppComponent`上发现一个`color`属性。
**We never defined a color property for the host *AppComponent***!
And yet this code works. Where is the template `color` value going?
**但我们从来没有在宿主`AppComponent`上定义过color属性**
不过这段代码却能正常工作。模板中的`color`值哪去了?
Browser debugging reveals that Angular dynamically added a `color` property
to the runtime instance of the `AppComponent`.
在浏览器中调试就会发现Angular在`AppComponent`的运行期实例上添加了一个`color`属性。
This is *convenient* behavior but it is also *implicit* behavior that could be confusing.
For clarity, consider adding the `color` property to the `AppComponent`.
在浏览器中调试就会发现Angular在`AppComponent`的运行期实例上添加了一个`color`属性。
This is *convenient* behavior but it is also *implicit* behavior that could be confusing.
While it's cool that this technique works, we recommend adding the `color` property to the `AppComponent`.
这是一个*很便利的*行为,但它也是*隐式的*行为,这容易让人困惑。
虽然这样也可行,但我们建议你还是要把`color`属性加到`AppComponent`中。
:marked
Here is the second version of the directive in action.
Here is our second version of the directive in action.
下面是指令操作演示的第二版。
figure.image-display
img(src="/resources/images/devguide/attribute-directives/highlight-directive-v2-anim.gif" alt="Highlight v.2")
@ -625,41 +484,31 @@ figure.image-display
a#second-property
:marked
## Bind to a second property
## 绑定到第二个属性
This example directive only has a single customizable property. A real app often needs more.
本例的指令只有一个可定制属性,真实的引用通常需要更多。
Let's allow the template developer to set the default color&mdash;the color that prevails until the user picks a highlight color.
To do this, first add a second **input** property to `HighlightDirective` called `defaultColor`:
## 绑定到第二个属性
Our directive only has a single, customizable property. What if we had ***two properties***?
我们的指令只有一个可定制属性,如果有***两个***呢?
Let's allow the template developer to set the default color, the color that prevails until the user picks a highlight color.
We'll add a second **input** property to `HighlightDirective` called `defaultColor`:
我们要让模板开发者设置一个默认颜色,直到用户选择了一个高亮颜色才失效。
要让模板开发者设置一个默认颜色,直到用户选择了一个高亮颜色才失效。
给`HighlightDirective`添加第二个**输入型**属性`defaultColor`
+makeExample('attribute-directives/ts/app/highlight.directive.ts', 'defaultColor')(format=".")
:marked
The `defaultColor` property has a setter that overrides the hard-coded default color, "red".
You don't need a getter.
`defaultColor`属性是一个setter函数它代替了硬编码的默认颜色“red”。不需要getter函数。
How do you bind to it? The app is already using `myHighlight` attribute name as a binding target.
该如何绑定到它?别忘了已经把`myHighlight`属性名用作绑定目标了。
Remember that a *component is a directive, too*.
You can add as many component property bindings as you need by stringing them along in the template
as in this example that sets the `a`, `b`, `c` properties to the string literals 'a', 'b', and 'c'.
We don't need a getter.
`defaultColor`属性是一个setter函数它代替了硬编码的默认颜色“red”。不需要getter函数。
How do we bind to it? We already "burned" the `myHighlight` attribute name as a binding target.
该如何绑定到它?别忘了已经把`myHighlight`属性名用作绑定目标了。
Remember that a *component is a directive too*.
We can add as many component property bindings as we need by stringing them along in the template
as in this example that sets the `a`, `b`, `c` properties to the string literals 'a', 'b', and 'c'.
记住,*组件也是指令*。
只要需要,就可以通过把它们依次串在模板中来为组件添加多个属性绑定。
@ -668,7 +517,6 @@ code-example(format="." ).
&lt;my-component [a]="'a'" [b]="'b'" [c]="'c'">&lt;my-component>
:marked
The same holds true for an attribute directive.
We do the same thing with an attribute directive.
在属性型指令中也可以这样做。
+makeExample('attribute-directives/ts/app/app.component.html', 'defaultColor')(format=".")
@ -676,13 +524,9 @@ code-example(format="." ).
Here the code is binding the user's color choice to the `myHighlight` attribute as before.
It is *also* binding the literal string, 'violet', to the `defaultColor`.
Here we're binding the user's color choice to the `myHighlight` attribute as we did before.
We're *also* binding the literal string, 'violet', to the `defaultColor`.
这里,我们像以前一样把用户选择的颜色绑定到了`myHighlight`上。
我们*还*把字符串字面量'violet'绑定到了`defaultColor`上。
Here is the final version of the directive in action.
下面就是该指令最终版的操作演示。
@ -692,23 +536,19 @@ figure.image-display
.l-main-section
:marked
## Summary
This page covered how to:
- [Build a simple **attribute directive** to attach behavior to an HTML element](#write-directive).
- [Use that directive in a template](#apply-directive).
- [Respond to **events** to change behavior based on an event](#respond-to-user).
- [Use **binding** to pass values to the attribute directive](#bindings).
## 总结
We now know how to
现在,我们知道了该如何:
- [build a simple **attribute directive** to attach behavior to an HTML element](#write-directive),
This page covered how to:
本章介绍了如何:
- [Build a simple **attribute directive** to attach behavior to an HTML element](#write-directive).
- [构建一个简单的**属性型指令**来为一个HTML元素添加行为](#write-directive)
- [use that directive in a template](#apply-directive),
- [Use that directive in a template](#apply-directive).
- [在模板中使用那个指令](#apply-directive)
- [respond to **events** to change behavior based on an event](#respond-to-user),
- [Respond to **events** to change behavior based on an event](#respond-to-user).
- [响应**事件**,以便基于事件改变行为](#respond-to-user)
- and [use **binding** to pass values to the attribute directive](#bindings).
- 以及[使用**绑定**来把值传给属性型指令](#bindings)。
- [Use **binding** to pass values to the attribute directive](#bindings).
- 以及[使用**绑定**来把值传给属性型指令](#bindings)。
The final source:
@ -735,22 +575,16 @@ a#why-input
.l-main-section
:marked
### Appendix: Input properties
### 附录Input属性
In this demo, the `highlightColor` property is an ***input*** property of
`HighlightDirective`.
本例中, `highlightColor`属性是`HighlightDirective`指令的一个***input***属性。
You've seen properties in bindings before but never had to declare them as anything. Why now?
### 附录Input属性
Earlier we declared the `highlightColor` property to be an ***input*** property of our
`HighlightDirective`
之前, 我们曾把`highlightColor`定义为`HighlightDirective`指令的一个***input***属性。
We've seen properties in bindings before.
We never had to declare them as anything. Why now?
以前也见过属性绑定,但我们从没有定义过它们。为什么现在就不行了?
Angular makes a subtle but important distinction between binding **sources** and **targets**.
@ -760,16 +594,13 @@ a#why-input
In all previous bindings, the directive or component property was a binding ***source***.
A property is a *source* if it appears in the template expression to the ***right*** of the equals (=).
A property is a *target* when it appears in **square brackets** ([ ]) to the **left** of the equals (=)
as it is does when binding to the `myHighlight` property of the `HighlightDirective`.
在以前的所有绑定中,指令或组件的属性都是绑定***源***。
如果属性出现在了模板表达式等号(=)的***右侧***,它就是一个*源*。
A property is a *target* when it appears in **square brackets** ([ ]) to the **left** of the equals (=) ...
as it is does when we bind to the `myHighlight` property of the `HighlightDirective`,
A property is a *target* when it appears in **square brackets** ([ ]) to the **left** of the equals (=)
as it is does when binding to the `myHighlight` property of the `HighlightDirective`.
如果它出现在了**方括号**([ ])中,并且出现在等号(=)的**左侧**,它就是一个*目标*……
就像在绑定到`HighlightDirective`的`myHighlight`属性时所做的那样。
+makeExample('attribute-directives/ts/app/app.component.html','pHost')(format=".")
@ -785,45 +616,31 @@ a#why-input
You must declare it as an *input* property or
Angular rejects the binding with a clear error.
We must declare it as an *input* property.
Angular rejects the binding with a clear error if we don't.
`[myHighlight]="color"`中的'myHighlight'就是绑定***目标***。
必须把它定义为一个*Input*属性否则Angular就会拒绝这次绑定并给出一个明确的错误。
Angular treats a *target* property differently for a good reason.
A component or directive in target position needs protection.
Angular这样区别对待*目标*属性有充分的理由。
作为目标的组件或指令需要保护。
Imagine that `HighlightDirective` did truly wonderous things in a
popular open source project.
假想一下,`HighlightDirective`真是一个好东西。
我们优雅的把它当作礼物送给全世界。
Surprisingly, some people &mdash; perhaps naively &mdash;
start binding to *every* property of the directive.
Not just the one or two properties you expected them to target. *Every* property.
That could really mess up your directive in ways you didn't anticipate and have no desire to support.
The ***input*** declaration ensures that consumers of your directive can only bind to
the properties of the public API but nothing else.
Angular这样区别对待*目标*属性有充分的理由。
作为目标的组件或指令需要保护。
Imagine that our `HighlightDirective` did truly wonderous things.
We graciously made a gift of it to the world.
假想一下,`HighlightDirective`真是一个好东西。
我们优雅的把它当作礼物送给全世界。
To our surprise, some people &mdash; perhaps naively &mdash;
started binding to *every* property of our directive.
Not just the one or two properties we expected them to target. *Every* property.
That could really mess up our directive in ways we didn't anticipate and have no desire to support.
出乎意料的是,有些人(可能因为太天真)开始绑定到这个指令中的*每一个*属性。
不仅仅只是我们预期为绑定目标的那一两个属性,而是*每一个*。
这可能会扰乱指令的工作方式 —— 我们既不想这样做也不想支持它们这样做。
The *input* declaration ensures that consumers of our directive can only bind to
the properties of our public API ... nothing else.
The ***input*** declaration ensures that consumers of your directive can only bind to
the properties of the public API but nothing else.
于是,这种*输入*声明可以确保指令的消费者只能绑定到公开API中的属性其它的都不行。

View File

@ -2495,7 +2495,7 @@ a(href="#toc") 回到顶部
**Why?** If you ever need to rename the property or event name associated with
`@Input` or `@Output`, you can modify it a single place.
**为何?** 如果你需要重命名属性或者`@Input`或者关联的事件名字
**为何?** 如果你需要重命名属性或者`@Input`或者`@Output`关联的事件名字,你可以在一个位置修改。
.s-why
:marked