自定義結構型 Directive
這篇筆記介紹如何自定義一個結構型 Directive,其功能類似於 Angular 內建的 @if
(或舊版的 *ngIf
)。
基本用法
建立一個名為 appAuth
的結構型 Directive,用來根據用戶權限顯示或隱藏元素:
<p appAuth="admin">Only admins should see this!</p>
Directive 的基本實現
首先,我們在 Directive class 中定義必要的輸入和依賴:
// auth.directive.ts
import { Directive, input, effect, inject, TemplateRef, ViewContainerRef } from '@angular/core';
import { AuthService } from './auth.service';
import { Permission } from './permission.model';
@Directive({
selector: '[appAuth]',
standalone: true
})
export class AuthDirective {
// 使用 input() 設定輸入屬性,並給予別名
userType = input.required<Permission>({ alias: 'appAuth' });
// 注入必要的服務和參考
private authService = inject(AuthService);
constructor() {
effect(() => {
if (this.authService.activePermission() === this.userType()) {
console.log('SHOW');
} else {
console.log('DONT SHOW');
}
});
}
}
在這段程式碼中,我們:
使用
input()
定義了一個輸入屬性,並透過alias
設定別名為appAuth
(與選擇器相同)注入了
AuthService
以獲取當前用戶權限使用
effect()
在相關依賴變化時執行權限檢查
但這樣只能在控制台輸出訊息,還無法真正控制 DOM 的顯示與隱藏。
使用 ng-template 和結構型 Directive
要實現真正的結構型 Directive,我們需要:
使用
ng-template
包裝目標內容:
<ng-template appAuth="admin">
<p>Only admins should see this!</p>
</ng-template>
在 Directive 中注入
TemplateRef
和ViewContainerRef
:
export class AuthDirective {
userType = input.required<Permission>({ alias: 'appAuth' });
private authService = inject(AuthService);
// 注入 TemplateRef 和 ViewContainerRef
private templateRef = inject(TemplateRef);
private viewContainerRef = inject(ViewContainerRef);
constructor() {
effect(() => {
if (this.authService.activePermission() === this.userType()) {
// 顯示內容
this.viewContainerRef.createEmbeddedView(this.templateRef);
} else {
// 清除內容
this.viewContainerRef.clear();
}
});
}
}
這裡的關鍵點是:
TemplateRef
:引用包含在ng-template
中的內容ViewContainerRef
:指向 DOM 中應該插入內容的位置createEmbeddedView()
:將模板內容渲染到視圖容器中clear()
:從視圖容器中移除所有內容
當我們進入頁面的時候不會看到那句話出現在畫面上,但在 element 裡面可以看到一個 Angular 的標記,可以找到當符合條件時內容應該呈現的地方。如圖:

當條件符合時,模板內容會被渲染;不符合時,內容會被移除。
使用星號語法糖(*)
Angular 提供了星號(*
)作為語法糖,讓我們可以更簡潔地使用結構型 Directive:
<p *appAuth="'admin'">Only admins should see this!</p>
這等同於之前的 ng-template
寫法,但更簡潔。注意這裡的 'admin'
需要用單引號包起來,因為它在引號內被當作 TypeScript 表達式處理。
使用星號語法時,Angular 會在背後:
創建一個
ng-template
元素將原始元素移入模板中
在模板上應用 Directive
結論
自定義結構型 Directive 需要:
定義輸入屬性接收條件
注入
TemplateRef
和ViewContainerRef
根據條件使用
createEmbeddedView()
或clear()
控制內容的顯示
Last updated