用戶輸入

版本:Angular 5.0.0-alpha

用戶的動作如:點擊鏈接、按下按鈕或者輸入文字,都會產生 DOM 事件。本章解釋如何使用 Angular 事件綁定語法把這些事件綁定到事件處理器。

運行在線例子(查看源碼)。

綁定到用戶輸入事件

我們可以使用 Angular 事件綁定機制來響應任意 DOM 事件。許多 DOM 事件是由用戶輸入觸發的。綁定這些事件提供了一種獲取用戶輸入的方式。

要綁定 DOM 事件,只要把 DOM 事件的名字包裹在圓括號中,然后用放在引號中的模板語句對它賦值就可以了。下面的例子展示了一個事件綁定,它實現了一個點擊事件處理器:

<button (click)="onClickMe()">Click me!</button>

等號左邊的(click)表示把按鈕的點擊事件作為綁定目標。等號右邊引號中的文本是模板語句,通過調用組件的onClickMe()方法來響應這個點擊事件。

寫綁定時,必須要知道模板語句的執行上下文。出現在模板語句中的每個標識符都屬于特定的上下文對象。這個對象通常都是控制此模板的 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 調用ClickMeComponentonClickMe()方法。

從 $event 對象獲取用戶輸入

DOM 事件可以攜帶可能對組件有用的信息。這一部分將展示如何綁定輸入框的 keyup 事件,在每個敲擊鍵盤時獲取用戶輸入。

下面的代碼監聽 keyup 事件,并將整個事件載荷 ($event) 傳遞給組件的事件處理器。

// lib/src/keyup_components.dart (v1 template)

template: '''
  <input (keyup)="onKey(\$event)"> // 注意前面的 \,因為這是在dart文件中,如果是html則不需要
  <p>{{values}}</p>
'''

模板在 Dart 文件中,需要在$前面加\。如果模板是外部的 HTML 文件,則直接使用$event

當用戶按下并釋放一個按鍵時,觸發keyup事件,Angular 在$event變量提供一個相應的 DOM 事件對象,上面的代碼將它作為參數傳遞給onKey()方法。

class KeyUp1Component {
  String values = '';

  void onKey(dynamic event) {
    values += event.target.value + ' | ';
  }
}

$event對象的屬性取決于 DOM 事件的類型。例如,鼠標事件和輸入框編輯事件包含不同的信息。

所有標準 DOM 事件對象都有一個target屬性,引用觸發該事件的元素。在本例中,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參數是dynamic。盡管這樣簡化了代碼,但使用更具體的類型可以揭露實事件對象的屬性并防止愚蠢的錯誤。

下面的例子,使用類型重寫了方法:

// lib/src/keyup_components.dart (v1 class)

class KeyUp1Component {
  String values = '';

  void onKey(KeyboardEvent event) {
    InputElement el = event.target;
    values += '${el.value}  | ';
  }
}

現在event聲明為KeyboardEvent類型,event.target聲明為一個擁有 value屬性的InputElement類型。使用這些類型,onKey()方法更加清晰的表達了它期望從模板得到什么,以及它是如何解析事件的。

傳入 $event 是不可靠的做法

類型化事件對象通過傳遞整個 DOM 事件到方法中,暴露了一個重要問題:組件和模板細節緊密的聯系起來。組件不使用 web APIs,它就不能夠提取信息。這就違反了模板(用戶看到的)和組件(應用如何處理用戶數據)之間關注點分離的原則。

下面的部分將介紹如何用模板引用變量來解決這個問題。

從一個模板引用變量中獲得用戶輸入

還有另一種方法獲取用戶數據:Angular 模板引用變量提供了從模塊中直接訪問元素的能力。在標識符前加上井號 (#) 就能聲明一個模板引用變量。

下面的例子使用了局部模板變量,在一個超簡單的模板中實現按鍵反饋功能。

@Component(
  selector: 'loop-back',
  template: '''
    <input #box (keyup)="0">
    <p>{{box.value}}</p>
  ''',
)
class LoopBackComponent {}

<input> 元素上聲明的名為box的模板引用變量,引用<input>元素本身。代碼使用box變量來獲得輸入元素的value值,并通過插值表達式把它顯示在<p>標簽中。

這個模板是完全自包含的。它沒有綁定到組件,組件也沒做任何事情。

在輸入框中輸入,就會看到每次按鍵時,顯示也隨之更新了。

除非你綁定一個事件,否則這將完全無法工作。
只有在應用做了些異步事件(如按鍵),Angular 才更新綁定(并最終影響到屏幕)。本例代碼將keyup事件綁定到了數字 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 | ';
}

這個方法最漂亮的一點是:組件代碼從視圖中獲得了干凈的數據值。它不再需要$event的信息及其結構了。

按鍵事件過濾(使用key.enter

(keyup)事件處理器監聽每一次按鍵。有時只在意回車鍵,因為它標志著用戶結束輸入。解決這個問題的一種方法是檢查每個$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屬性才能更新。

讓我們通過同時監聽輸入框的回車鍵和失去焦點事件來修復這個問題。

// 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 = '';
}

把它們放在一起

上一章介紹了如何顯示數據。本章展示了事件綁定方法。

現在,在一個微型應用中一起使用它們,應用能顯示一個英雄列表,并把新的英雄加到列表中。用戶可以通過輸入英雄名和點擊添加按鈕來添加英雄。

下面就是“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
  • 傳遞數值,而非元素。獲取輸入框的值并將它傳遞給組件的 addHero()方法,而不是傳遞 newHero
  • 保持模板語句簡單(blur)事件綁定了兩個語句。第一句調用addHero()方法。第二句newHero.value=''在添加新英雄到列表中后清空輸入框。

總結

你已經看過了響應用戶輸入和操作的基礎原理。

這些方法對小規模演示很實用,但是在處理大量用戶輸入時,很容易變得累贅和笨拙。要在數據錄入字段和模型屬性之間傳遞數據,雙向數據綁定是更加優雅和簡潔的方式。下一章Forms解釋了如何用NgModel來進行雙向綁定。

下一步

表單

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 用戶輸入觸發 DOM 事件。我們通過事件綁定來監聽它們,把更新過的數據導入回我們的組件和 model 。(1)綁定...
    趙然228閱讀 3,402評論 0 2
  • 學習資料來自 Angular.cn 與 Angular.io。 模板語法 在線例子 在 Angular 中,組件扮...
    小鐳Ra閱讀 3,787評論 0 3
  • 最開始是看著mv聽這首歌的感覺風格很清新童心但是看了歌詞卻發現不是這樣的 情感中的困擾人生中的徘徊一年一年長大卻什...
    凜冽閱讀 362評論 0 1
  • 明天就要走了,今天晚上有點睡不著,真的舍不得爸媽,一個月竟不知不覺就這樣過去了,哎,不該王者的,打了幾局,本來是要...
    孫少的日記閱讀 205評論 0 0
  • 這里有一座高塔,是所有的人都必須去攀登的。它至多不過有一百級。這座高塔是中空的,如果一個人一旦達到它的頂端,就會掉...
    夜雨狂歌如夢閱讀 616評論 0 0