手把手教你使用Angular CDK Portal创建动态内容

手把手教你使用Angular CDK Portal创建动态内容

之前介绍过原生 API 的动态视图插入,功能上已经可以满足大多数使用场景。不过也有一些缺憾,还没有解决在 Angular 应用外插入内容的需求,指令也不能跟动态插入的组件有输入输出的交互。

好在 Angular 官方提供了一套组件开发套件 Component Dev Kit (CDK),作为各种 Angular 组件开发的基础工具,其中就提供 “Portal(传送门)” 来辅助动态视图的创建。

这个 ”动态视图“ 可以是组件、TemplateRef 或者 DOM 元素,分别对应三种 Portal 类型(ComponentPortal、TemplatePortal、DomPortal)。它们三个的抽象泛型基类是 Portal,有三个方法:attach(挂载到容器)、detach(从容器移除)、isAttached(判断视图是否是挂载状态)。

而容器也是由一个抽象类 BasePortalOutlet 定义,和视图类似,包含 attach(给容器挂载视图)、detach(从容器移除视图)、dispose(销毁容器)、isAttached(是否有挂载视图)。它的主要实现是 DomPortalOutlet 类。用以挂载三种类型的动态视图。

创建动态内容

先来看看三种动态视图的创建。

ComponentPortal

相比原生 API,要创建一个动态组件非常的简单,只需要把组件类传入 ComponentPortal 构造函数即可。

this.componentPortal = new ComponentPortal(ExampleComponent);

登录后复制

可以传入任意自定义的组件类,用以创建 ComponentPortal 对象,再动态插入视图中。

✨注意:Angular 9 后的版本推荐使用 Ivy 编译器,如果是老版本编译器,传入的组件类,需要在 Module 的 entryComponents 中声明,并且这个 Module 不能懒加载。

TemplatePortal

TemplatePortal 的构建,相比组件,多了一个参数(ViewContainerRef)。看过前一篇应该对它非常熟悉了,需要依赖它调用 createEmbeddedView() 来创建嵌入视图。这里通过构造注入,直接使用当前组件的 ViewContainerRef 实例。

  

一些需要动态插入的内容.

登录后复制

@ViewChild('testTemplate') templatePortalContent: TemplateRef;constructor(private _viewContainerRef: ViewContainerRef) { }ngAfterViewInit() {  this.templatePortal = new TemplatePortal(    this.templatePortalContent,    this._viewContainerRef  );}

登录后复制

除了通过构造函数,TemplatePortal 也有一个指令(CdkPortal)可以便捷创建。

  

一些需要动态插入的内容.

  一些需要动态插入的内容.

登录后复制

然后通过 @ViewChild 就可以获得 TemplatePortal 的实例了。

DomPortal

就像上面的示例通过 @ViewChild 获取 Template 实例来创建,类似的也可以获取 ElementRef 来创建动态的 DOM。

原生DOM内容

登录后复制

@ViewChild('domPortalContent') domPortalContent: ElementRef;ngAfterViewInit() {  this.domPortal = new DomPortal(this.domPortalContent);}

登录后复制

可以动态的将这段 DOM 转移到任意位置。要注意的是,转移之后,原来的数据绑定,或者绑定的指令可能不会再继续更新。

插入容器

前面三种类型的 Portal 都说了可以渲染到任意位置,那具体怎么渲染呢?

CdkPortOutlet

最简单的就是通过 CdkPortOutlet 指令了:

  

登录后复制

给 anyPortal 传值上面三个中任意的 Portal 实例,都会动态渲染到当前位置。

和原生 API 的指令不同,它可以自动判断是什么类型的 Portal。另外,它还有个额外的事件:attached,通过这个事件,可以获取到挂载的组件实例,或者 TemplateRef。这也让和挂载组件的交互变得十分方便了。

构造容器实例

不过既然说了是可以渲染到任意位置,那自然也包括 Angular 应用外部,要渲染到应用之外,就需要咱们通过构造函数创建容器实例。

这个容器类就是 DomPortalOutlet,它是 PortalOutlet 的实现子类。它的构造参数主要是:Element(挂载视图的DOM节点)、ComponentFactoryResolver(和上篇一样,用以动态构建组件)、appRef(当前 Angular 应用的整体实例)、Injector(注入器,用于传递依赖)。

constructor(  private viewContainerRef: ViewContainerRef,  @Inject(DOCUMENT) private document: any,  private injector: Injector,  private componentFactoryResolver: ComponentFactoryResolver) {  // 在下创建外部宿主元素  const container = this.document.createElement('div');  container.classList.add('outside-portal-container');  this.outsideContainer = this.document.body.appendChild(container);  // 获取应用实例  this.appRef = this.injector.get(ApplicationRef);  // 创建外部容器  this.outsideOutlet = new DomPortalOutlet(    this.outsideContainer,     this.componentFactoryResolver,     this.appRef,     this.injector  );}// 在应用外部插入动态组件。openComponentPortalOutSideAngularContext(): void {  const componentPortal = new ComponentPortal(AlertComponent);  const componentRef = this.outsideOutlet.attach(componentPortal);    componentRef.instance.closeAlert.subscribe(() => {      this.outsideOutlet.detach();    });}// 在应用外部插入动态模板。openTemplatePortalInsideAngularContext(): void {  const templatePortal = new TemplatePortal(this.templatePortalContent, this.viewContainerRef);  this.outsideOutlet.attach(templatePortal);}

登录后复制

除了挂载视图到应用外的 DOM 元素中,还需要能够跟视图进行数据交互,组件可以通过注入依赖,模板可以传入上下文对象。

const injectionToken = new InjectionToken('Sharing data with outside component portal');const customInjector = Injector.create({ providers: [{ provide: CustomInjectionToken, useValue: 'test value' }] });

登录后复制

对创建 outsideContainer 的代码稍作修改,把这个 customInjector 作为参数传入(而不是使用当前组件的 injector)

// 重点是第四个参数new DomPortalOutlet(this.outsideContainer, this.componentFactoryResolver, this.appRef, customInjector);

登录后复制

相应的,这个组件只需要按这个 injectionToken 注入依赖即可:

constructor(@Inject(injectionToken) public customData: any) {}

登录后复制

给模板传递上下文就比较简单了,在创建 TemplatePortal 对象时,传入上下文对象即可:

// 重点是第三个参数new TemplatePortal(this.templatePortalContent, this.viewContainerRef, { customData:'test values' });

登录后复制

总结

相比原生 API,CDK portal 主要实现了:

动态插入视图到应用外部的能力;

和插入到外部的视图数据交互的能力;

更加便捷和灵活的指令。

有了它,创建动态的组件容器,或者弹窗,浮动菜单,甚至是搭建一个低代码设计平台,都变得更加容易了。

项目源码:https://github.com/locotor/angular-dynamic-view-example在线示例:https://coding-pages-bucket-1575455-8137703-14801-541995-1303365836.cos-website.ap-beijing.myqcloud.com/

更多编程相关知识,请访问:编程入门!!

以上就是手把手教你使用Angular CDK Portal创建动态内容的详细内容,更多请关注【创想鸟】其它相关文章!

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

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

(0)
上一篇 2025年3月7日 20:25:18
下一篇 2025年3月5日 19:52:06

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

相关推荐

  • 浅谈Angular中如何使用路由?

    angular中如何使用路由?本篇文章就来带大家了解一下angular中使用路由的方法,快速入门angular路由,希望对大家有所帮助! 路由的概念在前端的框架中得到了广泛的应用,对于路由的感念不做阐述,路由的应用无外乎就是嵌套、传参,高级…

    2025年3月7日
    200
  • 聊聊Angular中的自定义管道

    angular中管道有什么用?特点是什么?怎么自定义管道?下面本篇文章带大家了解一下angular中的管道,介绍一下自定义管道的方法,希望对大家有所帮助! 一、管道的作用 方便我们在模板中对我们的数据进行格式化处理。【相关教程推荐:《ang…

    2025年3月7日
    200
  • 深入了解Angular中的路由

    什么是路由?本篇文章带大家深入了解一下angular中的路由,希望对大家有所帮助! 路由简介 路由是实现单页面应用的一种方式,通过监听hash或者history的变化,渲染不同的组件,起到局部更新的作用,避免每次URL变化都向服务器请求数据…

    2025年3月7日
    200
  • 深入浅析Angular中的依赖注入

    什么是依赖注入?本篇文章带大家了解一下angular中的依赖注入,希望对大家有所帮助! 依赖注入概念: 维基百科对依赖注入的解释:在软件工程中,依赖注入是实现控制反转的一种软件设计模式,一个依赖是一个被其他对象(client)调用的对象(服…

    2025年3月7日
    200
  • 聊聊Angular中常用的错误处理方式

    本篇文章带大家深入了解一下angular中常用的错误处理方式,希望对大家有所帮助! 错误处理是编写代码经常遇见的并且必须处理的需求,很多时候处理异常的逻辑是为了避免程序的崩溃,本文将简单介绍Angular处理异常的方式。【相关教程推荐:《a…

    2025年3月7日
    200
  • 带你了解Angular10中的双向绑定

    下面本篇文章带大家了解一下双向绑定,看看angular中两种类型的双向绑定,希望对大家有所帮助! 前面我们了解了属性绑定、事件绑定以及输入和输出的使用,是时候了解双向绑定了。本节,我们将利用@Input()和@Output()来了解下双向绑…

    2025年3月7日 编程技术
    200
  • 浅析Angular中什么是ngModule

    什么是ngmodule?本篇文章带给大家简单了解一下angular语法,介绍一下angular中的ngmodule,希望对大家有所帮助! 作为Angular10教程,在我的理解中,angular相较于VUE,它的模块化做得更好,这样使代码结…

    2025年3月7日
    200
  • 聊聊Angular+Service如何改进日志功能

    如何改善angular的日志使用方式?下面本篇文章给大家介绍一下使用angular中的service管理控制台输出,改进日志功能的方法,希望对大家有所帮助! 改善在Angular 应用中的日志使用方式 Angular是一个非常受欢迎的开发框…

    2025年3月7日 编程技术
    200
  • 深入浅析Angular中的指令、管道和服务

    angular中什么是指令、管道、服务?下面本篇文章带大家了解一下angular中的指令、管道和服务,希望对大家有所帮助! 1. 指令 Directive 指令是 Angular 提供的操作 DOM 的途径。指令分为属性指令和结构指令。【相…

    2025年3月7日
    200
  • 带你了解Angular中的组件通讯和依赖注入

    angular组件间怎么进行通讯?依赖注入是什么?下面本篇文章带大家简单了解一下组件通讯的方法,并介绍一下依赖注入,希望对大家有所帮助! 1.  组件通讯 1.1  向组件内部传递数据 登录后复制 // favorite.component…

    2025年3月7日
    200

发表回复

登录后才能评论