Angular使用动态加载组件方法实现Dialog步骤详解

这次给大家带来Angular使用动态加载组件方法实现Dialog步骤详解,Angular使用动态加载组件方法实现Dialog的注意事项有哪些,下面就是实战案例,一起来看一下。

网上的文章和教程基本上写到组件加载完成就没了!没了?!而且都是只能存在一个dialog,想要打开另一个dialog必须先销毁当前打开的dialog,之后看过 material 的实现方式,怪自己太蠢看不懂源码,就只能用自己的方式来实现一个dialog组件了

Dialog组件的目标:可以同时存在多个Dialog,可销毁指定Dialog,销毁后html中无组件残留且提供回调

动态加载组件的实现方式有两种,angular4.0版本之前使用ComponentFactoryResolver来实现,4.0之后可以使用更便捷的ngComponentOutlet来实现,

通过ComponentFactoryResolver实现动态载入

首先理一下ViewChild、ViewChildren、ElementRef、ViewContainerRef、ViewRef、ComponentRef、ComponentFactoryResolver之间的关系:

ViewChild 与 ViewChildren

ViewChild是通过模板引用变量(#)或者指令(directive)用来获取 Angular Dom 抽象类,ViewChild可以使用 ElementRef 或者 ViewContainerRef 进行封装。

@ViewChild('customerRef') customerRef:ElementRef;

登录后复制

ViewChildren通过模板引用变量或者指令用来获取QueryList,像是多个ViewChild组成的数组。

@ViewChildren(ChildDirective) viewChildren: QueryList;

登录后复制

ElementRef 与 ViewContainerRef

ViewChild可以使用 ElementRef 或者 ViewContainerRef 进行封装,那么 ElementRef 和 ViewContainerRef 的区别是什么?

用 ElementRef 进行封装,然后通过 .nativeElement 来获取原生Dom元素

console.log(this.customerRef.nativeElement.outerHTML);

登录后复制

ViewContainerRef :视图的容器,包含创建视图的方法和操作视图的api(组件与模板共同定义了视图)。api会返回 ComponentRef 与 ViewRef,那么这两个又是什么?

// 使用ViewContainetRef时,请使用read声明@ViewChild('customerRef',{read: ViewContainerRef}) customerRef:ViewContainerRef;···this.customerRef.createComponent(componentFactory) // componentFactory之后会提到

登录后复制

ViewRef 与 ComponentRef

ViewRef 是最小的UI单元,ViewContainerRef api操作和获取的就是ViewRef

ComponentRef:宿主视图(组件实例视图)通过 ViewContainerRef 创建的对组件视图的引用,可以获取组件的信息并调用组件的方法

ComponentFactoryResolver

要获取 ComponentRef ,需要调用 ViewContainer 的 createComponent 方法,方法需要传入ComponentFactoryResolver创建的参数

constructor( private componentFactoryResolver:ComponentFactoryResolver) { }viewInit(){  componentFactory =    this.componentFactoryResolver.resolveComponentFactory(DialogComponent);  // 获取对组件视图的引用,到这一步就已经完成了组件的动态加载  componentRef = this.customerRef.createComponent(componentFactory);  // 调用载入的组件的方法  componentRef.instance.dialogInit(component);}

登录后复制

具体实现

let componentFactory,componentRef;

@ViewChild('customerRef',{read: ViewContainerRef}) customerRef:ViewContainerRef;constructor( private componentFactoryResolver:ComponentFactoryResolver) { }viewInit(){ // DialogComponent:你想要动态载入的组件,customerRef:动态组件存放的容器  componentFactory =    this.componentFactoryResolver.resolveComponentFactory(DialogComponent);  componentRef = this.customerRef.createComponent(componentFactory);}

登录后复制

通过ngComponentOutlet实现动态载入

ngComponentOutlet 大大缩减了代码量,但是只有带4.0之后的版本才支持

具体实现

在dialog.component.html建立动态组件存放节点


登录后复制

将组件(不是组件名称)传入,就OK了,为什么可以这么简单!

dialogInit(component){  this.componentName = component;};

登录后复制

Dialog的实现

实现的思路是这样的:首先创建一个dialog组件用来承载其他组件,为dialog创建遮罩和动画,建立一个service来控制dialog的生成和销毁,不过service只生成dialog,dialog内的组件还是需要在dialog组件内进行生成

1、首先写一个公共的service,用来获取根组件的viewContainerRef(尝试过 ApplicationRef 获取根组件的 viewContainerRef 没成功,所以就写成service了)

gerRootNode(...rootNodeViewContainerRef){  if(rootNode){   return rootNode;  }else {   rootNode = rootNodeViewContainerRef[0];  };}// 然后再根组件.ts内调用this.fn.gerRootNode(this.viewcontainerRef);

登录后复制

2、创建dialog.service.ts,定义open、close三个方法,使用ViewContainerRef创建dialog组件,创建之前需要调用 ComponentFactoryReslover,并将DialogComponent传入

let componentFactory;let componentRef;@Injectable()export class DialogService { constructor(    private componentFactoryResolver:ComponentFactoryResolver    private fn:FnService  ) { }    open(component){  componentFactory =    this.componentFactoryResolver.resolveComponentFactory(DialogComponent);    // 这里的获取的是ComponentRef  containerRef = this.fn.gerRootNode().createComponent(componentFactory);     // 将containerRef存储下来,以便之后的销毁  containerRefArray.push(containerRef);    // 调用了组件内的初始化方法,后面会提到  return containerRef.instance.dialogInit(component,containerRef); }  // 这里有两种情况,一种是在当前组件和dialog组件关闭调用的,因为有返回值所以可以关闭指定的dialog;还有一种是在插入到dialog组件内的组件调用的,因为不知道父组件的信息,所以默认关闭最后一个dialog close(_containerRef=null){  if( _containerRef ){   return _containerRef.containerRef.instance.dialogDestory();  }else{   containerRefArray.splice(-1,1)[0].instance.dialogDestory();  } }}

登录后复制

3、dialog.component.ts,这里使用 ngComponentOutlet 来实现(ngComponentOutlet 在下面提到,这里为了偷懒,直接拿来用了)

let containerRef,dialogRef = new DialogRef();export class DialogComponent implements OnInit { componentName; constructor(  private fn:FnService ) { } dialogInit( _component, _containerRef){  this.componentName = _component;  containerRef = _containerRef;  dialogRef['containerRef'] = containerRef;  return dialogRef; }; dialogDestory(){  let rootNode = this.fn.gerRootNode();  // 等待动画结束再移除  setTimeout(()=>{  // 这里用到了 viewContainerRef 里的indexOf 和 remove 方法   rootNode.remove(rootNode.indexOf(containerRef.hostView));  },400);  dialogRef.close();  return true; }; }

登录后复制

4、这里还创建了一个 DialogRef 的类,用来处理 dialog 关闭后的回调,这样就可以使用 XX.afterClose().subscribe() 来创建回调的方法了

@Injectable()export class DialogRef{ public afterClose$ = new Subject(); constructor(){} close(){  this.afterClose$.next();  this.afterClose$.complete(); } afterClose(){  return this.afterClose$.asObservable(); }}

登录后复制

创建和销毁dialog

// 创建let _viewRef = this.dialogService.open(DialogTestComponent);_viewRef.afterClose().subscribe(()=>{  console.log('hi');});// 销毁this.dialogService.close()

登录后复制

相信看了本文案例你已经掌握了方法,更多精彩请关注【创想鸟】其它相关文章!

推荐阅读:

Node.js Express安装与使用步骤详解

table表格内对某列内容进行搜索筛选步骤详解

以上就是Angular使用动态加载组件方法实现Dialog步骤详解的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2759828.html

(0)
上一篇 2025年3月8日 08:45:20
下一篇 2025年3月8日 08:45:26

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • Ajax实现列表无限加载和二级下拉选项效果

    这篇文章主要为大家详细介绍了ajax实现列表无限加载和二级下拉选项效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 Ajax做列表无限加载和Ajax做二级下拉选项,供大家参考,具体内容如下 //栏目Ajax做加载public func…

    编程技术 2025年3月8日
    200
  • Angular路由守卫使用步骤详解

    这次给大家带来Angular路由守卫使用步骤详解,Angular路由守卫使用的注意事项有哪些,下面就是实战案例,一起来看一下。 一、路由守卫 当用户满足一定条件才被允许进入或者离开一个路由。 路由守卫场景: 只有当用户登录并拥有某些权限的时…

    2025年3月8日 编程技术
    200
  • vue项目中公用footer组件底部位置适配步骤详解

    这次给大家带来vue项目中公用footer组件底部位置适配步骤详解,vue项目中公用footer组件底部位置适配的注意事项有哪些,下面就是实战案例,一起来看一下。 需求: footer为公用组件,其他页面都需要引入,这是会存在一种情况:有的…

    2025年3月8日
    200
  • Ajax实现动态加载数据

    这篇文章主要为大家详细介绍了ajax动态加载数据的小例子,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 前言: 1.这个随笔实现了一个Ajax动态加载的例子。 2.使用.net 的MVC框架实现。 3.这个例子重点在前后台交互,其它略写…

    编程技术 2025年3月8日
    200
  • ajax实现页面加载和内容删除

    这篇文章主要为大家详细介绍了ajax实现页面加载和内容删除的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 ajax最大的好处就在于加载和删除的时候不会跳转页面,现在的网页大多都会选择用ajax来写,相比嵌入PHP代码来说减少了…

    2025年3月8日
    200
  • 怎样用React Form完成组件封装

    这次给大家带来怎样用React Form完成组件封装,用React Form完成组件封装的注意事项有哪些,下面就是实战案例,一起来看一下。 前言 对于网页系统来说,表单提交是一种很常见的与用户交互的方式,比如提交订单的时候,需要输入收件人、…

    2025年3月8日
    200
  • 怎样使用@angular/cli V6.0开发PWA应用

    这次给大家带来怎样使用@angular/cli V6.0开发PWA应用,使用@angular/cli V6.0开发PWA应用的注意事项有哪些,下面就是实战案例,一起来看一下。 什么是PWA PWA(Progressive Web App)利…

    2025年3月8日 编程技术
    200
  • 如何使JS文件内加载jquery.js

    这次给大家带来如何使JS文件内加载jquery.js,使JS文件内加载jquery.js的注意事项有哪些,下面就是实战案例,一起来看一下。 最近有一个需求: 1.在一个html中只能引入一个JS文件 不能有JS代码和其他JS文件的引入; 2…

    2025年3月8日
    100
  • 怎样使用Angular模版驱动表单

    这次给大家带来怎样使用Angular模版驱动表单,使用Angular模版驱动表单的注意事项有哪些,下面就是实战案例,一起来看一下。 获取用户输入 Angular表单 登录 登录后复制 假如有以上简单表单,先不论优劣,有哪些方式可以获取到表单…

    2025年3月8日 编程技术
    200
  • angular httpclient实现 HTTP 客户端功能

    这次给大家带来angular httpclient实现 HTTP 客户端功能,angular httpclient实现HTTP客户端功能的注意事项有哪些,下面就是实战案例,一起来看一下。 现代浏览器支持使用两种不同的 API 发起 HTTP…

    2025年3月8日 编程技术
    200

发表回复

登录后才能评论