部件开发套件 Component Dev Kit (CDK)

lxf2023-03-10 20:29:01

部件开发套件 Component Dev Kit (CDK)

以前推荐过原生态 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其他类似文章!