技术经验分享:Angular动态创建组件之Portals

简介: 技术经验分享:Angular动态创建组件之Portals

这篇文章主要介绍使用Angular api 和 CDK Portals两种方式实现动态创建组件,另外还会讲一些跟它相关的知识点,如:Angular多级依赖注入、ViewContainerRef,Portals可以翻译为 门户 ,我觉得放到这里叫 入口 更好,可以理解为动态创建组件的入口,类似于小程序或者Vue中的Slot.

cdk全名Component Development Kit 组件开发包,是Angular官方在开发基于Material Design的组件库时抽象出来单独的一个开发包,里面封装了一些开发组件时的公共逻辑并且跟Material Design 设计无关,可以用来封装自己的组件库或者直接在业务开发中使用,里面代码抽象程度非常高,非常值得学习,现在我用到的有Portals、Overlay(打开浮层相关)、SelectionModel、Drag and Drop等.

官方:

中文翻译:

动态创建组件

想想应用的路由,一般配置路由地址的时候都会给这个地址配置一个入口组件,当匹配到这个路由地址的时候就在指定的地方渲染这个组件,动态创建组件类似,在最页面未接收到用户行为的时候,我不知道页面中这块区域应该渲染那个组件,当页面加载时根据数据库设置或者用户的操作行为才能确定最终要渲染的组件,这时候就要用代码动态创建组件把目标组件渲染到正确的地方。

示例截图

使用Angular API动态创建组件

该路由的入口组件是PortalsEntryConponent组件,如上面截图所示右侧有一块虚线边框的区域,里面具体的渲染组件不确定。

第一步

先在视图模板中定义一个占位的区域,动态组件就要渲染在这个位置,起一个名称#virtualContainer

文件portals-entry.component.html

?1234[/code>div class="portals-outlet"

第二步

通过ViewChild取到这个container对应的逻辑容器

文件portals-entry.component.ts

?12@ViewChild('virtualContainer', { read: ViewContainerRef }) virtualContainer: ViewContainerRef;

第三步

处理单击事件,单击按钮时动态创建一个组件,portals-entry.component.ts完整逻辑

?12345678910111213141516171819202122232425262728293031import { TaskDetailComponent } from '../task/task-detail/task-detail.component';@Component({ selector: 'app-portals-entry', templateUrl: './portals-entry.component.html', styleUrls: 【'./portals-entry.component.scss'】, providers: 【 】})export class PortalsEntryComponent implements OnInit { @ViewChild('virtualContainer', { read: ViewContainerRef }) virtualContainer: ViewContainerRef; constructor( private dynamicComponentService: DynamicComponentService, private componentFactoryResolver: ComponentFactoryResolver, private injector: Injector, ) { } ngOnInit() { } openTask() { const task = new TaskEntity(); task.id = '1000'; task.name = '写一篇关于Portals的文章'; const componentFactory = this.componentFactoryResolver.resolveComponentFactory(TaskDetailComponent); const componentRef = this.virtualContainer.createComponent/code>TaskDetailComponent

代码说明

openTask()方法绑定到模板中按钮的单击事件

导入要动态创建的组件TaskDetailComponent

constructor注入injector、componentFactoryResolver 动态创建组件需要的对象,只有在组件上下文中才可以拿到这些实例对象

使用api创建组件,现根据组件类型创建一个ComponentFactory对象,然后调用viewContainer的createComponent创建组件

使用componentRef.instance获取创建的组件实例,这里用来设置组件的task属性值

其它

ViewContainerRef除了createComponent方法外还有一个createEmbeddedView方法,用于创建模板

?123@ViewChild('customTemplate')customTemplate: TemplateRef;this.virtualContainer.createEmbeddedView(this.customTemplate, { name: 'pubuzhixing' });

createEmbeddedView方法的第二个参数,用于指定模板的上下文参数,看下模板定义及如何使用参数

?123

自定义模板,传入参数name:{{name}}

此外还可以通过ngTemplateOutlet直接插入内嵌视图模板,通过ngTemplateOutletContext指定模板的上下文参数

?1

小结

分析下Angular动态创建组件/内嵌视图的API,动态创建组件首先需要一个被创建的组件定义或模板声明,另外需要Angular上下文的环境来提供这个组件渲染在那里以及这个组件的依赖从那获取,viewContainerRef是动态组件的插入位置并且提供组件的逻辑范围,此外还需要单独传入依赖注入器injector,示例直接使用逻辑容器的injector,是不是很好理解。

示例仓储:

CDK Portal 官方文档介绍

这里先对Portal相关的内容做一个简单的说明,后面会有两个使用示例,本来这块内容准备放到最后的,最终还是决定放在前面,可以先对Portals有一个简单的了解,如果其中有翻译不准确请见谅。

地址:

-------- 文档开始

portals 提供渲染动态内容到应用的可伸缩的实现,其实就是封装了Angular动态创建组件的过程

Portals

这个Portal指是能动态渲染一个指定位置的 UI块 到页面中的一个 open slot 。

UI块 指需要被动态渲染的内容,可以是一个组件或者是一个模板,而 open slot 是一个叫做PortalOutlet的开放的占位区域。

Portals和PortalOutlets是其它概念中的低级的构造块,像overlays就是在它基础上构建的

?1Portal 包括动态组件的抽象类,可以是TemplatePortal(模板)或者ComponentPortal(组件)

方法描述

attach(PortalOutlet): T

把当前Portal附加到宿主上

detach(): void

把Portal从宿主上拆离

isAttached://代码效果参考:http://www.jhylw.com.cn/160723361.html

boolean

当前Portal是否已经附加到宿主上

?1PortalOutlet 动态组件的宿主

方法描述

attach(Portal): any

附加指定Portal

detach(): any

拆离当前附加Portal

dispose(): void

永久释放宿主资源

hasAttached: boolean

当前是否已经装在Portal

代码片段说明

CdkPortal

?12345678

The content of this template is captured by the portal.

可以通过ViewChild、ViewChildren获取到该Portal,类型应该是CdkPortal,如下所示:

?12// 模板中的Portal@ViewChild(CdkPortal) templateCDKPortal: TemplatePortal;

ComponentPortal

组件类型的Portal,需要当前组件在NgModule的entryComponents中配置才能动态创建该组件。

?1this.userSettingsPortal = new ComponentPortal(UserSettingsComponent);

CdkPortalOutlet

使用指令可以把portal outlet添加到一个ng-template,cdkPortalOutlet把当前元素指定为PortalOutlet,下面代码把userSettingsPortal绑到此portal-outlet上

?12

cdkPortalOutlet】="userSettingsPortal"

----- 文档完毕

Portals使用示例

这里首先使用新的api完成和最上面示例一样的需求,在同样的位置动态渲染TaskDetailComponent组件。

第一步

同样是设置一个宿主元素用于渲染动态组件,可以使用指令cdkPortalOutlet挂载一个PortalOutlet在这个ng-container元素上

?1234[/code>div class="portals-outlet"

第二步

与 使用Angular API动态创建组件 一节使用同一个逻辑元素作为宿主,只不过这里的获取容器的类型是CdkPortalOutlet,代码如下

?12@ViewChild('virtualContainer', { read: CdkPortalOutlet })virtualPotalOutlet: CdkPortalOutlet;

第三步

创建一个ComponentPortal类型的Portal,并且将它附加上面获取的宿主virtualPotalOutlet上,代码如下

?12345678portalOpenTask() { this.virtualPotalOutlet.detach(); const taskDetailCompoentPortal = new ComponentPortal ; const ref = this.virtualPotalOutlet.attach(taskDetailCompoentPortal); // 此处同样可以 通过ref.instance传递task参数}

小结

这里是使用ComponentPortal的示例实现动态创建组件,Portal还有一个子类TemplatePortal是针对模板实现的,上节 CDK Portal 官方文档介绍 中有介绍,这里就不在赘述了。总之使用Portals可以很大程度上简化代码逻辑。

示例仓储:

Portals 源码分析

上面只是使用Portal的最简单用法,下面讨论下它的

相关文章
|
3月前
|
开发框架 前端开发 JavaScript
使用Angular构建大型企业级应用的技术探索
【8月更文挑战第11天】Angular凭借其强大的组件化开发能力、模块化系统、丰富的生态系统和静态类型检查特性,成为了构建大型企业级应用的理想选择。通过设计良好的架构、使用Angular CLI、组件化开发实践、合理利用服务、性能优化以及严格测试和调试等方法,可以高效地构建出高质量、可维护、可扩展的企业级应用。未来,随着Angular技术的不断发展和完善,相信它将在企业级应用开发领域发挥更加重要的作用。
|
3月前
|
前端开发 Java Spring
Spring与Angular/React/Vue:当后端大佬遇上前端三杰,会擦出怎样的火花?一场技术的盛宴,你准备好了吗?
【8月更文挑战第31天】Spring框架与Angular、React、Vue等前端框架的集成是现代Web应用开发的核心。通过RESTful API、WebSocket及GraphQL等方式,Spring能与前端框架高效互动,提供快速且功能丰富的应用。RESTful API简单有效,适用于基本数据交互;WebSocket支持实时通信,适合聊天应用和数据监控;GraphQL则提供更精确的数据查询能力。开发者可根据需求选择合适的集成方式,提升用户体验和应用功能。
92 0
|
3月前
|
API 开发者 UED
PrimeFaces:JSF的魔法衣橱,解锁UI设计的无限可能!
【8月更文挑战第31天】本文介绍如何结合 JSF(JavaServer Faces)和 PrimeFaces 构建美观且功能强大的现代用户界面。PrimeFaces 提供丰富的 UI 组件库,包括按钮、输入框、数据网格等,支持现代 Web 标准,简化界面开发。文章通过具体示例展示如何使用 `<p:inputText>` 和 `<p:calendar>` 等组件创建用户表单,并用 `<p:dataTable>` 展示数据集合,提升 JSF 应用的易用性和开发效率。
58 0
|
3月前
|
应用服务中间件 Java Maven
掌控视图的力量!深入解析 JSF 视图管理,揭秘视图生命周期的秘密,让你的应用更高效!
【8月更文挑战第31天】JavaServer Faces (JSF) 是一种强大的框架,用于管理 Web 应用程序的视图。本文通过具体案例介绍 JSF 视图管理的基础知识,包括创建、管理和销毁视图的过程。首先,在 Eclipse 中创建一个新 JSF 项目,并配置 Maven 依赖。接着,在 `WEB-INF` 目录下配置 `web.xml` 文件,设置 JSF servlet。
54 0
|
3月前
|
UED
JSF文件下载:解锁终极文件传输秘籍,让你的Web应用瞬间高大上!
【8月更文挑战第31天】掌握JSF文件下载功能对构建全面的Web应用至关重要。本文通过具体代码示例,详细介绍如何在JSF中实现文件下载。关键在于后端Bean中的文件读取与响应设置。示例展示了从创建实体类到使用`<h:commandLink>`触发下载的全过程,并通过正确设置响应头和处理文件流,确保文件能被顺利下载。这将显著提升Web应用的实用性与用户体验。
66 0
|
3月前
|
开发者 Java 开发框架
JSF与EJB,打造企业级应用的神器!让你的Web应用更加稳定、高效!
【8月更文挑战第31天】在现代企业级应用开发中,JSF(JavaServer Faces)与EJB(Enterprise JavaBeans)是两大核心技术。JSF作为一款基于Java的Web应用框架,以其丰富的UI组件和表单处理功能著称;EJB则专注于提供分布式事务处理及远程调用等企业级服务。两者的结合为企业应用带来了高效便捷的开发模式。下文将通过一个简单的示例展示如何利用JSF进行用户信息的输入与保存,并借助EJB实现相关业务逻辑。尽管这一组合具有明显优势,但在实际应用中还需考虑其局限性并作出合理选择。
53 0
|
3月前
|
前端开发 UED 开发者
无障碍设计的魔法:JSF让每个用户都能畅游数字世界!
【8月更文挑战第31天】本文介绍如何使用JavaServer Faces (JSF)构建无障碍Web应用,确保所有用户都能访问和使用。文章通过实际代码示例展示了如何利用ARIA属性增强组件、实现键盘导航、提供文本替代以及使用语义化标签等技术。无障碍设计不仅是道德责任,也是提升用户体验的关键。通过这些方法,JSF可以帮助开发者创建更加公平和包容的应用。
33 0
|
3月前
|
Java 前端开发 Spring
技术融合新潮流!Vaadin携手Spring Boot、React、Angular,引领Web开发变革,你准备好了吗?
【8月更文挑战第31天】本文探讨了Vaadin与Spring Boot、React及Angular等主流技术栈的最佳融合实践。Vaadin作为现代Java Web框架,与其他技术栈结合能更好地满足复杂应用需求。文中通过示例代码展示了如何在Spring Boot项目中集成Vaadin,以及如何在Vaadin项目中使用React和Angular组件,充分发挥各技术栈的优势,提升开发效率和用户体验。开发者可根据具体需求选择合适的技术组合。
69 0
|
3月前
|
存储 前端开发 JavaScript
"Angular与AWS Amplify的神奇之处:如何用云端连接技术让你的项目一鸣惊人?"
【8月更文挑战第31天】在现代软件开发中,云端连接的前端应用已成为主流。本文探讨了Angular与AWS Amplify的结合,展示了如何通过示例代码快速构建云端连接的前端应用。Angular是由Google支持的开源前端框架,而AWS Amplify是AWS提供的云服务,两者结合可以快速构建云端连接的前端应用。文中还分享了一些最佳实践,帮助开发者更高效地使用这两种技术构建高性能的云端连接的前端应用。随着Angular和AWS Amplify生态的不断成熟,它们将在未来的Web开发中扮演更加重要的角色。
52 0
|
3月前
|
JavaScript 测试技术
如何在 Angular 中使用 NgTemplateOutlet 创建可重用组件
如何在 Angular 中使用 NgTemplateOutlet 创建可重用组件
25 0