[從 0 開始的 Angular 生活]No.15 資料繫結的四種方法 - 事件繫結

前言

在 Angular 內,第三種資料繫結的方法是事件繫結 ( Event Binding ),具體來說怎麼實踐,讓我們繼續看下去。

事件繫結 ( Event Binding )

這是我們目前網頁上的一張 Q 版的 chrome LOGO ,假設我們要在這張圖片加上 Click 點擊事件,點下去之後網站標題會跟著改變。

事件繫結語法 (一)

在事件中間加上 「-」,代表這是 Angular 的語法,並且在雙引號內放入 function ,但是在 Angular 內並沒有 function 只有類別,而類別內只有屬性以及方法

template

1
<img on-click="changeTitle()" [title]="title" [src]="imgUrl" [attr.data-title]="title" class="pull-left logo">

讓我們宣告一個方法叫做 changeTitle

component

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'firstAngular';
link = 'http://www.google.com';
imgUrl = '/assets/images/logo.png';
changeTitle() {
this.title = 'changeTitle';
}
}

事件繫結語法 (二)

除了上述的作法外,也可以使用這種方式添加事件繫結。

template

1
<img (click)="changeTitle()" [title]="title" [src]="imgUrl" [attr.data-title]="title" class="pull-left logo">

這樣的方式跟上一篇提到的屬性繫結是不是有點相似呢?

差別在於屬性繫結是使用中括號 [] 表示,而事件繫結是使用小括號 () 表示。

而大部分的 Angular 開發者都是使用第二種方法來進行事件綁定,較少使用第一種方法。

接著運行開發伺服器,測試看看結果。

點擊 LOGO 後

標題的確被更新了,但這是怎麼辦到的呢?

事件繫結的背後

我們在 LOGO 上執行了 Click 動作,然後註冊 Angular 的事件繫結,而這個事件繫結到了 changeTitle 方法,因此當有人點了 LOGO 時,就會跳到 AppComponent 內去執行 changeTitle 方法。

而這個方法會藉由執行 this.title = 'changeTitle'; 來變更 class 內的 title 屬性,又因為先前我們對網站標題使用了內嵌繫結,所以當 class 內的 title 屬性有異動時, Angular 就會管理頁面 DOM 的狀態,也就是所有頁面中有繫結 title 屬性的地方一起改變。

事件繫結 - 使用 $event 參數

當撰寫事件繫結時必須要傳入一個方法,預設可以不用傳入任何參數,但是在這裡確實可以傳入一個很特別的參數 $event ,讓我們觀察看看。

這個 $event 可以幫助我們取得事件的詳細資訊

template

1
<img (click)="changeTitle($event)" [title]="title" [src]="imgUrl" [attr.data-title]="title" class="pull-left logo">

component

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'firstAngular';
link = 'http://www.google.com';
imgUrl = '/assets/images/logo.png';
changeTitle($event) {
this.title = 'changeTitle';
console.log($event);
}
}

接著運行開發伺服器,按下 F12 開啟開發者工具並點擊 LOGO 圖案。

可以看到跑出了很多東西,而這個 MouseEvent 其實就是 DOM 的 MouseEvent ,因此這一次觸發的滑鼠事件內可以找到相當多的屬性。

$event 參數內 - target

target 屬性代表的是剛剛點下去的那個 DOM 物件,例如說剛剛我們是點擊 img 觸發的,也就是說它的 target 屬性會是:

img 標籤的 DOM

$event 參數內 - altkey

altkey 屬性代表的是點擊時有沒有按下 「alt」 這個按鍵,因此我們可以替剛剛那個範例加上一個新的需求,必須要按下 「alt」 這個按鍵才可以更改標題。

component

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'firstAngular';
link = 'http://www.google.com';
imgUrl = '/assets/images/logo.png';
changeTitle($event) {
if ($event.altKey) {
this.title = 'changeTitle';
}
console.log($event);
}
}

我在這邊踩到了一的雷,那就是 altKey 的 K 是大寫,因此這部分要特別注意英文的大小寫部分。

搞定!運行開發伺服器測試看看

但是這個部分可以有更好的寫法,那就是使用具有型別的 $event 參數

事件繫結 - 使用具有型別 $event 參數

在上一個範例裡,因為英文的大小寫導致程式沒有按我們預期的跑,但我們現在是使用 TypeScript 進行開發,所以我們可以利用 TypeScript 帶來的好處,利用型別來標註參數的型別,具體來說我們可以這麼做:

  • 由剛才範例可知 $event 的內容其實是 MouseEvent
    • 也就是說傳入方法的參數其實是 MouseEvent 的型別

因此可以在 Component 內這麼寫:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'firstAngular';
link = 'http://www.google.com';
imgUrl = '/assets/images/logo.png';
changeTitle($event: MouseEvent) {
if ($event.altKey) {
this.title = 'changeTitle';
}
console.log($event);
}
}

接著神奇的事情發生了,當我們輸入 $event 並按下 . 時,VS Code 會列出所有 MouseEvent 內所有可以選擇的屬性。

巧妙的利用型別重構

我們知道可以在事件繫結中傳入 $event 參數,但其實這個部分可以更進一步的改寫,並且結合剛才的提到的型別,例如:

template

1
<img (click)="changeTitle($event.altKey)" [title]="title" [src]="imgUrl" [attr.data-title]="title" class="pull-left logo">

可以直接在這個地方就傳入 $event.altKey

component

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'firstAngular';
link = 'http://www.google.com';
imgUrl = '/assets/images/logo.png';
changeTitle(altKey: boolean) {
if (altKey) {
this.title = 'changeTitle';
}
}
}

然而因為 $event.altKey 的值是 true 或 false ,因此型別是布林。

接著可以再次確認運作是否正常。

小結

在事件繫結中,有些同樣的事情會有不同的方法可以實作,至於要用哪種方式撰寫就見仁見智了。對我來說,怎麼樣的寫法是易懂又容易維護的,那就是值得學習的好方法。

0%