用戶的動作如:點擊鏈接、按下按鈕或者輸入文字,都會產生 DOM 事件务唐。本章解釋如何使用 Angular 事件綁定語法把這些事件綁定到事件處理器。
綁定到用戶輸入事件
我們可以使用 Angular 事件綁定機制來響應任意 DOM 事件劝篷。許多 DOM 事件是由用戶輸入觸發(fā)的。綁定這些事件提供了一種獲取用戶輸入的方式民宿。
要綁定 DOM 事件娇妓,只要把 DOM 事件的名字包裹在圓括號中,然后用放在引號中的模板語句對它賦值就可以了活鹰。下面的例子展示了一個事件綁定哈恰,它實現(xiàn)了一個點擊事件處理器:
<button (click)="onClickMe()">Click me!</button>
等號左邊的(click)
表示把按鈕的點擊事件作為綁定目標。等號右邊引號中的文本是模板語句志群,通過調用組件的onClickMe()
方法來響應這個點擊事件着绷。
寫綁定時,必須要知道模板語句的執(zhí)行上下文赖舟。出現(xiàn)在模板語句中的每個標識符都屬于特定的上下文對象蓬戚。這個對象通常都是控制此模板的 Angular 組件。上面的例子中只顯示了一行 HTML宾抓,那段 HTML 片段屬于一個更大的組件:
// lib/src/click_me_component.dart (component)
@Component(
selector: 'click-me',
template: '''
<button (click)="onClickMe()">Click me!</button>
{{clickMessage}}
''',
)
class ClickMeComponent {
String clickMessage = '';
void onClickMe() => clickMessage = 'You are my hero!';
}
當用戶點擊按鈕時子漩,Angular 調用ClickMeComponent
的onClickMe()
方法豫喧。
從 $event 對象獲取用戶輸入
DOM 事件可以攜帶可能對組件有用的信息。這一部分將展示如何綁定輸入框的 keyup
事件幢泼,在每個敲擊鍵盤時獲取用戶輸入紧显。
下面的代碼監(jiān)聽 keyup
事件,并將整個事件載荷 ($event)
傳遞給組件的事件處理器缕棵。
// lib/src/keyup_components.dart (v1 template)
template: '''
<input (keyup)="onKey(\$event)"> // 注意前面的 \孵班,因為這是在dart文件中,如果是html則不需要
<p>{{values}}</p>
'''
模板在 Dart 文件中招驴,需要在
$
前面加\
篙程。如果模板是外部的 HTML 文件,則直接使用$event
别厘。
當用戶按下并釋放一個按鍵時虱饿,觸發(fā)keyup
事件,Angular 在$event
變量提供一個相應的 DOM 事件對象触趴,上面的代碼將它作為參數(shù)傳遞給onKey()
方法氮发。
class KeyUp1Component {
String values = '';
void onKey(dynamic event) {
values += event.target.value + ' | ';
}
}
$event
對象的屬性取決于 DOM 事件的類型。例如冗懦,鼠標事件和輸入框編輯事件包含不同的信息爽冕。
所有標準 DOM 事件對象都有一個target
屬性,引用觸發(fā)該事件的元素披蕉。在本例中颈畸,target
是 <input> 元素,event.target.value
返回該元素的當前內容没讲。
每次調用后承冰,onKey()
方法把輸入框的值和后面跟著的分隔符 (|
) 添加到組件的values
屬性。模板使用 Angular 的插值表達式{{...}}
來顯示values
屬性食零。
假設用戶輸入字母“abc”困乒,然后用退格鍵一個一個刪除它們。 用戶界面將顯示:
a | ab | abc | ab | a | |
或者贰谣,你可以用
event.key
替代event.target.value
娜搂,在這個例中,同樣的用戶輸入產生結果如下:
a | b | c | Backspace | Backspace | Backspace |
event 的類型
上面的例子聲明的onKey() event
參數(shù)是dynamic
吱抚。盡管這樣簡化了代碼百宇,但使用更具體的類型可以揭露實事件對象的屬性并防止愚蠢的錯誤。
下面的例子秘豹,使用類型重寫了方法:
// lib/src/keyup_components.dart (v1 class)
class KeyUp1Component {
String values = '';
void onKey(KeyboardEvent event) {
InputElement el = event.target;
values += '${el.value} | ';
}
}
現(xiàn)在event
聲明為KeyboardEvent
類型携御,event.target
聲明為一個擁有 value
屬性的InputElement
類型。使用這些類型,onKey()
方法更加清晰的表達了它期望從模板得到什么啄刹,以及它是如何解析事件的涮坐。
傳入 $event 是不可靠的做法
類型化事件對象通過傳遞整個 DOM 事件到方法中,暴露了一個重要問題:組件和模板細節(jié)緊密的聯(lián)系起來誓军。組件不使用 web APIs袱讹,它就不能夠提取信息。這就違反了模板(用戶看到的)和組件(應用如何處理用戶數(shù)據(jù))之間關注點分離的原則昵时。
下面的部分將介紹如何用模板引用變量來解決這個問題捷雕。
從一個模板引用變量中獲得用戶輸入
還有另一種方法獲取用戶數(shù)據(jù):Angular 模板引用變量提供了從模塊中直接訪問元素的能力。在標識符前加上井號 (#) 就能聲明一個模板引用變量壹甥。
下面的例子使用了局部模板變量救巷,在一個超簡單的模板中實現(xiàn)按鍵反饋功能。
@Component(
selector: 'loop-back',
template: '''
<input #box (keyup)="0">
<p>{{box.value}}</p>
''',
)
class LoopBackComponent {}
在 <input>
元素上聲明的名為box
的模板引用變量句柠,引用<input>
元素本身征绸。代碼使用box
變量來獲得輸入元素的value
值,并通過插值表達式把它顯示在<p>
標簽中俄占。
這個模板是完全自包含的。它沒有綁定到組件淆衷,組件也沒做任何事情缸榄。
在輸入框中輸入,就會看到每次按鍵時祝拯,顯示也隨之更新了甚带。
除非你綁定一個事件,否則這將完全無法工作佳头。
只有在應用做了些異步事件(如按鍵)鹰贵,Angular 才更新綁定(并最終影響到屏幕)。本例代碼將keyup
事件綁定到了數(shù)字 0康嘉,這可能是最短的模板語句了碉输。雖然這個語句不做什么,但它滿足 Angular 的要求亭珍,所以 Angular 將更新屏幕敷钾。
從模板引用變量獲得輸入框比通過 $event 對象更加簡單。下面的代碼使用模板引用變量來獲得用戶輸入肄梨,重寫了之前keyup
示例阻荒。
lib/src/keyup_components.dart (v2)
@Component(
selector: 'key-up2',
template: '''
<input #box (keyup)="onKey(box.value)">
<p>{{values}}</p>
''',
)
class KeyUp2Component {
String values = '';
void onKey(value) => values += '$value | ';
}
這個方法最漂亮的一點是:組件代碼從視圖中獲得了干凈的數(shù)據(jù)值。它不再需要$event
的信息及其結構了众羡。
按鍵事件過濾(使用key.enter
)
(keyup)
事件處理器監(jiān)聽每一次按鍵侨赡。有時只在意回車鍵,因為它標志著用戶結束輸入。解決這個問題的一種方法是檢查每個$event.keyCode
羊壹,只有鍵值是回車鍵時才采取行動蓖宦。
更簡單的方法是:綁定到 Angular 的 keyup.enter
模擬事件。然后舶掖,只有當用戶敲回車鍵時球昨,Angular 才會調用事件處理器。
// lib/src/keyup_components.dart (v3)
@Component(
selector: 'key-up3',
template: '''
<input #box (keyup.enter)="values=box.value">
<p>{{values}}</p>
''',
)
class KeyUp3Component {
String values = '';
}
下面展示了它是如何工作的眨攘。
失去焦點事件
在前面的例中主慰,如果用戶沒有先按回車鍵,而是移開了鼠標鲫售,點擊了頁面中其它地方共螺,輸入框的當前值就會丟失。只有當用戶按下了回車鍵后情竹,組件的values
屬性才能更新藐不。
讓我們通過同時監(jiān)聽輸入框的回車鍵和失去焦點事件來修復這個問題。
// lib/src/keyup_components.dart (v4)
@Component(
selector: 'key-up4',
template: '''
<input #box
(keyup.enter)="values=box.value"
(blur)="values=box.value">
<p>{{values}}</p>
''',
)
class KeyUp4Component {
String values = '';
}
把它們放在一起
上一章介紹了如何顯示數(shù)據(jù)秦效。本章展示了事件綁定方法雏蛮。
現(xiàn)在,在一個微型應用中一起使用它們阱州,應用能顯示一個英雄列表挑秉,并把新的英雄加到列表中。用戶可以通過輸入英雄名和點擊添加按鈕來添加英雄苔货。
下面就是“Little Tour of Heroes”組件犀概。
// lib/src/little_tour_component.dart (little-tour)
@Component(
selector: 'little-tour',
template: '''
<input #newHero
(keyup.enter)="addHero(newHero.value)"
(blur)="addHero(newHero.value); newHero.value='' ">
<button (click)="addHero(newHero.value)">Add</button>
<ul><li *ngFor="let hero of heroes">{{hero}}</li></ul>
''',
directives: [coreDirectives],
)
class LittleTourComponent {
List<String> heroes = ['Windstorm', 'Bombasto', 'Magneta', 'Tornado'];
void addHero(String newHero) {
if (newHero == null || newHero.isEmpty) return;
heroes.add(newHero);
}
}
注意
-
使用模板變量來引用元素。
newHero
模板變量引用了<input>
元素夜惭。你可以在<input>
的任何兄弟或子級元素中引用newHero
姻灶。 -
傳遞數(shù)值,而非元素诈茧。獲取輸入框的值并將它傳遞給組件的
addHero()
方法产喉,而不是傳遞newHero
。 -
保持模板語句簡單敢会。
(blur)
事件綁定了兩個語句镊叁。第一句調用addHero()
方法。第二句newHero.value=''
在添加新英雄到列表中后清空輸入框走触。
總結
你已經(jīng)看過了響應用戶輸入和操作的基礎原理晦譬。
這些方法對小規(guī)模演示很實用,但是在處理大量用戶輸入時互广,很容易變得累贅和笨拙敛腌。要在數(shù)據(jù)錄入字段和模型屬性之間傳遞數(shù)據(jù)卧土,雙向數(shù)據(jù)綁定是更加優(yōu)雅和簡潔的方式。下一章Forms
解釋了如何用NgModel
來進行雙向綁定像樊。
下一步