You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular 13+ 如何直接通过组件JS代码实现动态组件加载?

Angular 13+ 直接用JS代码加载动态组件的可行方案

你当前尝试用import()加载字符串形式JS代码的思路不可行——import()仅支持加载符合ES模块规范的文件路径,无法直接解析执行字符串代码。以下是两种可落地的实现方案:


方案1:JIT模式下动态编译组件(灵活适配开发场景)

Angular的JIT(即时编译)模式允许在运行时动态创建并编译组件,完全无需提前打包组件文件。

实现代码

import { Component, ViewChild, ViewContainerRef, Compiler, Injector, NgModule, NgModuleRef } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <div>
      <button (click)="loadDynamicComponent()">Load Dynamic Component</button>
    </div>  
    <ng-template #container></ng-template>
  `
})
export class AppComponent {
  @ViewChild('container', { read: ViewContainerRef })
  container!: ViewContainerRef;

  constructor(private compiler: Compiler, private injector: Injector) {}

  async loadDynamicComponent() {
    // 1. 直接定义组件类与模板
    const DynamicComponent = Component({
      selector: 'app-dynamic',
      template: '<p>my dynamic text works!</p>'
    })(class {
      ngOnInit() {
        console.log('动态组件初始化完成');
      }
    });

    // 2. 创建包含该组件的动态NgModule
    const DynamicModule = NgModule({
      declarations: [DynamicComponent]
    })(class {});

    // 3. 编译模块并创建组件
    const moduleFactory = await this.compiler.compileModuleAsync(DynamicModule);
    const moduleRef: NgModuleRef<any> = moduleFactory.create(this.injector);
    
    this.container.clear();
    const componentFactory = moduleRef.componentFactoryResolver.resolveComponentFactory(DynamicComponent);
    this.container.createComponent(componentFactory, undefined, moduleRef.injector);
  }
}

配置说明

需要在angular.json中关闭AOT编译:

{
  "projects": {
    "your-project-name": {
      "architect": {
        "build": {
          "options": {
            "aot": false
          }
        }
      }
    }
  }
}

或在main.ts改用JIT启动方式:

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';

platformBrowserDynamic().bootstrapModule(AppModule)
  .catch(err => console.error(err));

注:JIT模式会增加应用体积,不建议在生产环境大规模使用。


方案2:AOT模式下嵌入预编译组件代码(适配生产环境)

在生产常用的AOT(提前编译)模式下,可将组件编译后的代码直接嵌入主应用,彻底避免服务器请求。

实现代码

import { Component, ViewChild, ViewContainerRef, Injector, NgModule, createNgModuleRef } from '@angular/core';
import { ɵɵdefineComponent, ɵɵelement, ɵɵtext } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <div>
      <button (click)="loadDynamicComponent()">Load Dynamic Component</button>
    </div>  
    <ng-template #container></ng-template>
  `
})
export class AppComponent {
  @ViewChild('container', { read: ViewContainerRef })
  container!: ViewContainerRef;

  constructor(private injector: Injector) {}

  loadDynamicComponent() {
    // 1. 嵌入AOT编译后的组件代码
    class DynamicComponent {
      ngOnInit() {
        console.log('动态组件初始化完成');
      }
    }

    // Angular内部标识,需与AOT编译输出格式一致
    DynamicComponent.ɵfac = function (t) { return new (t || DynamicComponent)(); };
    DynamicComponent.ɵcmp = ɵɵdefineComponent({
      type: DynamicComponent,
      selectors: [["app-dynamic"]],
      decls: 2,
      vars: 0,
      template: function (rf, ctx) {
        if (rf & 1) {
          ɵɵelement(0, "p");
          ɵɵtext(1, "my dynamic text works!");
        }
      },
      encapsulation: 2
    });

    // 2. 创建动态模块并加载组件
    const DynamicModule = NgModule({
      declarations: [DynamicComponent]
    })(class {});

    this.container.clear();
    const moduleRef = createNgModuleRef(DynamicModule, this.injector);
    this.container.createComponent(DynamicComponent, undefined, moduleRef.injector);
  }
}

注意事项

  • 代码中使用了Angular私有API(如ɵɵdefineComponent),这类API可能随Angular版本更新发生变化,需注意版本兼容性。
  • 若追求更稳定的实现,可提前将组件编译为工厂类,打包进主应用后直接导入使用。

内容的提问来源于stack exchange,提问作者Joe Almore

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 04:47:22