用户输入触发 DOM 事件。我们通过事件绑定来监听它们,把更新过的数据导入回我们的组件和 model。
当用户点击链接、按下按钮或者输入文字时,这些用户动作都会产生 DOM 事件。
本章解释如何使用 Angular 事件绑定语法把这些事件绑定到事件处理器。
User actions such as clicking a link, pushing a button, and entering
text raise DOM events.
This page explains how to bind those events to component event handlers using the Angular
event binding syntax.
You can use Angular event bindings
to respond to any DOM event.
Many DOM events are triggered by user input. Binding to these events provides a way to
get input from the user.
要绑定 DOM 事件,只要把 DOM 事件的名字包裹在圆括号中,然后用放在引号中的模板语句对它赋值就可以了。
To bind to a DOM event, surround the DOM event name in parentheses and assign a quoted
template statement to it.
下例展示了一个事件绑定,它实现了一个点击事件处理器:
The following example shows an event binding that implements a click handler:
The (click) to the left of the equals sign identifies the button's click event as the target of the binding.
The text in quotes to the right of the equals sign
is the template statement, which reponds
to the click event by calling the component's onClickMe method.
写绑定时,需要知道模板语句的执行上下文。
出现在模板语句中的每个标识符都属于特定的上下文对象。
这个对象通常都是控制此模板的 Angular 组件。
上例中只显示了一行 HTML,那段 HTML 片段属于下面这个组件:
When writing a binding, be aware of a template statement's execution context.
The identifiers in a template statement belong to a specific context object,
usually the Angular component controlling the template.
The example above shows a single line of HTML, but that HTML belongs to a larger component:
src/app/click-me.component.ts
@Component({
selector:'click-me',template:`
<button (click)="onClickMe()">Click me!</button>
{{clickMessage}}`})exportclassClickMeComponent{
clickMessage ='';
onClickMe(){this.clickMessage ='You are my hero!';}}
当用户点击按钮时,Angular 调用ClickMeComponent的onClickMe方法。
When the user clicks the button, Angular calls the onClickMe method from ClickMeComponent.
通过 $event 对象取得用户输入
Get user input from the $event object
DOM 事件可以携带可能对组件有用的信息。
本节将展示如何绑定输入框的keyup事件,在每个敲击键盘时获取用户输入。
DOM events carry a payload of information that may be useful to the component.
This section shows how to bind to the keyup event of an input box to get the user's input after each keystroke.
下面的代码监听keyup事件,并将整个事件载荷 ($event) 传递给组件的事件处理器。
The following code listens to the keyup event and passes the entire event payload ($event) to the component event handler.
当用户按下并释放一个按键时,触发keyup事件,Angular 在$event变量提供一个相应的 DOM
事件对象,上面的代码将它作为参数传递给onKey()方法。
When a user presses and releases a key, the keyup event occurs, and Angular provides a corresponding
DOM event object in the $event variable which this code passes as a parameter to the component's onKey() method.
src/app/keyup.components.ts (类 v.1)
exportclassKeyUpComponent_v1{
values ='';
onKey(event: any){// without type infothis.values +=event.target.value +' | ';}}
$event对象的属性取决于 DOM 事件的类型。例如,鼠标事件与输入框编辑事件包含了不同的信息。
The properties of an $event object vary depending on the type of DOM event. For example,
a mouse event includes different information than a input box editing event.
所有标准 DOM 事件对象都有一个target属性,
引用触发该事件的元素。
在本例中,target是<input>元素,
event.target.value返回该元素的当前内容。
All standard DOM event objects
have a target property, a reference to the element that raised the event.
In this case, target refers to the <input> element and
event.target.value returns the current contents of that element.
After each call, the onKey() method appends the contents of the input box value to the list
in the component's values property, followed by a separator character (|).
The interpolation
displays the accumulating input box changes from the values property.
假设用户输入字母“abc”,然后用退格键一个一个删除它们。
用户界面将显示:
Suppose the user enters the letters "abc", and then backspaces to remove them one by one.
Here's what the UI displays:
Alternatively, you could accumulate the individual keys themselves by substituting event.key
for event.target.value in which case the same user input would produce:
The example above casts the $event as an any type.
That simplifies the code at a cost.
There is no type information
that could reveal properties of the event object and prevent silly mistakes.
下面的例子,使用了带类型方法:
The following example rewrites the method with types:
src/app/keyup.components.ts (class v.1 - typed )
exportclassKeyUpComponent_v1{
values ='';
onKey(event:KeyboardEvent){// with type infothis.values +=(<HTMLInputElement>event.target).value +' | ';}}
The $event is now a specific KeyboardEvent.
Not all elements have a value property so it casts target to an input element.
The OnKey method more clearly expresses what it expects from the template and how it interprets the event.
传入 $event 是靠不住的做法
Passing $event is a dubious practice
类型化事件对象揭露了重要的一点,即反对把整个 DOM 事件传到方法中,因为这样组件会知道太多模板的信息。
只有当它知道更多它本不应了解的 HTML 实现细节时,它才能提取信息。
这就违反了模板(用户看到的)和组件(应用如何处理用户数据)之间的分离关注原则。
Typing the event object reveals a significant objection to passing the entire DOM event into the method:
the component has too much awareness of the template details.
It can't extract information without knowing more than it should about the HTML implementation.
That breaks the separation of concerns between the template (what the user sees)
and the component (how the application processes user data).
下面将介绍如何用模板引用变量来解决这个问题。
The next section shows how to use template reference variables to address this problem.
There's another way to get the user data: use Angular
template reference variables.
These variables provide direct access to an element from within the template.
To declare a template reference variable, precede an identifier with a hash (or pound) character (#).
下面的例子使用了局部模板变量,在一个超简单的模板中实现按键反馈功能。
The following example uses a template reference variable
to implement a keystroke loopback in a simple template.
The template reference variable named box, declared on the <input> element,
refers to the <input> element itself.
The code uses the box variable to get the input element's value and display it
with interpolation between <p> tags.
这个模板完全是完全自包含的。它没有绑定到组件,组件也没做任何事情。
The template is completely self contained. It doesn't bind to the component,
and the component does nothing.
在输入框中输入,就会看到每次按键时,显示也随之更新了。
Type something in the input box, and watch the display update with each keystroke.
除非你绑定一个事件,否则这将完全无法工作。
This won't work at all unless you bind to an event.
只有在应用做了些异步事件(如击键),Angular 才更新绑定(并最终影响到屏幕)。
Angular updates the bindings (and therefore the screen)
only if the app does something in response to asynchronous events, such as keystrokes.
This example code binds the keyup event
to the number 0, the shortest template statement possible.
While the statement does nothing useful,
it satisfies Angular's requirement so that Angular will update the screen.
It's easier to get to the input box with the template reference
variable than to go through the $event object. Here's a rewrite of the previous
keyup example that uses a template reference variable to get the user's input.
A nice aspect of this approach is that the component gets clean data values from the view.
It no longer requires knowledge of the $event and its structure.
The (keyup) event handler hears every keystroke.
Sometimes only the Enter key matters, because it signals that the user has finished typing.
One way to reduce the noise would be to examine every $event.keyCode and take action only when the key is Enter.
In the previous example, the current state of the input box
is lost if the user mouses away and clicks elsewhere on the page
without first pressing Enter.
The component's value property is updated only when the user presses Enter.
下面通过同时监听输入框的回车键和失去焦点事件来修正这个问题。
To fix this issue, listen to both the Enter key and the blur event.
Now, put it all together in a micro-app
that can display a list of heroes and add new heroes to the list.
The user can add a hero by typing the hero's name in the input box and
clicking Add.
Use template variables to refer to elements —
The newHero template variable refers to the <input> element.
You can reference newHero from any sibling or child of the <input> element.
传递数值,而非元素 —
获取输入框的值并将它传递给组件的addHero,而不要传递newHero。
Pass values, not elements —
Instead of passing the newHero into the component's addHero method,
get the input box value and pass that to addHero.
Keep template statements simple —
The (blur) event is bound to two JavaScript statements.
The first statement calls addHero. The second statement, newHero.value='',
clears the input box after a new hero is added to the list.
These techniques are useful for small-scale demonstrations, but they
quickly become verbose and clumsy when handling large amounts of user input.
Two-way data binding is a more elegant and compact way to move
values between data entry fields and model properties.
The next page, Forms, explains how to write
two-way bindings with NgModel.