Angular-多級配置搞事情啦

Wuyang發表於2019-04-28
上一篇文章寫到:
input元件的方式,可以擴充套件為依靠服務在業務模組中進行配置,以達到每個模組所用的同一個公共元件擁有不同的互動。
但經過具體實踐發現,在惰性載入模組進行配置是可行的;在急性載入模組配置是會出事的!
結合官網的這篇文件可以一窺究竟:Angular - 多級依賴注入器,可以從“元素注入器”讀起。 那其實有一句挺有意思的:
在不同層次上重新配置一個或多個提供商的能力,開啟了一些既有趣又有用的可能性。
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]
  })複製程式碼

樣例

Angular-多級配置搞事情啦
資料夾結構。子模組預設頁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,將會看到這樣的執行效果。
Angular-多級配置搞事情啦
根元件展示了ShareModuleConfigService的初始值
然後,點選”去懶載入模組(惰性載入模組)“,將會看到:
Angular-多級配置搞事情啦
經過惰性模組修改後,初始值被改變了,實現了模組級配置
再來修改下lazy-loaded中的Index.component.ts,我已寫好,只要把註釋去掉即可。那麼將會看到這樣的效果。
Angular-多級配置搞事情啦
元件的配置,”覆蓋“掉了模組內的配置
還有一點值得注意:根元件所使用的值未變化,可以理解為惰性模組將單例服務又例項化了一次。將兩者完全隔離開了。由此可以達到各個惰性模組內擁有自己的配置,以將share模組內的元件、指令、管道實現不同的互動或功能。
3.急性模組內修改配置
一如之前的流程,但一開始將會看到不一樣結果。去掉AppModule中之前的註釋。將急性模組載入到應用裡來。
Angular-多級配置搞事情啦
根元件的值直接被修改了
然後,將AppModule中的將CoreModule放在最後
Angular-多級配置搞事情啦
根元件的值並未發生改變
是不是很神奇?其實官方已經給出解釋,讓我們來看一看。
根AppModule匯入了CoreModule,並把它的providers新增到了AppModule的服務提供商中。 特別是,Angular 會在@NgModule.providers前面新增這些匯入的服務提供商。 這種順序保證了AppModule中的服務提供商總是會優先於那些從其它模組中匯入的服務提供商
由此,若是想保證單例服務的唯一性,就必須將CoreModule置於所有其餘模組的後面,以免被急性模組干擾。
子元件的配置就不再提了,跟惰性模組是一樣的。說了這麼多,本文提到的點還是蠻多的。現在來總結一下:
1.惰性模組若需配置share模組:利用惰性模組新建例項的性質,在模組內直接配置。
2.急性模組若需配置share模組,則不能在模組內進行配置,要麼會被單例服務覆蓋,要麼會覆蓋單例服務。所以可以將配置提到該模組的根元件內以達到此效果。
3.由急性模組中的元件修改單例服務的值,根模組中的值其實並未變化的現象。可以看出,在Angular中值的流動其實是從上到下單向流動的。就像一顆倒置的樹,營養(資料)從根(根元件)傳遞到各個樹枝上。

參考:


相關文章