Angular2 多級(jí)注入器詳解及實(shí)例
angular2 的依賴(lài)注入包含了太多的內(nèi)容,其中的一個(gè)重點(diǎn)就是注入器,而注入器又非常難理解,今天我們不深入介紹注入器的內(nèi)容,可以參考官方文檔,我們今天來(lái)說(shuō)注入器的層級(jí)。
也就是組件獲取服務(wù)的容器會(huì)選擇具體哪一個(gè)。
先簡(jiǎn)單介紹一個(gè)背景:有3個(gè)組件AppComponent 根組件、DetailList組件 ( 日志列表組件)、Detail組件( 日志組件)。
這三個(gè)組件會(huì)形成一個(gè)組件樹(shù),對(duì)應(yīng)的我們也可以認(rèn)為每個(gè)組件都會(huì)有一個(gè)獨(dú)立的注入器(有時(shí)候不會(huì)出現(xiàn),但是可以這么認(rèn)為)。
加入一個(gè)日志服務(wù)LoggerService,如果按照我們普通的入門(mén)方式,在根模塊providers 中提供LoggerService。那么在整個(gè)應(yīng)用程序中,LoggerService只有一個(gè)實(shí)例,什么意思呢?就是說(shuō)無(wú)論在哪個(gè)組件,獲取到的都是首次創(chuàng)建的LoggerService,所有組件共用一個(gè)服務(wù)實(shí)例,這有時(shí)候會(huì)是一個(gè)有用的特性,比如我們使用的全局配置。
全局唯一不是我們這次要驗(yàn)證的重點(diǎn),因?yàn)檫@個(gè)太普通,我們這次要說(shuō)明的是我們?nèi)绾卧诿總€(gè)組件中都獲取單獨(dú)的LoggerService實(shí)例,即每個(gè)組件的實(shí)例都不同。這個(gè)就需要對(duì)ng2的依賴(lài)注入有所了解才可以。
我們逐步來(lái)說(shuō)明如何實(shí)現(xiàn)?
為了便于看到這篇短文的同學(xué)有所了解,我加入一些基礎(chǔ)代碼。
1.app.module.ts 應(yīng)用程序根模塊。注意此處我們沒(méi)有在Providers中注冊(cè)loggerService。當(dāng)然注冊(cè)了通過(guò)后面的方法也可以達(dá)到我們的目的。
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(); } }
請(qǐng)注意,我們?cè)诟M件中providers中注冊(cè)了LoggerService。
3.app.detailList.ts 日志列表中providers中也注冊(cè)了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沒(méi)有注冊(cè)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)在我們通過(guò)chrome來(lái)看一下 LoggerService的層級(jí)關(guān)系。
通過(guò)查看依賴(lài)關(guān)系圖,我們可以看到AppComponent組件使用了單獨(dú)的LoggerService,DetailList組件也使用單獨(dú)的LoggerService 實(shí)例,而Detail組件使用的是父組件DetailList的LoggerService實(shí)例。
目前來(lái)看沒(méi)有達(dá)到我們的要求,我們的要求是每個(gè)組件都有單獨(dú)的LoggerService實(shí)例,那么我們假設(shè)Detail組件的providers是我們忘記輸入的,很難測(cè)試出原因所在。那么我們加入一個(gè)@Host()來(lái)限制注入器的查找范圍。
對(duì)于注入器的向上查找方式,請(qǐng)參考官方文檔。
為了便于調(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(); } }
會(huì)提示找不到LoggerService的實(shí)例,@Host()的作用就是限制注入器查找到當(dāng)前組件就停止,不會(huì)繼續(xù)往上查找。所以會(huì)出現(xiàn)找不到Providers的錯(cuò)誤。
加上providers 的結(jié)果就是我們想要的了。
完美的解決了多組件使用單獨(dú)服務(wù)實(shí)例的問(wèn)題。
總結(jié):
1.如果要使組件單獨(dú)使用服務(wù),那么首先要在providers 中單獨(dú)注冊(cè)該服務(wù)。很容易理解
2.為了更好的檢測(cè)可能出現(xiàn)的問(wèn)題,在組件服務(wù)上加入@Host()裝飾器,可以盡量早的拋出錯(cuò)誤信息
3.使用ng2的debug工具
4.要明確各組件之間的關(guān)系,因?yàn)椴煌慕M件關(guān)系會(huì)導(dǎo)致服務(wù)的實(shí)例的不同
5.服務(wù)盡量是模塊級(jí),不是應(yīng)用級(jí)。
感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
相關(guān)文章
AngularJS實(shí)現(xiàn)根據(jù)變量改變動(dòng)態(tài)加載模板的方法
這篇文章主要介紹了AngularJS實(shí)現(xiàn)根據(jù)變量改變動(dòng)態(tài)加載模板的方法,結(jié)合實(shí)例形式簡(jiǎn)單分析了AngularJS動(dòng)態(tài)加載模板的主要操作技巧與模板實(shí)現(xiàn)代碼,需要的朋友可以參考下2016-11-11AngularJS實(shí)現(xiàn)動(dòng)態(tài)編譯添加到dom中的方法
這篇文章主要介紹了AngularJS實(shí)現(xiàn)動(dòng)態(tài)編譯添加到dom中的方法,結(jié)合實(shí)例形式分析了AngularJS動(dòng)態(tài)編輯構(gòu)建模板的相關(guān)操作技巧,需要的朋友可以參考下2016-11-11AngularJS ng-bind 指令簡(jiǎn)單實(shí)現(xiàn)
本文主要介紹AngularJS ng-bind 指令,在這里對(duì)ng-bind 指令做了詳細(xì)資料整理并講解,提供了實(shí)例代碼以便大家參考,有需要的小伙伴可以參考下2016-07-07Angularjs 實(shí)現(xiàn)動(dòng)態(tài)添加控件功能
這篇文章主要介紹了Angularjs 實(shí)現(xiàn)動(dòng)態(tài)添加控件功能,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-05-05Angular 2應(yīng)用的8個(gè)主要構(gòu)造塊有哪些
這篇文章主要為大家詳細(xì)介紹了Angular 2應(yīng)用的8個(gè)主要構(gòu)造塊,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10Angular實(shí)現(xiàn)下載安裝包的功能代碼分享
本文通過(guò)實(shí)例代碼給大家介紹了angular實(shí)現(xiàn)下載安裝包的功能以及基于angularjs代碼實(shí)現(xiàn)錨點(diǎn)跳轉(zhuǎn)的功能,需要的朋友參考下吧2017-09-09AngularJS中的指令實(shí)踐開(kāi)發(fā)指南(二)
這篇文章主要介紹了AngularJS中的指令實(shí)踐指南(二)的相關(guān)資料,需要的朋友可以參考下2016-03-03