在前幾天中有介紹了 Angular 中內建的一些 attribute directive,但是在實際開發專案時可能會遇到內建 attribute directive 無法處理的問題,這時候就需要建立客製化 attribute directive,本章就會介紹如何建立屬於自己的 attribute directive。
來跟著 Angular 的官方文檔做一個練習,將會建立一個客製化的 attribute directive,將一個宿主 element 的背景顏色設置為黃色的 directive。
首先先使用 Angular CLI 建立一個 directive
ng generate directive highlight
ng g d highlight
使用這個 CLI 指令可以自動建立一個名為 highlight.directive.ts 和 highlight.directive.spec.ts 的檔案,並且會在被加入到 app.module.ts 的 declares
,所以如果不是用 CLI 建立 directive file 時,要記得手動將它加入到 declares 裡面喔!
在 highlight.directive.ts 中從 @angular/core
中導入 ElementRef
import { Directive, ElementRef } from '@angular/core';
@Directive({
selector: '[appHighlight]'
})
export class HighlightDirective {
constructor(el: ElementRef) { // (1)
el.nativeElement.style.backgroundColor = 'yellow'; // (2)
}
}
nativeElement
property 授與對宿主 DOM element 的直接訪問權限,並將他的 style 改變為黃色在 app.component.html 中添加一個 element 並將剛剛客製化的 directive 加在上面
<!-- app.component.html -->
<p appHighlight>Highlight me!</p>
Angular 會將 HighlightDirective 給實例化並將對 <p>
element 的 reference injects 到 highlight.directive.ts 的 constructor 中,讓他可以對這個元素的 style 進行更改。
除了改變 element 之外也可以在客製化的 directive 中檢測用戶在畫面中的事件(鼠標移入或移出)並對事件進行不同的響應。
舉個例子,保持上面的例子只是將畫面上的 <p>
element 綁定一個 hover 事件,當鼠標移到上面時將他背景顏色改為黃色
從 @angular/core
中導入 HostListener
import { Directive, ElementRef, HostListener } from '@angular/core';
更改 highlight.directive.ts 中的 method 用於響應事件
import { Directive, ElementRef, HostListener } from '@angular/core';
@Directive({
selector: '[appHighlight]'
})
export class HighlightDirective {
constructor(private el: ElementRef) {}
@HostListener('mouseenter') onMouseEnter() { // (1)
this.highlight('yellow');
}
@HostListener('mouseleave') onMouseLeave() { // (2)
this.highlight('');
}
private highlight(color: string) { // (3)
this.el.nativeElement.style.backgroundColor = color;
}
}
在畫面中可以看,當我們的鼠標移動到 <p>
element 上面時會觸發 highlight.directive.ts 中的 method 將他的背景顏色改為黃色。
除了將你要更改的內容寫死在 directive 之外(上面例子是寫死 hover 時背景變黃色),你也可以透過傳遞參數的方式,動態的傳遞你所期望改變的內容,一樣拿上面的例子來延伸吧
首先先改變 highlight.directive.ts 的內容
import { Directive, ElementRef, HostListener, Input } from '@angular/core'; // (1)
@Directive({
selector: '[appHighlight]'
})
export class HighlightDirective {
@Input() appHighlight = ''; // (2)
constructor(private el: ElementRef) {}
@HostListener('mouseenter') onMouseEnter() {
this.highlight(this.appHighlight); // (3)
}
@HostListener('mouseleave') onMouseLeave() {
this.highlight('');
}
private highlight(color: string) {
this.el.nativeElement.style.backgroundColor = color;
}
}
@angular/core
中引入 Input更改 app.component.html 的內容,將顏色傳遞給 HighlightDirective
<!-- app.component.html -->
<p [appHighlight]="'red'">Highlight me!</p>
可以看到畫面中,當鼠標移動到 element 時從黃色變為我們傳遞給 directive 的紅色了。
除了可以傳遞參數給 directive 之外還可以對他設定一個預設值,以上面例子來說,我們可以設定一個預設值,直到使用者改變顏色後才變為指定的顏色
更改 highlight.directive.ts 中的內容
import { Directive, ElementRef, HostListener, Input } from '@angular/core';
@Directive({
selector: '[appHighlight]'
})
export class HighlightDirective {
@Input() appHighlight = '';
@Input() defaultColor = ''; // (1)
constructor(private el: ElementRef) {}
@HostListener('mouseenter') onMouseEnter() {
this.highlight(this.appHighlight || this.defaultColor || 'red');
}
@HostListener('mouseleave') onMouseLeave() {
this.highlight('');
}
private highlight(color: string) {
this.el.nativeElement.style.backgroundColor = color;
}
}
在 app.component.ts 中添加一個 property 與 method
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
color = ''; // (1)
onClick (color: string) { // (2)
this.color = color;
}
}
在 app.component.html 中新增三個 <button>
並將 directive 加上預設值
<!-- app.component.html -->
<button (click)="onClick('green')">Green</button>
<button (click)="onClick('yellow')">Yellow</button>
<button (click)="onClick('cyan')">Cyan</button>
<p [appHighlight]="color" defaultColor="violet">Highlight me too!</p>
在畫面中可以看到,當我們沒有點擊畫面中的 <button>
時我們的鼠標移動到 element 時顯示的顏色是預設的顏色,而當點擊了其中一個按鈕後就換更新為指定的顏色。
本章介紹了如何建立與使用客製化的 directive,可以透過使用 ElementRef 的 nativeElement
property 授與對宿主 DOM element 的直接訪問權限,可以使用 HostListener 用來處理畫面中使用者的行為,也可以使用之前提到的 @Input() 用於傳遞參數進到 directive 中,這個客製化的 directive 對於要處理特別的情況時非常好用。
下一章將介紹如何創建客製化的 structural directive並介紹 directive 使如何工作的、 Angular 如解釋速記以及如何添加 template 的保護 property 用於捕獲 template 的錯誤,那我們就明天見囉!