基础知识-用户输入 一审完毕

This commit is contained in:
Zhicheng Wang 2016-05-16 15:17:45 +08:00
parent d76964ed91
commit 0d3cb23139
3 changed files with 43 additions and 43 deletions

View File

@ -653,7 +653,7 @@ table
Let's add a temporary [template reference variable](./template-syntax.html#ref-vars) named **spy** Let's add a temporary [template reference variable](./template-syntax.html#ref-vars) named **spy**
to the "Name" `<input>` tag and use the spy to display those classes. to the "Name" `<input>` tag and use the spy to display those classes.
我们往姓名`<input>`标签上添加一个名叫 **spy** 的临时[局部模板变量](./template-syntax.html#local-vars)然后用这个spy来显示它上面的所有css类。 我们往姓名`<input>`标签上添加一个名叫 **spy** 的临时[模板引用变量](./template-syntax.html#local-vars)然后用这个spy来显示它上面的所有css类。
+makeExample('forms/ts/app/hero-form.component.html', 'ngControl-2','app/hero-form.component.html (节选)')(format=".") +makeExample('forms/ts/app/hero-form.component.html', 'ngControl-2','app/hero-form.component.html (节选)')(format=".")

View File

@ -263,7 +263,7 @@ include ../_util-fns
The only exceptions to these guidelines should be in specific circumstances that you thoroughly understand. The only exceptions to these guidelines should be in specific circumstances that you thoroughly understand.
这些指南中唯一的例外是:当你彻底理解了模板表达式之后,仍然觉得这个场景很特殊,那也可以不遵循它 这些指南中唯一的例外应该出现在那些你确信自己已彻底理解的特定场景中
#### No visible side effects #### No visible side effects
#### 没有可见的副作用 #### 没有可见的副作用

View File

@ -6,7 +6,7 @@ include ../_util-fns
In this chapter we learn to bind to those events using the Angular In this chapter we learn to bind to those events using the Angular
event binding syntax. event binding syntax.
当用户点击连接、按下按钮或者输入文字时,我们得知道发生了什么。这些用户操作都会产生DOM事件。 当用户点击链接、按下按钮或者输入文字时,我们得知道发生了什么。这些用户动作都会产生DOM事件。
本章中我们将学会如何使用Angular事件绑定语法来绑定这些事件。 本章中我们将学会如何使用Angular事件绑定语法来绑定这些事件。
[Run the live example](/resources/live-examples/user-input/ts/plnkr.html) [Run the live example](/resources/live-examples/user-input/ts/plnkr.html)
@ -25,7 +25,7 @@ include ../_util-fns
The syntax is simple. We surround the DOM event name in parentheses and assign a quoted template statement to it. The syntax is simple. We surround the DOM event name in parentheses and assign a quoted template statement to it.
As an example, here's an event binding that implements a click handler: As an example, here's an event binding that implements a click handler:
语法非常简单。我们只要把DOM事件的一个包裹在圆括号中,然后用一个放在引号中的模板语句对它赋值就可以了。 语法非常简单。我们只要把DOM事件的名字包裹在圆括号中,然后用一个放在引号中的模板语句对它赋值就可以了。
+makeExample('user-input/ts/app/click-me.component.ts', 'click-me-button')(format=".", language="html") +makeExample('user-input/ts/app/click-me.component.ts', 'click-me-button')(format=".", language="html")
<a id="click"></a> <a id="click"></a>
@ -35,25 +35,24 @@ include ../_util-fns
respond to the click event by calling the component's `onClickMe` method. A [template statement](./template-syntax.html#template-statements) is a subset respond to the click event by calling the component's `onClickMe` method. A [template statement](./template-syntax.html#template-statements) is a subset
of JavaScript with restrictions and a few added tricks. of JavaScript with restrictions and a few added tricks.
等号左边的`(click)`表示用此按钮的click事件作为 **绑定目标** 等号左边的`(click)`表示把该按钮的click事件作为**绑定目标**
等号右边放在引号中的文本是一个 **模板语句** ,在这里我们通过调用组件的`onClickMe`方法来响应这个click事件。 等号右边,引号中的文本是一个**模板语句**,在这里我们通过调用组件的`onClickMe`方法来响应这个click事件。
[模板语句](./template-syntax.html#template-statements)的语法是JavaScript语法的一个受限子集它也添加了少量“小花招”。 [模板语句](./template-syntax.html#template-statements)的语法是JavaScript语法的一个受限子集但它也添加了少量“小花招”。
When writing a binding we must be aware of a template statement's **execution context**. When writing a binding we must be aware of a template statement's **execution context**.
The identifiers appearing within a statement belong to a specific context object. The identifiers appearing within a statement belong to a specific context object.
That object is usually the Angular component that controls the template ... which it definitely is That object is usually the Angular component that controls the template ... which it definitely is
in this case because that snippet of HTML belongs to the following component: in this case because that snippet of HTML belongs to the following component:
一个绑定时,我们必须知道模板语句的 **执行上下文** 写绑定时,我们必须知道模板语句的**执行上下文**。
出现在语句中的各个标识符,全都属于一个特的上下文对象。 出现在模板语句中的各个标识符,全都属于一个特的上下文对象。
这个对象通常都是控制此模板的Angular组件 …… 在本例子它是明确的因为这段HTML片段属于下面这个组件 这个对象通常都是控制此模板的Angular组件…… 在本例中它很明确因为这段HTML片段属于下面这个组件
+makeExample('user-input/ts/app/click-me.component.ts', 'click-me-component', 'app/click-me.component.ts')(format=".") +makeExample('user-input/ts/app/click-me.component.ts', 'click-me-component', 'app/click-me.component.ts')(format=".")
:marked :marked
When the user clicks the button, Angular calls the component's `onClickMe` method. When the user clicks the button, Angular calls the component's `onClickMe` method.
当用户点击此按钮时Angular调用组件的`onClickMe`方法。 当用户点击此按钮时Angular调用组件的`onClickMe`方法。
.l-main-section .l-main-section
:marked :marked
## Get user input from the $event object ## Get user input from the $event object
@ -61,7 +60,7 @@ include ../_util-fns
We can bind to all kinds of events. Let's bind to the keyup event of an input box and replay We can bind to all kinds of events. Let's bind to the keyup event of an input box and replay
what the user types back onto the screen. what the user types back onto the screen.
我们可以绑定到所有类型的事件。我们来绑定到一个输入框的keyup事件并且把用户输入的东西回显到屏幕上。 我们可以绑定到所有类型的事件。让我们试试绑定到一个输入框的keyup事件并且把用户输入的东西回显到屏幕上。
This time we'll (1) listen to an event and (2) grab the user's input. This time we'll (1) listen to an event and (2) grab the user's input.
@ -72,8 +71,8 @@ include ../_util-fns
which we pass to the component's `onKey()` method. which we pass to the component's `onKey()` method.
The user data we want is in that variable somewhere. The user data we want is in that variable somewhere.
Angular把事件对象存入 **`$event`** 变量中,也就是我们传入组件的`onKey()`方法中的那个。 Angular把事件对象存入**`$event`**变量中,也就是我们传到组件的`onKey()`方法中的那个。
我们希望得到的用户数据就在这个变量中的某个地方。 我们希望取得的用户数据就在该变量中的某个地方。
+makeExample('user-input/ts/app/keyup.components.ts', 'key-up-component-1-class-no-type', 'app/keyup.components.ts (类 v.1)')(format=".") +makeExample('user-input/ts/app/keyup.components.ts', 'key-up-component-1-class-no-type', 'app/keyup.components.ts (类 v.1)')(format=".")
:marked :marked
The shape of the `$event` object is determined by whatever raises the event. The shape of the `$event` object is determined by whatever raises the event.
@ -84,7 +83,7 @@ include ../_util-fns
`$event`对象的形态取决于所触发的事件。 `$event`对象的形态取决于所触发的事件。
这个`keyup`事件来自DOM所以`$event`必须是一个[标准的DOM事件对象](https://developer.mozilla.org/en-US/docs/Web/API/Event)。 这个`keyup`事件来自DOM所以`$event`必须是一个[标准的DOM事件对象](https://developer.mozilla.org/en-US/docs/Web/API/Event)。
`$event.target`给了我们一个[`HTMLInputElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement),它有一个`value`属性,是用户所输入的数据。 `$event.target`给了我们一个[`HTMLInputElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement)对象,它有一个`value`属性,是用户所输入的数据。
The `onKey()` component method is where we extract the user's input The `onKey()` component method is where we extract the user's input
from the event object, adding that input to the list of user data that we're accumulating in the component's `values` property. from the event object, adding that input to the list of user data that we're accumulating in the component's `values` property.
@ -92,7 +91,7 @@ include ../_util-fns
to display the accumulating `values` property back on screen. to display the accumulating `values` property back on screen.
组件的`onKey()`方法是我们从事件对象中提取出用户输入的地方,然后把这个输入加入用户数据的列表,并累加到组件的`values`属性上。 组件的`onKey()`方法是我们从事件对象中提取出用户输入的地方,然后把这个输入加入用户数据的列表,并累加到组件的`values`属性上。
后使用[插值表达式](./template-syntax.html#interpolation)来把存放累加结果的`values`属性回显到屏幕上。 后使用[插值表达式](./template-syntax.html#interpolation)来把存放累加结果的`values`属性回显到屏幕上。
Enter the letters "abc", and then backspace to remove them. Enter the letters "abc", and then backspace to remove them.
Here's what the UI displays: Here's what the UI displays:
@ -118,7 +117,7 @@ figure.image-display
<br>Strong typing reveals a serious problem with passing a DOM event into the method: <br>Strong typing reveals a serious problem with passing a DOM event into the method:
too much awareness of template details, too little separation of concerns. too much awareness of template details, too little separation of concerns.
<br>强类型暴露出了把DOM事件对象传入方法导致的一个严重问题关心模板细节太多关注点分离得太少。(译注:比如需要进行丑陋的强制类型转换) <br>开启强类型之后暴露出一个严重问题直接把DOM事件对象传给方法会导致过多关心模板细节而关注点分离得太少了。(译注:比如需要进行丑陋的强制类型转换)
We'll address this problem in our next try at processing user keystrokes. We'll address this problem in our next try at processing user keystrokes.
@ -131,7 +130,7 @@ figure.image-display
## 从一个模板引用变量中获得用户输入 ## 从一个模板引用变量中获得用户输入
There's another way to get the user data without the `$event` variable. There's another way to get the user data without the `$event` variable.
还有另一种方式,不用通过`$event`变量获得用户数据。 还有另一种方式,不用通过`$event`变量获得用户数据。
Angular has a syntax feature called [**template reference variables**](./template-syntax.html#ref-vars). Angular has a syntax feature called [**template reference variables**](./template-syntax.html#ref-vars).
These variables grant us direct access to an element. These variables grant us direct access to an element.
@ -144,7 +143,7 @@ figure.image-display
Here's an example of using a template reference variable Here's an example of using a template reference variable
to implement a clever keystroke loopback in an ultra-simple template. to implement a clever keystroke loopback in an ultra-simple template.
下面的例子就通过使用局部模板变量,在一个超简单的模板中实现了一个聪明的按键反馈循环。 下面的例子就通过使用局部模板变量,在一个超简单的模板中实现了一个聪明的按键反馈循环。
+makeExample('user-input/ts/app/loop-back.component.ts', 'loop-back-component', 'app/loop-back.component.ts')(format=".") +makeExample('user-input/ts/app/loop-back.component.ts', 'loop-back-component', 'app/loop-back.component.ts')(format=".")
:marked :marked
We've declared a template reference variable named `box` on the `<input>` element. We've declared a template reference variable named `box` on the `<input>` element.
@ -152,13 +151,13 @@ figure.image-display
grab the input element's `value` and display it grab the input element's `value` and display it
with interpolation between `<p>` tags. with interpolation between `<p>` tags.
我们在`<input>`元素上定义了一个名叫`box`的局部模板变量。 我们在`<input>`元素上定义了一个名叫`box`的模板引用变量。
`box`变量引用的就是`<input>`元素本身这意味着我们可以获得input元素的`value`值,并通过插值表达式把它显示在`<p>`标签中。 `box`变量引用的就是`<input>`元素本身这意味着我们可以获得input元素的`value`值,并通过插值表达式把它显示在`<p>`标签中。
The template is completely self contained. It doesn't bind to the component, The template is completely self contained. It doesn't bind to the component,
and the component does nothing. and the component does nothing.
本模板完全是自包含的。它不需要绑定到组件,即使绑定,组件也不需要做什么。 本模板完全是自包含的。它不需要绑定到组件,即使绑定,组件也不需要额外做什么。
Type in the input box, and watch the display update with each keystroke. *Voila!* Type in the input box, and watch the display update with each keystroke. *Voila!*
@ -170,7 +169,7 @@ figure.image-display
:marked :marked
**This won't work at all unless we bind to an event**. **This won't work at all unless we bind to an event**.
**除非我们绑定到一个事件,否则这将完全无法工作。 **我们必须绑定到一个事件,否则这将完全无法工作。**
Angular only updates the bindings (and therefore the screen) Angular only updates the bindings (and therefore the screen)
if we do something in response to asynchronous events such as keystrokes. if we do something in response to asynchronous events such as keystrokes.
@ -182,14 +181,14 @@ figure.image-display
That is all it takes to keep Angular happy. We said it would be clever! That is all it takes to keep Angular happy. We said it would be clever!
这就是我们为什么需要把`keyup`事件绑定到一个语句,它做了……好吧,它啥也没做。 这就是我们为什么需要把`keyup`事件绑定到一个语句,它做了……好吧,它啥也没做。
它被绑定到了数字0这是我们所能想到的最短语句。 它被绑定到了数字0因为这是我们所能想到的最短语句。
这么做完全是为了讨好Angular。我们认为还应该有更聪明的方式 这么做完全是为了讨好Angular。我们认为还应该有更聪明的方式
:marked :marked
That template reference variable is intriguing. It's clearly easier to get to the textbox with that That template reference variable is intriguing. It's clearly easier to get to the textbox with that
variable than to go through the `$event` object. Maybe we can rewrite our previous variable than to go through the `$event` object. Maybe we can rewrite our previous
keyup example so that it uses the variable to get the user's input. Let's give it a try. keyup example so that it uses the variable to get the user's input. Let's give it a try.
局部模板变量很有意思。它用一个变量就简洁明了的获了文本框,而不再需要通过`$event`对象。 模板引用变量很有意思。它用一个变量就简洁明了的获了文本框,而不再需要通过`$event`对象。
也许我们可以重写前面的keyup范例以便它能用这个变量来获得用户输入。我们这就试试看。 也许我们可以重写前面的keyup范例以便它能用这个变量来获得用户输入。我们这就试试看。
+makeExample('user-input/ts/app/keyup.components.ts', 'key-up-component-2' ,'app/keyup.components.ts (v2)')(format=".") +makeExample('user-input/ts/app/keyup.components.ts', 'key-up-component-2' ,'app/keyup.components.ts (v2)')(format=".")
:marked :marked
@ -198,7 +197,7 @@ figure.image-display
It no longer requires knowledge of the `$event` and its structure. It no longer requires knowledge of the `$event` and its structure.
看起来真是简单多了。 看起来真是简单多了。
这个方案最漂亮的一点是:我们的组件代码从视图中获得了干净的数据值。再也不需要知道`$event`变量及其结构了。 该方案最漂亮的一点是:我们的组件代码从视图中获得了干干净净的数据值。再也不用了解`$event`变量及其结构了。
<a id="key-event"></a> <a id="key-event"></a>
.l-main-section .l-main-section
@ -224,7 +223,8 @@ figure.image-display
the update happens inside the event binding statement. A better practice the update happens inside the event binding statement. A better practice
would be to put the update code in the component.) would be to put the update code in the component.)
只有在这种情况下,我们才更新组件的`values`属性。(在这个例子中,更新代码是写在事件绑定语句中的。但在实践中更好的方式是把更新代码放到组件中。) 只有在这种情况下,我们才更新组件的`values`属性。
(在这个例子中,更新代码是写在事件绑定语句中的。但在实践中更好的方式是把更新代码放到组件中。)
+makeExample('user-input/ts/app/keyup.components.ts', 'key-up-component-3' ,'app/keyup.components.ts (v3)')(format=".") +makeExample('user-input/ts/app/keyup.components.ts', 'key-up-component-3' ,'app/keyup.components.ts (v3)')(format=".")
:marked :marked
Here's how it works. Here's how it works.
@ -267,7 +267,7 @@ figure.image-display
pressing Enter, clicking the Add button, or clicking elsewhere on the page. pressing Enter, clicking the Add button, or clicking elsewhere on the page.
让我们在一个微型应用中把它们放在一起,它能显示一个英雄列表,并且把新的英雄加到列表中。 让我们在一个微型应用中把它们放在一起,它能显示一个英雄列表,并且把新的英雄加到列表中。
用户可以通过下列步骤田家英雄:先在输入框中输入,然后按下回车键、按下添加按钮或点击页面中的其它地方。 用户可以通过下列步骤添加英雄:先在输入框中输入,然后按下回车键、按下添加按钮或点击页面中的其它地方。
figure.image-display figure.image-display
img(src='/resources/images/devguide/user-input/little-tour-anim.gif' alt="简版英雄指南") img(src='/resources/images/devguide/user-input/little-tour-anim.gif' alt="简版英雄指南")
@ -282,7 +282,7 @@ figure.image-display
:marked :marked
We've seen almost everything here before. A few things are new or bear repeating. We've seen almost everything here before. A few things are new or bear repeating.
我们在这里看到了以前接触过的几乎每一个概念。有少量新东西,其它是复习。 我们在这里几乎看到了以前接触过的每一个概念。有少量新东西,其它是复习。
### Use template variables to refer to elements ### Use template variables to refer to elements
### 使用模板变量引用元素 ### 使用模板变量引用元素
@ -291,14 +291,14 @@ figure.image-display
We can use `newHero` from any sibling or child of the `<input>` element. We can use `newHero` from any sibling or child of the `<input>` element.
`newHero`模板变量引用了`<input>`元素。 `newHero`模板变量引用了`<input>`元素。
我们可以在`<input>`元素的任何兄弟组件或子组件中使用`newHero`。 我们可以在`<input>`元素的任何兄弟节点或子节点中使用`newHero`。
Getting the element from a template variable makes the button click handler Getting the element from a template variable makes the button click handler
simpler. Without the variable, we'd have to use a fancy CSS selector simpler. Without the variable, we'd have to use a fancy CSS selector
to find the input element. to find the input element.
从模板变量中获得元素让按钮click事件处理变得更简单。 从模板变量中获得元素让按钮click事件处理变得更简单。
如果没有变量,我们就不得不使用“时髦的”CSS选择器来查找这个input元素。 如果没有变量,我们就不得不使用“奇怪的”CSS选择器来查找这个input元素。
### Pass values, not elements ### Pass values, not elements
### 传入值,不要传元素 ### 传入值,不要传元素
@ -310,48 +310,48 @@ figure.image-display
But that would require `addHero` to pick its way through the `<input>` DOM element, But that would require `addHero` to pick its way through the `<input>` DOM element,
something we learned to dislike in our first try at a [keyup component](#keyup1). something we learned to dislike in our first try at a [keyup component](#keyup1).
需要`addHero`通过访问`<input>`DOM元素的方式先取得它 —— 我们以前在[keyup组件](#keyup1)中学过的那种讨厌的方式。 但那需要`addHero`通过访问`<input>`DOM元素的方式先取得它 —— 也就是我们以前在[keyup组件](#keyup1)中学过的那种讨厌的方式。
Instead, we grab the input box *value* and pass *that* to `addHero`. Instead, we grab the input box *value* and pass *that* to `addHero`.
The component knows nothing about HTML or the DOM, which is the way we like it. The component knows nothing about HTML or the DOM, which is the way we like it.
该怎么做呢?我们获得输入框的 *value* ,并且把它传入`addHero`。 该怎么做呢?我们该取得输入框的*value*,并把它传给`addHero`。
该组件不需要知道关于HTML或DOM的任何知识我们更喜欢这种方式。 该组件不需要知道关于HTML或DOM的任何知识我们更喜欢这种方式。
### Keep template statements simple ### Keep template statements simple
### 保持模板中的语句简洁 ### 保持模板中的语句简洁
We bound `(blur)` to *two* JavaScript statements. We bound `(blur)` to *two* JavaScript statements.
我们把`(blue)`事件绑定到了 *两个* JavaScript语句。 我们把`(blue)`事件绑定到了*两条*JavaScript语句。
We like the first one, which calls `addHero`. We like the first one, which calls `addHero`.
We do not like the second one, which assigns an empty string to the input box value. We do not like the second one, which assigns an empty string to the input box value.
我们喜欢前一,它调用了`addHero`。 我们喜欢前一,它调用了`addHero`。
我们不喜欢第二,它把一个空值赋值给了输入框的`value`。 我们不喜欢第二,它把一个空值赋值给了输入框的`value`。
The second statement exists for a good reason. We have to clear the input box after adding the new hero to the list. The second statement exists for a good reason. We have to clear the input box after adding the new hero to the list.
The component has no way to do that itself because it has no access to the The component has no way to do that itself because it has no access to the
input box (our design choice). input box (our design choice).
第二个语句的存在有一个好理由:在把新的英雄加入列表中之后,我们得清除输入框的值。 第二条语句的存在理由很充分:在把新的英雄加入列表中之后,我们得清除输入框的值。
组件自己做不到这一点,它不能访问输入框(我们的设计就是这样)。 组件自己做不到这一点,它不能访问输入框(我们的设计就是这样)。
Although the example *works*, we are rightly wary of JavaScript in HTML. Although the example *works*, we are rightly wary of JavaScript in HTML.
Template statements are powerful. We're supposed to use them responsibly. Template statements are powerful. We're supposed to use them responsibly.
Complex JavaScript in HTML is irresponsible. Complex JavaScript in HTML is irresponsible.
虽然范例 *能工作* 但我们得对HTML中的JavaScript保持警惕。 虽然范例*能工作*但我们得对HTML中的JavaScript保持警惕。
模板语句很强大。我们要负责任的使用它们。 模板语句很强大,所以我们更得认真负责的使用它们。
但显然在HTML中使用复杂的JavaScript是不负责任的表现。 但显然在HTML中使用复杂的JavaScript是不负责任的表现。
Should we reconsider our reluctance to pass the input box into the component? Should we reconsider our reluctance to pass the input box into the component?
我们要重新考虑我们是否不得不把输入框传给组件? 我们要重新考虑是否不得不把输入框传给组件?
There should be a better third way. And there is, as we'll see when we learn about `NgModel` in the [Forms](forms.html) chapter. There should be a better third way. And there is, as we'll see when we learn about `NgModel` in the [Forms](forms.html) chapter.
应该有一种更好的第三条路。确实有!当我们在[表单](forms.html)一章学到`ngModel`时就明白了。 应该有一种更好的第三条路。恩,确实有!当我们在[表单](forms.html)一章学到`ngModel`时就明白了。
.l-main-section .l-main-section
:marked :marked
## Source code ## Source code
@ -359,7 +359,7 @@ figure.image-display
Here is all the code we talked about in this chapter. Here is all the code we talked about in this chapter.
下面是我们在本章中讨论的所有源码。 下面是我们在本章中讨论的所有源码。
+makeTabs(` +makeTabs(`
user-input/ts/app/click-me.component.ts, user-input/ts/app/click-me.component.ts,
user-input/ts/app/keyup.components.ts, user-input/ts/app/keyup.components.ts,