Angular能否创建非单例Service?如何实现?
Angular模块间服务独立实例实现方案
完全可行,以下是针对你的需求的具体实现方法:
为什么之前的配置无效
Angular中,预加载(eagerly loaded)模块的@NgModule.providers会被合并到根注入器,因此所有预加载模块共享同一服务实例;只有懒加载模块会创建独立的模块注入器,此时声明在providers中的服务才会生成独立实例。如果你的报表模块是预加载的,自然会出现数据共享的问题。
方案1:使用懒加载模块(适合允许懒加载的场景)
将每个报表模块配置为懒加载,通过路由的loadChildren加载模块,此时每个懒加载模块会拥有独立的注入器,在模块的providers中声明ReportParamsStoreService即可获得独立实例:
- 配置路由:
const routes: Routes = [ { path: 'inss-report', loadChildren: () => import('./inss-report/inss-report.module').then(m => m.InssReportModule) }, { path: 'irrf-report', loadChildren: () => import('./irrf-report/irrf-report.module').then(m => m.IrrfReportModule) }, { path: 'fgts-report', loadChildren: () => import('./fgts-report/fgts-report.module').then(m => m.FgtsReportModule) } ];
- 在每个报表模块的
@NgModule中声明服务:
@NgModule({ declarations: [InssReportComponent], providers: [ReportParamsStoreService] // 懒加载模块会创建独立实例 }) export class InssReportModule { }
方案2:使用providedIn: 'any'(推荐,支持预加载/懒加载模块)
Angular 6+ 提供了providedIn: 'any'选项,该配置会让服务在每个注入器中生成独立实例,无论模块是预加载还是懒加载,无需在模块providers中重复声明:
- 修改服务的装饰器:
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'any' // 关键配置:每个注入器对应一个实例 }) export class ReportParamsStoreService { private reportParams: Record<string, any> = {}; setParam(key: string, value: any): void { this.reportParams[key] = value; } getParam(key: string): any { return this.reportParams[key]; } }
- 在报表模块的组件中直接注入服务即可,每个模块会自动获得独立实例:
import { Component } from '@angular/core'; import { ReportParamsStoreService } from '../report-params-store.service'; @Component({ selector: 'app-inss-report', template: `<button (click)="setParams()">设置INSS参数</button>` }) export class InssReportComponent { constructor(private paramsStore: ReportParamsStoreService) { } setParams(): void { this.paramsStore.setParam('reportType', 'INSS'); // 该参数仅存在于INSS模块的服务实例中 } }
方案3:共享模块forChild模式(适合服务需随共享模块分发的场景)
如果你的服务需要和其他共享组件/指令一起封装在共享模块中,可以通过forChild方法为每个导入模块提供独立实例:
- 创建共享模块:
import { NgModule, ModuleWithProviders } from '@angular/core'; import { ReportParamsStoreService } from './report-params-store.service'; @NgModule({ // 声明共享组件/指令等 }) export class ReportSharedModule { // 静态方法为每个导入模块提供独立服务实例 static forChild(): ModuleWithProviders<ReportSharedModule> { return { ngModule: ReportSharedModule, providers: [ReportParamsStoreService] }; } }
- 每个报表模块导入
ReportSharedModule.forChild():
@NgModule({ declarations: [IrrfReportComponent], imports: [ReportSharedModule.forChild()] }) export class IrrfReportModule { }
以上三种方案都能实现各报表模块服务实例的隔离,无需重复编写服务代码。
内容的提问来源于stack exchange,提问作者Fabio Mendonça
相关产品推荐
相关产品推荐

