angular structural directives
前言:
使用過angular,就一定知道在寫html的時候會用到的*ngIf、*ngFor..這些angular提供可以改變結構的指令,在製作html網頁的時候幫我們省了不少工,也讓我們的html程式碼變得更容易閱讀。這些方便的方法,並不只內建的*ng開頭的指令,也可以自訂自己的指令,幫助我們更容易完成。
指令作法:
現在我們來介紹自訂指令的作法,我們打算自製一個類似*ngFor這樣的指令,在一個新專案中做模擬使用。
1、建立我們的新指令所需的類別。
import { Directive } from '@angular/core';
@Directive({
selector: '[appNgLoop]'
})
export class NgLoopDirective {
constructor() { }
}
* selector表示的就是待會我們的指令名稱。
2、直接去app.component.html中加入一個顯示的部分。
<div appNgLoop>Hello</div>
雖然我們將指令放了進去,但因為我們沒給他任何的功能,所以她沒有任何反應,如果我們加上星號"*",他更會直接告訴我們她不認識這個template屬性。
3、現在我們把用於指令所需的參數帶入我們的類別。
constructor(private container: ViewContainerRef,
private template: TemplateRef<any>,
) { }
* ViewContainerRef是一個特殊的容器,可以在裡面放一個或多個的畫面。
* TemplateRef<any>就是我們宿主元素中寫的模板資料,除了用*開頭指令,<ng-template></ng-template>之間的模板也可以
4、現在我們重編譯啟動app,我們會發現一個錯誤,template沒有被定義的錯誤。所以我們現在要來修正這個錯誤。
ngOnInit(): void {
this.container.createEmbeddedView(this.template);
}
5、如果現在看一下我們的app,我們可以看到以foo為內容的div元素正在顯示。我們剛剛創建了一條指令,該指令將我們提供給它的元素作為模板呈現。現在我們繼續把它做成我們想要的樣子。
6、首先我們將類別繼承一個父類別,並加入指令的輸入功能,因為待會要做類似*ngFor的效果,所以當然是一個Array。
export class NgLoopDirective implements OnChanges {
@Input() appNgLoopOf: Array<any>;
constructor(private container: ViewContainerRef,
private template: TemplateRef<any>,
) { }
}
* appNgLoopOf是我們待會對我們自創的指令輸入的資訊。
7、加入繼承之後,我們會發現多了紅字,沒關係,待會我們會加入一個預設的方法,現在我們先配合修改畫面,如下。
<div *appNgLoop="numbers">foo</div>
8、接著我們來處理剛剛的紅字,加入一個新的方法。
ngOnChanges() {
for (const input of this.appNgLoop) {
this.container.createEmbeddedView(this.template);
}
}
9、現在,在我們的指令中,我們依靠OnChanges在每次輸入更改時呈現視圖。我們遍歷numbers的時候,為每個項目創建一個嵌入式的view。
10、接下來我們嘗試在模板中使用輸入值。首先我們更改html如下。
<div *appNgLoop="let nr of numbers; index as i">
{{ nr }} - Foo
Index: {{ i }}
</div>
11、接著更改我們在ngOnChanges的處理方法。
ngOnChanges() {
this.container.clear();
for (const input of this.appNgLoopOf) {
this.container.createEmbeddedView(this.template, {
$implicit: input,
index: this.appNgLoopOf.indexOf(input),
});
}
}
12、在app重新整理之後,我們看到。
小結:
上述方式並不困難,但對於開發時相當有幫助,可以讓寫出來的程式碼更簡單也更容易閱讀,相信大家透過本介紹都可以輕鬆掌握本方法。