概要
依赖注入是Angular框架的重要组成部分。如果将root模块比作树的根节点,Angular 应用程序有多个依赖注入器,组织成一个与组件树平行的树状结构。每个注入器都会创建依赖的一个单例。
默认情况下,对于依赖注入的对象,Angular会先从当前组件的注入器中开始查找,经历父组件注入器,当前模块注入器和根模块注入器。直到找到需要依赖注入的对象。
@Self和@Host装饰器主要用于大型多团队的开发项目,对上述的依赖注入对象的搜索过程进行限定,避免错误引用。
@Self和@Host装饰器定义上比较类似,本文通过一个获取当前时间的例子,说明他们的区别。
实例说明
定义组件journalist,interview,report和article和模块journalist,其中journalist包含interview组件,interview包含report和article组件。所有组件均在journalist模块下。
report组件的构造函数采用@Self装饰器,article组件采用@Host装饰器修饰。
定义服务类DatetimeService,该类包含方法 getDateTime()获取当前日期和时间。
上述关键代码见附录。
实验1 将DatetimeService放到report和article注入器中
实验结果如下所示,两个组件都可以获取当前时间。
实验2 将DatetimeService放到父组件interview的注入器中
实验结果如下所示,只有article组件获取到了时间。
实验3 将DatetimeService放到父组件journalist的注入器中
实验结果同实验2
实验4 将DatetimeService放到journalist模块的注入器中
实验结果同实验2
结论
@Self装饰器规定只能在当前组件的注入器中查找被注入的对象,而@Host装饰器则允许在整个父组件树对应的注入器中查找被注入的对象。
附录
- journalist模块代码
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { JournalistComponent } from './journalist.component';
import { InterviewComponent } from '../interview/interview.component';
import { ReportComponent } from '../report/report.component';
import { ArticleComponent } from '../article/article.component';
import { DatetimeService } from 'src/app/services/datetime.service';
@NgModule({
declarations: [
JournalistComponent,
InterviewComponent,
ReportComponent,
ArticleComponent,
],
imports: [CommonModule],
// providers: [DatetimeService],
exports: [
JournalistComponent,
InterviewComponent,
ReportComponent,
ArticleComponent,
],
})
export class JournalistModule {}
- journalist组件的ts和html代码
import { Component, OnInit, Host, Optional } from '@angular/core';
import { DatetimeService } from 'src/app/services/datetime.service';
@Component({
selector: 'app-journalist',
templateUrl: './journalist.component.html',
styleUrls: ['./journalist.component.scss'],
// providers: [DatetimeService],
})
export class JournalistComponent implements OnInit {
constructor() {}
ngOnInit(): void {}
}
<div class="col-md-6">
<ng-content></ng-content>
</div>
- interview组件的ts和html代码
import { Component, OnInit, Host, Optional } from '@angular/core';
import { DatetimeService } from 'src/app/services/datetime.service';
@Component({
selector: 'app-interview',
templateUrl: './interview.component.html',
styleUrls: ['./interview.component.scss'],
// providers: [DatetimeService],
})
export class InterviewComponent implements OnInit {
constructor() {}
ngOnInit(): void {}
}
<ng-content></ng-content>
- article组件的ts和html代码
import { Component, OnInit, Self, Optional, Host } from '@angular/core';
import { DatetimeService } from 'src/app/services/datetime.service';
@Component({
selector: 'app-article',
templateUrl: './article.component.html',
styleUrls: ['./article.component.scss'],
// providers: [DatetimeService],
})
export class ArticleComponent implements OnInit {
ngOnInit(): void {
throw new Error('Method not implemented.');
}
alertClass: string = 'alert-danger';
alertInfo: string = 'Datetime Service is not loaded in ReportComponent.';
constructor(
@Host()
@Optional()
private datetimeService: DatetimeService
) {
if (this.datetimeService != null) {
this.alertClass = 'alert-success';
this.alertInfo = this.datetimeService.getDateTime();
}
this.alertInfo =
'I am ArticleComponent and using @Host to loacate service. ' +
this.alertInfo;
}
}
<div class="alert" [class]="alertClass" role="alert">
{{ alertInfo }}
</div>
- report组件的ts和html代码
import { Component, OnInit, Host, Optional, Self } from '@angular/core';
import { DatetimeService } from 'src/app/services/datetime.service';
@Component({
selector: 'app-report',
templateUrl: './report.component.html',
styleUrls: ['./report.component.scss'],
// providers: [DatetimeService],
})
export class ReportComponent implements OnInit {
alertClass: string = 'alert-danger';
alertInfo: string = 'Datetime Service is not loaded in ReportComponent.';
constructor(
@Self()
@Optional()
private datetimeService: DatetimeService
) {
if (this.datetimeService != null) {
this.alertClass = 'alert-success';
this.alertInfo = this.datetimeService.getDateTime();
}
this.alertInfo =
'I am ReportComponent and using @Self to loacate service. ' +
this.alertInfo;
}
ngOnInit(): void {}
}
<div class="alert" [class]="alertClass" role="alert">
{{ alertInfo }}
</div>
- DatetimeService代码
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class DatetimeService {
constructor() {}
getDateTime() {
return new Date().toUTCString();
}
}
请根据具体实验要求开启或关闭代码 providers: [DatetimeService], 本文中所有的css类均来自bootstrap最新版本。