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
相关产品推荐
相关产品推荐

