Angular动态加载组件

最近在看一些无关技术的书:《三体》还有《浪潮之巅》,一直没学啥新东西,工作的内容也轻车熟路,所以最近页没写啥博客。好久没写变得懒散了,还是得坚持这个习惯。

前两天做一个应用市场的功能,每个应用页面都不同,但使用同一个url(要不然得写n个url)。我的思路是,url映射的组件根据url中传入的aapName来动态加载对应的各应用的组件。

参考:

https://segmentfault.com/a/1190000010086185 https://angular.cn/guide/dynamic-component-loader

定义应用的interface

export interface EnterAppComponent {
  data: any;
}

某应用组件具体实现:

@Component({
  selector: 'app-market-app-demo',
  template: `
    ...
  `,
})
export class MarketAppDemoComponent implements OnInit, EnterAppComponent {
  @Input() data;
  constructor(
    private sanitizer: DomSanitizer
  ) { }

  ngOnInit(): void {
  }
}

应用名与组件映射表:

export const appComponentMap = {
  'demoApp': MarketAppDemoComponent,
  ...
};

动态加载组件核心代码:

import { Component, Input, OnInit, ViewChild, ComponentFactoryResolver, ViewContainerRef } from '@angular/core';

@Component({
  selector: 'app-market-enter-app',
  template: `
    <nz-card>
      <ng-template #enterAppContainer></ng-template>
    </nz-card>
  `
})
export class MarketEnterAppComponent implements OnInit {
    appName = this.route.snapshot.params.appName;

    @ViewChild('enterAppContainer', { read: ViewContainerRef }) container: ViewContainerRef;
    constructor(
        private componentFactoryResolver: ComponentFactoryResolver
    ) { }
    loadComponent(appComponent) {
        const componentFactory = this.componentFactoryResolver.resolveComponentFactory(appComponent);
        const componentRef = this.container.createComponent(componentFactory);

        const instance = (<EnterAppComponent>componentRef.instance);
        instance.data = {};
    }

    ngOnInit(): void {
        // 根据appName 动态加载对应组件
        const appComponent = appComponentMap[this.appName];
        if (appComponent) {
          this.loadComponent(appComponent);
        }
    }
}

在获取到实例的时候对实例调用的时候回报‘没有xxx属性’的错误,可以为实例指定类型:

const instance = <EnterAppComponent>componentRef.instance;

类似的还有

// 如果不指定类型回报 没有submit方法
const form = <HTMLFormElement>document.getElementById('form')
form.submit();