在Single SPA中实现Angular与Angular-parcel多组件条件化调用
实现Angular应用动态切换Single SPA Parcel中的组件
我已搭建两个应用:angular-parcel应用与Angular应用,并将二者均挂载至Single SPA根应用中。随后通过single-spa将angular-parcel应用挂载到Angular应用内,现有实现代码如下:
angular-parcel 的 main.single-spa.ts 文件
import { enableProdMode, NgZone } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { singleSpaAngular } from 'single-spa-angular'; import { AppModule } from './app/app.module'; import { environment } from './environments/environment'; import { singleSpaPropsSubject } from './single-spa/single-spa-props'; import { ParcelModuleModule } from './app/parcel-module/parcel-module.module'; if (environment.production) { enableProdMode(); } const lifecycles = singleSpaAngular({ bootstrapFunction: (singleSpaProps) => { return platformBrowserDynamic().bootstrapModule(AppModule); }, template: '<app-parcel />', NgZone, }); export const name = 'angular-parcel'; export const bootstrap = lifecycles.bootstrap; export const mount = lifecycles.mount; export const unmount = lifecycles.unmount;
Angular应用的 app.component.ts 文件
import { Component } from '@angular/core'; import { mountRootParcel } from 'single-spa'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent { title = 'angular-app'; mountRootParcel = mountRootParcel; parcelProps = { customProp1: 'Parent prop1' }; target = document.body; async ngconfig() { return (window as any).System.import('@dist/angular-parcel'); } ngparcelMounted():void { console.log('Angular parcel mounted'); } }
Angular应用的 app.component.html 文件
<parcel [config]="ngconfig" [mountParcel]="mountRootParcel" [customProps]="parcelProps" wrapWith="h1" [onParcelMount]="ngparcelMounted" [appendTo]="target" domElement="app-sub-parcel" ></parcel>
Angular应用的 app.module.ts 文件
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppRoutingModule } from './app-routing.module'; import { ParcelComponent } from 'single-spa-angular/parcel'; import { AppComponent } from './app.component'; @NgModule({ declarations: [AppComponent], imports: [BrowserModule, AppRoutingModule, ParcelComponent], providers: [], bootstrap: [AppComponent], }) export class AppModule {}
当前需求:angular-parcel应用的AppModule中包含多个组件,但目前默认仅展示第一个组件,希望能在Angular应用中根据条件调用其他组件。
解决方案
步骤1:修改angular-parcel应用,支持根据传入参数动态切换组件
传递Single SPA Props到应用内部
修改main.single-spa.ts中的bootstrapFunction,将父应用传入的props传递给singleSpaPropsSubject,让应用内部可以监听props变化:bootstrapFunction: (singleSpaProps) => { // 新增:将props传入subject,供内部组件订阅 singleSpaPropsSubject.next(singleSpaProps); return platformBrowserDynamic().bootstrapModule(AppModule); },在angular-parcel根组件中实现动态渲染逻辑
修改angular-parcel的app-parcel.component.ts,通过订阅props切换显示的组件:import { Component, OnInit } from '@angular/core'; import { singleSpaPropsSubject } from '../single-spa/single-spa-props'; @Component({ selector: 'app-parcel', template: ` <!-- 根据父组件传入的targetComponent值渲染对应组件 --> <app-component1 *ngIf="currentComponent === 'component1'"></app-component1> <app-component2 *ngIf="currentComponent === 'component2'"></app-component2> <app-component3 *ngIf="currentComponent === 'component3'"></app-component3> ` }) export class AppParcelComponent implements OnInit { // 默认显示第一个组件 currentComponent = 'component1'; ngOnInit() { // 订阅props变化,更新当前要显示的组件 singleSpaPropsSubject.subscribe(props => { if (props.customProps?.targetComponent) { this.currentComponent = props.customProps.targetComponent; } }); } }注意:确保所有需要切换的组件都已在
AppModule的declarations中声明,或导入了对应的子模块。
步骤2:修改Angular父应用,传递控制参数并支持动态更新
更新父组件逻辑,添加组件切换控制
修改Angular应用的app.component.ts,添加组件切换方法并保存parcel实例用于更新:import { Component } from '@angular/core'; import { mountRootParcel } from 'single-spa'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent { title = 'angular-app'; mountRootParcel = mountRootParcel; // 新增targetComponent字段,控制parcel显示哪个组件 parcelProps = { customProp1: 'Parent prop1', targetComponent: 'component1' }; target = document.body; // 保存parcel实例,用于后续更新props parcelInstance: any; async ngconfig() { return (window as any).System.import('@dist/angular-parcel'); } // 更新挂载回调,保存parcel实例 onParcelMounted(parcel: any) { this.parcelInstance = parcel; console.log('Angular parcel mounted'); } // 切换组件并通知parcel更新 switchComponent(componentKey: string) { this.parcelProps.targetComponent = componentKey; // 调用parcel的update方法传递新的props if (this.parcelInstance) { this.parcelInstance.update(this.parcelProps); } } }更新父组件模板,添加切换控件
修改Angular应用的app.component.html,添加按钮或其他控件触发组件切换(可根据业务需求替换为下拉框、条件判断等触发方式):<button (click)="switchComponent('component1')">显示组件1</button> <button (click)="switchComponent('component2')">显示组件2</button> <button (click)="switchComponent('component3')">显示组件3</button> <parcel [config]="ngconfig" [mountParcel]="mountRootParcel" [customProps]="parcelProps" wrapWith="div" [onParcelMount]="onParcelMounted" [appendTo]="target" domElement="app-sub-parcel" ></parcel>
内容的提问来源于stack exchange,提问作者sahil verma
相关产品推荐
相关产品推荐

