Angular2 多級注入器詳解及實例
angular2 的依賴注入包含了太多的內(nèi)容,其中的一個重點就是注入器,而注入器又非常難理解,今天我們不深入介紹注入器的內(nèi)容,可以參考官方文檔,我們今天來說注入器的層級。
也就是組件獲取服務(wù)的容器會選擇具體哪一個。
先簡單介紹一個背景:有3個組件AppComponent 根組件、DetailList組件 ( 日志列表組件)、Detail組件( 日志組件)。
這三個組件會形成一個組件樹,對應(yīng)的我們也可以認為每個組件都會有一個獨立的注入器(有時候不會出現(xiàn),但是可以這么認為)。
加入一個日志服務(wù)LoggerService,如果按照我們普通的入門方式,在根模塊providers 中提供LoggerService。那么在整個應(yīng)用程序中,LoggerService只有一個實例,什么意思呢?就是說無論在哪個組件,獲取到的都是首次創(chuàng)建的LoggerService,所有組件共用一個服務(wù)實例,這有時候會是一個有用的特性,比如我們使用的全局配置。
全局唯一不是我們這次要驗證的重點,因為這個太普通,我們這次要說明的是我們?nèi)绾卧诿總€組件中都獲取單獨的LoggerService實例,即每個組件的實例都不同。這個就需要對ng2的依賴注入有所了解才可以。
我們逐步來說明如何實現(xiàn)?
為了便于看到這篇短文的同學(xué)有所了解,我加入一些基礎(chǔ)代碼。
1.app.module.ts 應(yīng)用程序根模塊。注意此處我們沒有在Providers中注冊loggerService。當(dāng)然注冊了通過后面的方法也可以達到我們的目的。
import { NgModule, Optional, SkipSelf, ReflectiveInjector} from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; /* App Root */ import { AppComponent } from './app.component'; import { routing } from './app.routing'; import { Title } from '@angular/platform-browser'; import {MessagesModule, GrowlModule, ButtonModule}from 'primeng/primeng'; import {AppDetailComponent}from './app-detail.component'; import {AppDetailListComponent}from './app-detailList.component'; import {LoggerService}from './logger.service'; let allTitle:string="郭志奇"; @NgModule({ imports: [ BrowserModule, MessagesModule, GrowlModule, ButtonModule ], declarations: [AppComponent, AppDetailComponent, AppDetailListComponent],//聲明當(dāng)前模塊需要的指定 組件信息 exports: [], providers: [Title], bootstrap: [AppComponent] }) export class AppModule { constructor( @Optional() @SkipSelf() parentModule: AppModule) { console.log(parentModule); if (parentModule) { throw new Error( 'AppModule is already loaded. Import it in the AppModule only'); } } }
2.app.component.ts 應(yīng)用程序根組件
import { Component, ViewEncapsulation, Host, ViewContainerRef, ReflectiveInjector } from '@angular/core'; import { Title } from '@angular/platform-browser'; import { Message } from 'primeng/primeng'; import {LoggerService}from './logger.service'; @Component({ selector: 'my-app', moduleId: module.id, templateUrl: './app.component.html', providers: [ { provide: LoggerService, useClass: LoggerService } ] }) export class AppComponent { subtitle = '(Final)'; private msgs: Message[]; constructor(private title: Title, @Host() private logger: LoggerService) { this.title.setTitle("AppComponent"); } show(): void { this.logger.Debug(); } }
請注意,我們在跟組件中providers中注冊了LoggerService。
3.app.detailList.ts 日志列表中providers中也注冊了LoggerService
import {Component, Host}from '@angular/core'; import {LoggerService}from './logger.service'; @Component({ selector: 'my-detailList', templateUrl: './app-detailList.component.html', moduleId: module.id, providers: [ { provide: LoggerService, useClass: LoggerService } ] }) export class AppDetailListComponent { constructor( private logger: LoggerService) { } show(): void { this.logger.Debug(); } }
4.app.detail.ts 日志組件providers沒有注冊LoggerService。
import {Component, Host}from '@angular/core'; import {LoggerService}from './logger.service'; @Component({ selector: 'detail', moduleId: module.id, templateUrl: './app-detail.component.html', providers: [ // { provide: LoggerService, useClass: LoggerService } ] }) export class AppDetailComponent { constructor( private logger: LoggerService) { } show(): void { this.logger.Debug(); } }
現(xiàn)在我們通過chrome來看一下 LoggerService的層級關(guān)系。
通過查看依賴關(guān)系圖,我們可以看到AppComponent組件使用了單獨的LoggerService,DetailList組件也使用單獨的LoggerService 實例,而Detail組件使用的是父組件DetailList的LoggerService實例。
目前來看沒有達到我們的要求,我們的要求是每個組件都有單獨的LoggerService實例,那么我們假設(shè)Detail組件的providers是我們忘記輸入的,很難測試出原因所在。那么我們加入一個@Host()來限制注入器的查找范圍。
對于注入器的向上查找方式,請參考官方文檔。
為了便于調(diào)試,我們加入@Host().
@Host 裝飾器將把往上搜索的行為截止在 宿主組件
detail.ts 提示detail組件加入@Host()裝飾器
import {Component, Host}from '@angular/core'; import {LoggerService}from './logger.service'; @Component({ selector: 'detail', moduleId: module.id, templateUrl: './app-detail.component.html', providers: [ // { provide: LoggerService, useClass: LoggerService } ] }) export class AppDetailComponent { constructor( @Host() private logger: LoggerService) { } show(): void { this.logger.Debug(); } }
會提示找不到LoggerService的實例,@Host()的作用就是限制注入器查找到當(dāng)前組件就停止,不會繼續(xù)往上查找。所以會出現(xiàn)找不到Providers的錯誤。
加上providers 的結(jié)果就是我們想要的了。
完美的解決了多組件使用單獨服務(wù)實例的問題。
總結(jié):
1.如果要使組件單獨使用服務(wù),那么首先要在providers 中單獨注冊該服務(wù)。很容易理解
2.為了更好的檢測可能出現(xiàn)的問題,在組件服務(wù)上加入@Host()裝飾器,可以盡量早的拋出錯誤信息
3.使用ng2的debug工具
4.要明確各組件之間的關(guān)系,因為不同的組件關(guān)系會導(dǎo)致服務(wù)的實例的不同
5.服務(wù)盡量是模塊級,不是應(yīng)用級。
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
相關(guān)文章
AngularJS實現(xiàn)根據(jù)變量改變動態(tài)加載模板的方法
這篇文章主要介紹了AngularJS實現(xiàn)根據(jù)變量改變動態(tài)加載模板的方法,結(jié)合實例形式簡單分析了AngularJS動態(tài)加載模板的主要操作技巧與模板實現(xiàn)代碼,需要的朋友可以參考下2016-11-11AngularJS實現(xiàn)動態(tài)編譯添加到dom中的方法
這篇文章主要介紹了AngularJS實現(xiàn)動態(tài)編譯添加到dom中的方法,結(jié)合實例形式分析了AngularJS動態(tài)編輯構(gòu)建模板的相關(guān)操作技巧,需要的朋友可以參考下2016-11-11AngularJS ng-bind 指令簡單實現(xiàn)
本文主要介紹AngularJS ng-bind 指令,在這里對ng-bind 指令做了詳細資料整理并講解,提供了實例代碼以便大家參考,有需要的小伙伴可以參考下2016-07-07Angularjs 實現(xiàn)動態(tài)添加控件功能
這篇文章主要介紹了Angularjs 實現(xiàn)動態(tài)添加控件功能,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-05-05Angular 2應(yīng)用的8個主要構(gòu)造塊有哪些
這篇文章主要為大家詳細介紹了Angular 2應(yīng)用的8個主要構(gòu)造塊,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-10-10