如何实现可注入不同组件的Angular通用对话框组件?
实现方案
步骤1:创建通用对话框容器组件
该组件作为所有对话框的公共外壳,内置统一的按钮样式、取消逻辑、公共变量,预留动态渲染业务组件的出口:
import { Component, Inject, ViewChild, ViewContainerRef } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; @Component({ selector: 'app-common-dialog', template: ` <!-- 公共头部 统一样式 --> <div class="dialog-header"> <h2>{{data.title || '通用对话框'}}</h2> </div> <!-- 动态业务组件渲染容器 --> <div class="dialog-body"> <ng-template #componentHost></ng-template> </div> <!-- 公共底部按钮 统一样式和逻辑 --> <div class="dialog-footer"> <button class="btn btn-cancel" (click)="handleCancel()">取消</button> <button class="btn btn-confirm" (click)="handleConfirm()">确定</button> </div> `, styles: [` /* 统一写所有对话框的公共样式 */ .dialog-header { padding: 16px; border-bottom: 1px solid #eee; } .dialog-body { padding: 16px; min-height: 100px; } .dialog-footer { padding: 16px; border-top: 1px solid #eee; display: flex; justify-content: flex-end; gap: 12px; } .btn-cancel { border: 1px solid #ccc; padding: 6px 12px; border-radius: 4px; } .btn-confirm { background: #1890ff; color: #fff; border: none; padding: 6px 12px; border-radius: 4px; } `] }) export class CommonDialogComponent { @ViewChild('componentHost', { static: true, read: ViewContainerRef }) componentHost!: ViewContainerRef; constructor( public dialogRef: MatDialogRef<CommonDialogComponent>, @Inject(MAT_DIALOG_DATA) public data: any ) {} ngOnInit() { // 动态渲染传入的业务组件 const componentRef = this.componentHost.createComponent(this.data.targetComponent); // 给业务组件传递自定义数据 if (componentRef.instance && this.data.businessData) { Object.assign(componentRef.instance, this.data.businessData); } } // 统一取消逻辑 handleCancel() { this.dialogRef.close({ action: 'cancel' }); } // 统一确认逻辑,可根据需求扩展 handleConfirm() { this.dialogRef.close({ action: 'confirm' }); } }
如果是Angular14以下版本,需要将CommonDialogComponent添加到对应模块的declarations和entryComponents数组中。
步骤2:封装自定义Dialog服务
在服务中实现你需要的openById方法,同时支持给对话框分配自定义ID:
import { Injectable } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { CommonDialogComponent } from './common-dialog.component'; @Injectable({ providedIn: 'root' }) export class CustomDialogService { constructor(private dialog: MatDialog) {} openById(dialogId: string, targetComponent: any, config: any = {}) { // 合并默认配置和传入的自定义配置 const finalConfig = { id: dialogId, disableClose: true, hasBackdrop: true, ...config, data: { targetComponent, businessData: config.data || {} } }; // 统一打开通用容器组件 return this.dialog.open(CommonDialogComponent, finalConfig); } }
步骤3:业务侧调用
完全符合你期望的调用方式:
import { TargetBusinessComponent } from './target-business.component'; constructor(private customDialog: CustomDialogService) {} openCustomDialog() { this.customDialog.openById('user-edit-dialog', TargetBusinessComponent, { data: { userId: 123, userName: '张三' }, width: '600px' }).afterClosed().subscribe(res => { if (res?.action === 'confirm') { // 处理确认后的业务逻辑 } }); }
补充说明
- 所有公共逻辑、样式、变量全部收敛在
CommonDialogComponent中,业务组件无需重复实现 - 如果需要通过ID获取已打开的对话框实例,直接调用原生API
this.dialog.getDialogById('你自定义的dialogId')即可 - 若需要业务组件和通用对话框交互(比如业务组件控制确认按钮禁用状态),可通过服务、输入输出属性实现扩展
内容的提问来源于stack exchange,提问作者LaCodeM
相关产品推荐
相关产品推荐

