在 Angular 應用程式中,我們可以利用 NgTemplateOutlet 或 NgComponentOutlet 來實作動態內容元件。而在 CDK 裡也提供了 Portals 讓我們更容易實作這樣子的需求。
在引用 PortalModule
模組後,先使用 cdkPortalOutlet
來決定動態內容要放在的位置,並繫結型別為 Portal
的屬性。
<div [cdkPortalOutlet]="portal"></div>
selectedPortal: Portal<unkown>;
我們可以在此處放 Template、Component 或 DOM。例如,我們定義了一個 Template,接著在 TypeScript 中,利用這個 Template 建立 TemplatePortal
資料,就可以把它設定到 selectedPortal
來顯示出來。
<ng-template #templateContent>Template Portal</ng-template>
@ViewChild('templatePortal')
templateContent: TemplateRef<unknown>;
private readonly viewContainerRef = inject(ViewContainerRef);
templatePortal: TemplatePortal<any>;
ngAfterViewInit() {
this.templatePortal = new TemplatePortal(this.templateContent, this.viewContainerRef);
}
如果要傳入外部資料,則在建立實體時傳入第三個參數 ({ name: ‘A’ }
),就可以在範本中以 let-name=name
的方式取得。如下面程式,將動態內容元件建立一個 ComponentPortal
,就可以顯示在 cdkPortalOutlet
內。
@Component({ ... })
export class ContentComponent() {}
componentPortal: ComponentPortal<ContentComponent>;
ngAfterViewInit() {
this.componentPortal = new ComponentPortal(ContentComponent);
}
Overlay 是在 Angular Material 彈跳視窗的底層,我們可以利用 Overlay 來實作浮動於主頁面區塊的需求。在實作此種需求前,先使用 Portal 來定義動態頁面的區塊。
<ng-template cdkPortal>
<div style="border: solid 1px red; width: 400px">彈跳視窗內容</div>
</ng-template>
接著,在引用 OverlayModule
後,以及使用 Overlay
服務來開啟目標對象。如下面程式,可以利用 OverlayConfig
類別來定義開啟對象的位置、長與高等組態資訊。接著,透過 Overlay
服務的 create
來建立一個 Overlay 區域,並把剛定義的 Protal 內容加入這個區域內;以及關閉時把它給卸載掉。
@ViewChild(CdkPortal)
portal!: CdkPortal;
private readonly overlay = inject(Overlay);
onOpen(): void {
const config = new OverlayConfig({
positionStrategy: this.overlay
.position()
.global()
.centerHorizontally()
.centerVertically(),
minWidth: '500px',
height: '400px',
hasBackdrop: true,
});
const overlayRef = this.overlay.create(config);
overlayRef.attach(this.portal);
overlayRef.backdropClick().subscribe(() => overlayRef.detach());
}
除了上述方法外,我們也可以利用指令的方式來開啟 Overlay。如下面程式,在按鈕中透過 cdkOverlayOrigin
來設定觸發點,並且在點選這個按鈕時去控制一是否開啟的屬性。
<button
mat-stroked-button
color="primary"
cdkOverlayOrigin
#trigger="cdkOverlayOrigin"
(click)="isOpen = !isOpen"
>
Open
</button>
<ng-template
cdkConnectedOverlay
[cdkConnectedOverlayOrigin]="trigger"
[cdkConnectedOverlayOpen]="isOpen"
>
<div style="border: solid 1px red; width: 400px">Dialog Open</div>
</ng-template>
接著,在範本中利用 cdkConnectedOverlay
指定此為 Overlay 區域,並設定 cdkConnectedOverlayOrigin
與 cdkConnectedOverlayOpen
來決定開啟此區域的觸發按鈕與開啟狀態資訊。
在過去撰寫 Angular 專案時,常常會把 Angular Material 專案當作撰寫的參考資訊。在明確定義應用程式的全域與區域設定下,透過 Angular 與 Material 所提供的機制,可以較容易地開發出高靈活度的應用程式。