上一篇文章寫到:
input元件的方式,可以擴充套件為依靠服務在業務模組中進行配置,以達到每個模組所用的同一個公共元件擁有不同的互動。
但經過具體實踐發現,在惰性載入模組進行配置是可行的;在急性載入模組配置是會出事的!
結合官網的這篇文件可以一窺究竟:Angular - 多級依賴注入器,可以從“元素注入器”讀起。 那其實有一句挺有意思的:
在不同層次上重新配置一個或多個提供商的能力,開啟了一些既有趣又有用的可能性。
關鍵
那是時候展現真正的技術了。完整程式碼
預備知識
服務提供商
做個比喻:打電話可以視為電信提供的一個服務,那麼電信就可以視為打電話這個服務的提供商。假如就電信這麼一個公司,沒有它就沒法使用打電話的服務。那麼需要使用服務就需要服務提供商。
再經過層層“代理”,模組可以提供服務,元件也可以提供服務。它們在各自的範圍內,提供服務。
服務的分類
以下示例均採用可以搖樹優化的方式提供服務;元件提供的除外,因為一般上,元件會需要使用服務的方法或資料,若採用此方式,則會造成迴圈依賴。
建議:將服務放到最頂層的業務模組或元件中提供,在其子元件中,通過注入器冒泡的特性去獲取該服務的例項或方法或值。
1.單例服務
在 Angular 中有兩種方式來生成單例服務:宣告該服務應該在應用的根上提供。把該服務包含在 AppModule 或某個只會被 AppModule 匯入的模組中。
// 前者
@Injectable({
providedIn: 'root'
})
// 抽離core模組是目前看到的官網最佳實踐
@NgModule({
imports: [
CommonModule
],
declarations: [],
providers: [ShareModuleConfigService],
})
export class CoreModule { }
@NgModule({
imports: [
CoreModule,
// ....
],
declarations: [AppComponent],
bootstrap: [AppComponent],
providers: []
})
export class AppModule { }
複製程式碼
2.模組級服務:
@Injectable({
providedIn: EagerlyLoadedModule
})複製程式碼
3.元件級服務
@Component({
selector: 'app-index',
templateUrl: './index.component.html',
styleUrls: ['./index.component.css'],
providers: [IndexService]
})複製程式碼
樣例
資料夾結構。子模組預設頁IndexComponent
1.準備工作
(1)根元件中擁有helloComponent
(2)各子模組的Index.component.html內也有helloComponent
(3)share模組中的helloComponent將使用ShareModuleConfigService內的值進行顯示
export class HelloComponent implements OnInit {
@Input() txt: string;
constructor(
// 可選的服務
@Optional() private config: ShareModuleConfigService ) {}
ngOnInit() {
this.txt = this.config ? this.config.helloCompTxt : null;
}
}複製程式碼
(4)我們還有一個由coreModule提供的單例服務ShareModuleConfigService(將share模組可配置的集中於此,供各模組靈活配置),修改此配置來達到自定義share模組的某些展示或互動。
@Injectable()
export class ShareModuleConfigService {
helloCompTxt: string;
data = [1];
constructor() {
console.log('ShareModuleConfigService constructor');
}
}複製程式碼
(5)均通過useValue的方式簡單的配置一下:
providers: [
{
provide: ShareModuleConfigService,
useValue: {
helloCompTxt: '惰性模組搞一下hello元件',
data: [4]
}
}
]複製程式碼
(6)我們將在頁面上看到在不同層級下的helloComponent的展示效果。
2.惰性載入模組內配置
首先將樣例程式碼中AppModule中imports中註釋掉EagerlyLoadedModule,將會看到這樣的執行效果。
根元件展示了ShareModuleConfigService的初始值
然後,點選”去懶載入模組(惰性載入模組)“,將會看到:
經過惰性模組修改後,初始值被改變了,實現了模組級配置
再來修改下lazy-loaded中的Index.component.ts,我已寫好,只要把註釋去掉即可。那麼將會看到這樣的效果。
元件的配置,”覆蓋“掉了模組內的配置
還有一點值得注意:根元件所使用的值未變化,可以理解為惰性模組將單例服務又例項化了一次。將兩者完全隔離開了。由此可以達到各個惰性模組內擁有自己的配置,以將share模組內的元件、指令、管道實現不同的互動或功能。
3.急性模組內修改配置
一如之前的流程,但一開始將會看到不一樣結果。去掉AppModule中之前的註釋。將急性模組載入到應用裡來。
根元件的值直接被修改了
然後,將AppModule中的將CoreModule放在最後
根元件的值並未發生改變
是不是很神奇?其實官方已經給出解釋,讓我們來看一看。
根AppModule匯入了CoreModule,並把它的providers新增到了AppModule的服務提供商中。 特別是,Angular 會在@NgModule.providers前面新增這些匯入的服務提供商。 這種順序保證了AppModule中的服務提供商總是會優先於那些從其它模組中匯入的服務提供商
由此,若是想保證單例服務的唯一性,就必須將CoreModule置於所有其餘模組的後面,以免被急性模組干擾。
子元件的配置就不再提了,跟惰性模組是一樣的。說了這麼多,本文提到的點還是蠻多的。現在來總結一下:
1.惰性模組若需配置share模組:利用惰性模組新建例項的性質,在模組內直接配置。
2.急性模組若需配置share模組,則不能在模組內進行配置,要麼會被單例服務覆蓋,要麼會覆蓋單例服務。所以可以將配置提到該模組的根元件內以達到此效果。
3.由急性模組中的元件修改單例服務的值,根模組中的值其實並未變化的現象。可以看出,在Angular中值的流動其實是從上到下單向流動的。就像一顆倒置的樹,營養(資料)從根(根元件)傳遞到各個樹枝上。
參考: