[Angular] HostBinding&HostListener

介紹

今天要來講講HostBinding和HostListener,原本官網還能找到文章,但最近才發現他已經被殺了…
但還是要來說一下,誰叫我自己挖洞給自己跳了o(〒﹏〒)o

目標

來做一個highlight的功能,顏色可以自定,當游標進入時變色,離開則回復
如果是寫jquery,你會怎麼做? 使用on監聽事件

1
2
3
4
5
6
7
let color = 'red';
$(document).on('mouseenter', '.class', function(){
$(this).style('background-color', color);
});
$(document).on('mouseleave', '.class', function(){
$(this).style('background-color', '');
});

但我們現在是寫angular,當然要想辦法變成directive
並且能做到像jquery的事情一樣

建立directive

首先,先建立一個directive,並且傳入顏色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { Directive, ElementRef, Input, Component } from '@angular/core';
@Directive({
selector: '[highlight]'
})
export class HighlightDirective {
private _defaultColor: string = 'red';

constructor(private el:ElementRef) {
}

@Input('color') color: string;
}

@Component({
selector: 'app-root',
template: `
<div class="highlight">
Highlight Me!!
</div>
`
})

export class AppComponent {
}

HostListener

接著開始監聽事件,但是要怎麼做到,從一個element的屬性去監聽他的行為
這時候我們需要用到HostListener,從字面其實可以猜的出來,他就是用來監聽來自element(host)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { Directive, ElementRef, Input, HostListener } from '@angular/core';

@Directive({
selector: '.highlight'
})
export class HighlightDirective {
private _defaultColor: string = 'red';


constructor(private el:ElementRef) {
}

@Input('color') color: string;

@HostListener('mouseenter') onEnter() {
this.el.nativeElement.style.backgroundColor = this.color || this._defaultColor;
}

@HostListener('mouseleave') onLeave() {
this.el.nativeElement.style.backgroundColor = null;
}
}

補充說明:
beta版本時(遙遠的古代…),是在directive那邊的描述中加上一個host的來使用

1
2
3
4
5
6
@Directive({
selector: '[highlight]',
host: {
'(mouseenter)': 'onMouseEnter()',
}
})

HostBinding

可是上面那樣寫還是不夠漂亮,還要在事件內去控制,為什麼不能用model去控制呢
因此angular有提供HostBinding的功能,讓你可以直接用model來影響element屬性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { Directive, ElementRef, Input, HostListener, HostBinding } from '@angular/core';

@Directive({
selector: '.highlight'
})
export class HighlightDirective {
private _defaultColor: string = 'red';

constructor(private el:ElementRef) {
}

@Input('color') color: string;

@HostBinding('style.backgroundColor') bgColor: string;
@HostListener('mouseenter') onEnter() {
this.bgColor = this.color || this._defaultColor;
}

@HostListener('mouseleave') onLeave() {
this.bgColor = null;
}
}

哇屋~這樣的code看起來是不是更為清楚,而且好操作

這個範例是變更style的屬性,那如果要變更class的話,可以用下面的方法
使用boolean來控制class是否被引用

1
@HostBinding('class.draging') isDraging: boolean = false;

來點進階的內容,input和hostBinding合在一起有沒有搞頭
答案是,絕對有搞頭

1
2
3
@Input('color')
@HostBinding('style.backgroundColor')
bgColor: string;

外面的element用color這個屬性來傳入顏色,放入到bgColor這個變數,然後來影響backgroundColor
這樣可以讓變數減少,並且整合在一起,閱讀起來也很清楚

加上Output

上面的應用其實非常的簡單,但通常不會有這麼簡單的應用,那接著我們來加點料吧
在進入時,我們需要拋出event,讓component呈現計數滑動次數吧!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import { Directive, ElementRef, Input, HostListener, HostBinding, Output, EventEmitter } from '@angular/core';

@Directive({
selector: '.highlight'
})
export class HighlightDirective {
private _defaultColor: string = 'red';

constructor(private el:ElementRef) {
}

@Input('color') color: string;
@Output() onColorChange = new EventEmitter;

@HostBinding('style.backgroundColor') bgColor: string;
@HostListener('mouseenter') onEnter() {
this.bgColor = this.color || this._defaultColor;
this.onColorChange.emit();
}

@HostListener('mouseleave') onLeave() {
this.bgColor = null;
}
}

@Component({
selector: 'app-root',
template: `
<div class="highlight" (onColorChange)="onColorChange()">
Highlight Me!!
</div>
<div>
{{enteryCount}}
</div>
`
})

export class AppComponent {
enteryCount = 0;
onColorChange(){
this.enteryCount++;
}
}

Reference

https://ng2.codecraft.tv/custom-directives/hostlistener-and-hostbinding/
https://angular.io/docs/ts/latest/guide/cheatsheet.html
https://angular.io/docs/ts/latest/guide/attribute-directives.html