以前推荐过原生态 API 动态化主视图插进,性能上早已能够满足大部分适用场景。但也有一些遗憾,都还没处理在 Angular 运用外插进具体内容的需要,命令也不能和动态性插进的部件有输出的互动。
还好 Angular 官方网带来了一套部件开发套件 Component Dev Kit (CDK),做为各种各样 Angular 组件开发的前提专用工具,其中就给予 “Portal(传送器)” 来协助动态性主视图的建立。
这一 ”动态性主视图“ 能是部件、TemplateRef 或是 DOM 原素,分别对应三种 Portal 种类(ComponentPortal、TemplatePortal、DomPortal)。他们三个的抽象化泛型父类是 Portal<T>
,有三个方式: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
案例。
<ng-template #testTemplate>
<p>一些必须动态性插进内容.</p>
</ng-template>
@ViewChild('testTemplate') templatePortalContent: TemplateRef<any>;
constructor(private _viewContainerRef: ViewContainerRef) { }
ngAfterViewInit() {
this.templatePortal = new TemplatePortal(
this.templatePortalContent,
this._viewContainerRef
);
}
除开根据对象,TemplatePortal 也有一个命令(CdkPortal)能够方便快捷建立。
<ng-template cdkPortal>
<p>一些必须动态性插进内容.</p>
</ng-template>
<!-- 或创作 -->
<!-- 和之前书写是一致的实际效果 -->
<p *cdkPortal>
一些必须动态性插进内容.
</p>
再通过 @ViewChild
就能获得 TemplatePortal
的案例了。
DomPortal
如同上边的实例根据 @ViewChild
获得 Template 案例来建立,相近的都可以获得 ElementRef 来建立动态变化 DOM。
<div #domPortalContent><span>原生态DOM具体内容</span></div>
@ViewChild('domPortalContent') domPortalContent: ElementRef<HTMLElement>;
ngAfterViewInit() {
this.domPortal = new DomPortal(this.domPortalContent);
}
能够动态变化将这一段 DOM 转移至随意部位。需要注意的是,迁移以后,原先的数据绑定,或是关联的命令也许不会继续升级。
插进器皿
前边三种类型的 Portal 都说过能够3D渲染到任何具体位置,那实际怎么渲染呢?
CdkPortOutlet
简单的就是利用 CdkPortOutlet 命令了:
<div>
<ng-template [cdkPortalOutlet]="anyPortal"></ng-template>
</div>
给 anyPortal
传值上边三个中任意的 Portal 案例,都是会动态性3D渲染到所在位置。
和原生态 API 的指令不一样,它会自动判断出哪种类型的 Portal。此外,它还有一个额外事情:attached
,根据这件事情,能够掌握到初始化的部件案例,或是 TemplateRef。这也使得和初始化元件的互动变得十分便捷。
结构器皿案例
不过既然讲了是能够3D渲染到任何具体位置,那自然也就包含 Angular 运用外界,要3D渲染到运用以外,那就需要我们根据对象创建容器案例。
这一容器类便是 DomPortalOutlet
,这是 PortalOutlet
的实现派生类。它结构主要参数通常是:Element(初始化主视图的DOM连接点)、ComponentFactoryResolver(与上篇一样,用于动态性搭建部件)、appRef(现阶段 Angular 运用的总体案例)、Injector(注入器,用以传递依赖)。
constructor(
private viewContainerRef: ViewContainerRef,
@Inject(DOCUMENT) private document: any,
private injector: Injector,
private componentFactoryResolver: ComponentFactoryResolver
) {
// 在<body>下建立外界寄主原素
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<any>('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建立动态内容的具体内容,大量欢迎关注AdminJS其他类似文章!