一、当一个服务中需要别的服务时怎么做?
当服务需要依赖时,我们也可以用构造函数注入模式来添加一个带有别的依赖的构造函数。
例如在HeroService服务中需要Logger的服务:
import { Injectable } from '@angular/core';
import { HEROES } from './mock-heroes';
import { Logger } from '../logger.service';
@Injectable()
export class HeroService {
constructor(private logger: Logger) { }
getHeroes() {
this.logger.log('Getting heroes ...');
return HEROES;
}
}
其中日志服务Logger :
import { Injectable } from '@angular/core';
@Injectable()
export class Logger {
logs: string[] = []; // 用于测试的捕获日志
log(message: string) {
this.logs.push(message);
console.log(message);
}
}
也就是在构造函数中注入一个Logger
类的实例,并把它存到名为logger
的私有属性中。 当别人请求英雄数据时,在getHeroes()
方法中调用这个属性的方法。
@Ingectable()标识一个类可以被注入器实例化,在试图实例化没有被标识为@Injectable()
的类时,注入器会报错。
服务中没有要被注入的参数时,可以忽略@Injectable(),如果服务有注入的依赖,就必须要构造函数参数的元数据来注入。
建议:为每一个类都添加@Injectable()。
二、注入器的提供商们:
提供商提供依赖值的一个具体的、运行时的版本。 注入器依靠提供商创建服务的实例,注入器再将服务的实例注入组件或其它服务。
为注入器注册一个服务的提供商,否则注入器不知道如何创建该服务,实例:
providers:[Logger]
上面的实际上实注册提供商的简写模式,使用的是一个带有两个属性的提供商对象:
[{provide:Logger, useClass:Logger}]
第一个是令牌token,作为键值key使用,用于定位依赖值和注册提供商;第二个是提供商定义的对象,可以把它看做是指导如何创建依赖值的配方。
当想要请求Logger,返回BetterLogger时(也就是说Logger作为BetterLogger的别名,组件想使用Logger
记录消息时,我们希望改用BetterLogger
的单例对象来记录),可以这样写:
[{provide:Logger, useClass:BetterLogger}]
三、带依赖的类提供商:
[ UserService,
{ provide: Logger, useClass: EvenBetterLogger }]
别名类提供商(避免了应用中有两个不同的NewLogger
实例):
[ NewLogger,
// 使用useExisting:别名是OldLogger,引用NewLogger
{ provide: OldLogger, useExisting: NewLogger}]
值提供商(提供一个预先做好的对象):
let silentLogger = {
logs: ['Silent logger says "Shhhhh!". Provided via "useValue"'],
log: () => {}
};
// 下面是注册提供商的方法:使用useValue
[{ provide: Logger, useValue: silentLogger }]
四、注入器冒泡
上面是一个三级组件树,当一个组件申请获得一个依赖时,Angular 先尝试用该组件自己的注入器来满足它。 如果该组件的注入器没有找到对应的提供商,它就把这个申请转给它父组件的注入器来处理。 如果那个注入器也无法满足这个申请,它就继续转给它的父组件的注入器。 这个申请继续往上冒泡 —— 直到我们找到了一个能处理此申请的注入器或者超出了组件树中的祖先位置为止。 如果超出了组件树中的祖先还未找到,Angular 就会抛出一个错误。
五、通过$event对象取得用户输入:
template: `
<input (keyup)="onKey($event)">
<p>{{values}}</p>
`
export class KeyUpComponent_v1 {
values = '';
// 用户按下并释放一个按键时,触发keyup事件,Angular 在$event变量提供一个相应的 DOM 事件对象,
// 将它作为参数传递给onKey()方法
onKey(event: any) { // 现在event是any类型
this.values += event.target.value + ' | ';
}
}
$event
对象的属性取决于 DOM 事件的类型。例如,鼠标事件与输入框编辑事件包含了不同的信息。
所有标准 DOM 事件对象都有一个target
属性, 引用触发该事件的元素。 在本例中,target
是<input>
元素, event.target.value
返回该元素的当前内容。假设用户输入字母“abc”,然后用退格键一个一个删除它们。 用户界面将显示: