记得一个angular在路由配置中管理AngularMaterialDialog(实现动态组件的弹窗显示)
时间:2023-03-28 14:13:29
HTML
背景描述目标我们的目标如题所示:在路由配置中管理AngularMaterialDialog,这样比较容易(less代码量更少、复用性更强、扩展性更强、可维护性更强)来实现动态组件的弹窗显示。不难看出,我们的目标由两部分组成,动态组件和弹窗。其实将两者分开实现并不难。Angular官网推荐的很多UI库都有这两者对应的demo。然而,将两者稳健地结合起来并不是一件容易的事。我试过两种方案:一种是bootstrap->model实现弹窗+Material->Cdk->Portal实现动态组件;另一种是Material->Dialog实现弹窗+给openDialog()方法传参控制Loaded组件实现动态组件。尝试两种方案后,会发现两种方案都有问题,大同小异:使用的组件(C层,V层)的代码侵入过多,有些代码需要改写很多次,这不是有利于发展。好兆头。后来在老师的指导下,终于发现还是用路由配置来管理MaterialDialog来实现动态组件弹出显示比较合适。这就是我们下面要研究的内容。MaterialDialog的使用方法首先,我们需要对Material->Dialog的基本用法有一定的了解。具体可以参考官方文档:https://material.angular.io/components/dialog/overview,这里不再赘述。.如何通过路由配置实现管理?首先我们要了解官方提供的dialog的经典用法。经过观察研究,我们可以看到它的大致运行流程,如下图所示:这个过程中的上述问题主要集中在第三步。由于openDialog()方法是直接写在组件的C层,代码入侵的问题无法避免。而如果给方法传递参数来控制要加载的组件来实现动态组件,这无疑会增加侵入式代码量,有些代码需要改写多次;最流行的做不到的是:每一个要这样用的组件都得自带这么一套,真是折磨人。那么现在的问题进一步转化为:如何在Material->Dialog经典用法的基础上,将原本需要写在组件C层的openDialog()方法抽取出来,并使其可复用且易于调用维持。经过老师的指导和网上查阅资料,最终通过路由配置管理达到了我们想要的效果,回过头来总结一下它的具体实现思路:V层按钮不再直接绑定openDialog()方法,而是绑定路由(routerLink)并添加路由内容输出语句();在路由中。窗口入口组件,没错,这就是我们新建的dialog-entry.component.ts文件。这时候我们需要把原组件C层的openDialog()方法和其他相关方法移到这个上面,这样原组件C层就不会出现代码侵入的问题了);然后在routing.module文件中绑定路由的数据中设置component:你要弹出的组件。具体过程如下图所示:这样就把实现弹窗效果的openDialog()方法和其他相关方法提取到了DialogEntryComponent中;组件的动态渲染传递给路由文件中的DialogEntryComponent,完成目标组件。完美解决了上述一系列问题。代码实现文件目录准备:1、Term目录下需要term-index组件、term-add组件、term-edit组件。每个组件都有C层、V层、CSS文件、测试文件;还需要一个term.module.ts,term-routing.module.ts文件。2.dialog-entry目录下需要dialog-entry.component.ts和dialog-entry.module.ts文件。term-index的C层什么都不需要。term-index的V层add>editterm-add的C层导出类TermAddComponent实现OnInit{constructor(publicdialogRef:MatDialogRef,){}ngOnInit():void{}onNoClick():void{this.dialogRef.close();}onOkClick():void{this.dialogRef.close();}}term-addVLayer嗨!term-add有效NoThanksOk
term-edit的C层和term-add的C层基本一样,只需要在构造函数中填入MatDialogRef<>给自己的组件即可。term-edit的V层与term-add基本相同,只是在h1标签中填入可以识别该组件的内容。term-routing.module.tsimport{NgModule}from'@angular/core';import{RouterModule,Routes}from'@angular/router';import{TermIndexComponent}from'./term-index/term-index.component';从'./term-add/term-add.component'导入{TermAddComponent};从'./term-edit/term-edit.component'导入{TermEditComponent};从'../..导入{DialogEntryComponent}/common/dialog-entry/dialog-entry.component';constroutes:Routes=[{path:'',component:TermIndexComponent,children:[{path:'add',component:DialogEntryComponent,data:{component:TermAddComponent}},{path:'edit/:TermId',component:DialogEntryComponent,data:{component:TermEditComponent}}]}];@NgModule({imports:[RouterModule.forChild(routes)],exports:[RouterModule]})exportclassTermRoutingModule{}dialog-entry.component.tsimport{Component}from'@angular/core';从'@angular/material/dialog'导入{MatDialog};从'@angular/router'导入{ActivatedRoute,Router};@Component({template:''})exportclassDialogEntryComponent{url:string|不明确的;constructor(publicdialog:MatDialog,privaterouter:Router,privateroute:ActivatedRoute){this.url=this.route.snapshot.url[0].path;这个.openDialog();}openDialog():void{constdialogRef=this.dialog.open(this.route.snapshot.data.component,{width:'250px'});constrelativeBackUrl=this.getRelativeBackUrl();dialogRef.afterClosed().subscribe(result=>{this.router.navigate([relativeBackUrl],{relativeTo:this.route});});}privategetRelativeBackUrl():string{if(this.url==='add'){return'../';}elseif(this.url==='edit'){return'../../';}else{返回'';}}}dialog-entry.module.tsimport{NgModule}来自'@angular/core';import{MatDialogModule}from'@angular/material/dialog';import{DialogEntryComponent}from'./dialog-entry.component';@NgModule({declarations:[DialogEntryComponent],imports:[MatDialogModule],})exportclassDialogEntryModule{}最后,使用时需要记得在模块中引入DialogEntryModule。这个演示是一个术语模块,带有term.module.ts@NgModule({declarations:[TermIndexComponent,TermAddComponent,TermEditComponent],imports:[CommonModule,TermRoutingModule,ReactiveFormsModule,MatButtonModule,DialogEntryModule,MatDialogModule],providers:[{provide:MatDialogRef,useValue:{}},],})至此,我们的目的终于达到了。如果你想复用其他模块,只需要做以下三个工作:可以:1.在模块文件中导入我们的DialogEntryModule;2.将路由信息绑定到主组件的V层按钮;3.在routing.module文件中设置要重定向的组件到对应的路由。众所周知,即使不使用动态组件弹窗,第2步和第3步的工作也是少不了的。像本文这样配置之后,后面其他模块要复用的时候,额外的工作只是在第1步和第3步多写几行简单的代码。这就是我们想要的,不需要造重复的轮子,而且可以很容易并易于重复使用。效果预览参考文章https://medium.com/ngconf/routing-to-angular-material-dialogs...