Angular 6如何从懒加载模块中加载并显示组件?
解决Angular 6懒加载库组件无法通过MatDialog打开的问题
我之前也碰到过类似的Angular懒加载库组件配合MatDialog使用的坑,你的思路方向是对的,只是没get到懒加载模块的核心细节:懒加载模块会创建独立的模块引用(NgModuleRef),它的组件工厂只存在于自身的ComponentFactoryResolver中,根模块的注入器和组件工厂池根本找不到这些组件。下面给你两种可行的解决方案:
方案一:直接从懒加载模块引用中获取组件工厂
这个方案是基于你现有代码的改造,核心是拿到懒加载模块的组件解析器,再用它来获取目标组件的工厂,最后传给MatDialog。
步骤1:保存懒加载模块的引用
修改你在AppComponent里的load()方法,把创建好的模块引用保存下来:
import { NgModuleRef } from '@angular/core'; // 新增变量保存模块引用 private chatModuleRef: NgModuleRef<any>; constructor(private _injector: Injector, private loader: SystemJsNgModuleLoader, public dialog: MatDialog) {} load() { this.loader.load('dist/org/chat#ChatModule').then(moduleFactory => { // 保存模块引用 this.chatModuleRef = moduleFactory.create(this._injector); }); }
步骤2:用模块内的组件工厂打开对话框
新增打开对话框的方法,从保存的模块引用中获取组件工厂,再传给MatDialog:
openChatPopup() { // 先判断模块是否已加载 if (!this.chatModuleRef) { alert('请先加载聊天模块'); // 或者自动触发加载:this.load().then(() => this.openChatPopup()); return; } // 从懒加载模块中获取组件解析器 const resolver = this.chatModuleRef.componentFactoryResolver; // 获取ChatPopupComponent的组件工厂 const chatPopupFactory = resolver.resolveComponentFactory(ChatPopupComponent); // 用组件工厂打开对话框 const dialogRef = this.dialog.open(chatPopupFactory, { data: {} }); }
方案二:封装成模块内服务(更优雅)
如果想让主应用完全不用关心懒加载的细节,可以在你的@org/chat库中封装一个服务,专门负责加载模块和打开对话框,这样主应用只需要调用服务方法即可。
步骤1:在ChatModule中创建ChatService
import { Injectable, Inject, NgModuleRef, ComponentFactoryResolver } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { SystemJsNgModuleLoader, SYSTEM_JS_NG_MODULE_LOADER } from '@angular/core'; import { ChatPopupComponent } from './chat-popup.component'; @Injectable({ providedIn: 'root' // 或者在ChatModule的providers中声明 }) export class ChatService { private chatModuleRef: NgModuleRef<any>; constructor( private dialog: MatDialog, private injector: Injector, @Inject(SYSTEM_JS_NG_MODULE_LOADER) private loader: SystemJsNgModuleLoader ) {} async openChatDialog() { // 懒加载模块(仅第一次加载) if (!this.chatModuleRef) { const moduleFactory = await this.loader.load('dist/org/chat#ChatModule'); this.chatModuleRef = moduleFactory.create(this.injector); } // 获取组件工厂并打开对话框 const resolver = this.chatModuleRef.componentFactoryResolver; const factory = resolver.resolveComponentFactory(ChatPopupComponent); this.dialog.open(factory, { data: {} }); } }
步骤2:主应用中调用服务
在AppComponent中注入ChatService,直接调用方法即可:
constructor(private chatService: ChatService) {} openChat() { this.chatService.openChatDialog(); }
关键注意事项
- 确保
ChatPopupComponent在ChatModule的declarations和entryComponents中声明(Angular 6必须加entryComponents,Angular 9+可以省略,但为了兼容建议加上),并且要在模块中导出该组件:@NgModule({ declarations: [ChatPopupComponent], entryComponents: [ChatPopupComponent], exports: [ChatPopupComponent] }) export class ChatModule {} - 不要在
AppModule中导入ChatModule,否则就失去了懒加载的意义。
为什么你之前的方法不行?
- 直接导入组件:因为
AppModule没有导入ChatModule,Angular编译器无法识别该组件所属的模块,所以报错“Component is not part of any NgModule”。 - 用字符串名称打开:MatDialog默认会去根注入器的
ComponentFactoryResolver中查找组件工厂,而懒加载模块的组件工厂只存在于自身的模块引用中,根注入器根本找不到,所以报错“No component factory found”。
内容的提问来源于stack exchange,提问作者dev7
相关产品推荐
相关产品推荐

