类提供者
// comment.service.ts import { Injectable } from '@angular/core'; import comments from '../data/comments'; @Injectable() export class CommentService { constructor() { } getComments() { return comments; } }
providers: [CommentService]
Provider
接口定义的提供者配置对象。providers: [{ provide: CommentService, useClass: CommentService }]
Provider
接口定义是一个具有两个属性的对象字面量:1.provide
属性存有令牌(如上面provide: CommentService
的CommentService
),它作为一个 key
,在定位依赖值和配置注入器时使用;
2.第二个属性是一个提供者定义对象,它告诉注入器要如何创建依赖值。提供者定义对象中的 key
可以是 useClass
, 也可以是 useExisting
、useValue
或 useFactory
。(后面介绍)
提供不同于令牌(provide)的类
我们再创建一个first-comment
服务来获取第一条评论:
// first-comment.service.ts import { Injectable } from '@angular/core'; import comments from '../data/comments'; @Injectable() export class FirstCommentService { constructor() { } getComments() { return comments[0]; } }
provide
与useClass
的值不一样也是可以的:
// service.component.ts @Component({ // ... providers: [ {provide: CommentService, useClass: FirstCommentService}] }) export class ServiceComponent implements OnInit { constructor(private commentService: CommentService) { // 能够获取到我们想要的第一条评论数据 console.log(this.commentService.getComments()); } // ... }
别名提供者
useExisting
指向的服务一定是已经注册过的,这是和useClass
的区别之一
// service.component.ts @Component({ // ... providers: [ FirstCommentService, // 如果用useClass, 则会得到两份FirstCommentService实例 { provide: CommentService, useExisting: FirstCommentService } ] })
值提供者
对于很简单的值,没必要把它做成一个类,可用useValue
提供简单的值
// service.component.ts @Component({ // ... providers: [{provide: CommentService, useValue: 'aaaa'}] }) export class ServiceComponent implements OnInit { constructor(private commentService: CommentService) { console.log(this.commentService); // 'aaaa' } // ... }
非类令牌
上面每个provide
都是一个类,那么也可以用其它数据类型作为令牌
// service.component.ts @Component({ // ... providers: [{ provide: 'HttpApi', useValue: 'http://abc.com/'}] }) /** 这种,注入构造函数的方式就有变化了 **/ export class ServiceComponent implements OnInit { constructor(@Inject('HttpApi') readonly httpApi) { console.log(this.httpApi); // http://abc.com/ } // ... }
使用InjectionToken对象
InjectionToken
。一般情况下无法使用ts
接口作为令牌,但又想要限制值的类型,可以借助InjectionToken
。
// comment.ts import { InjectionToken } from "@angular/core"; // 定义接口 export interface CommentT { postId: number; id: number; name: string; email: string; body: string; } // 导出 括号里面的参数是该令牌的一个描述,可选 export const CommentType = new InjectionToken<Comment>('comment type');
// service.component.ts @Component({ // ... providers: [{ provide: CommentType, useValue: {id: '0001', name: 'Jack', body: 'BBBB'}}] }) export class ServiceComponent implements OnInit { constructor(@Inject(CommentType) private commentType: CommentT) { this.name = this.commentType.name; } // ... }
工厂提供者
我们先修改下CommentService:
// comment.service.ts ... @Injectable() export class CommentService { constructor(private comment: CommentT[]) { } getComments() { return this.comment; } }
再创建一个根据评论id
查询的服务get-comment-by-index.service
:
// get-comment-by-index.service.ts import { Injectable } from '@angular/core'; import comments from '../data/comments'; @Injectable() export class GetCommentByIndexService { constructor() {} getCommentsByIndex(index = 0) { if (index > comments.length || index < 0) { return comments; } else { return comments.slice(index, index + 1); } } }
使用工厂提供者,注入GetCommentByIndexService
:
// service.component.ts @Component({ // ... providers: [ { provide: CommentService, useFactory(getCommentByIndexService: GetCommentByIndexService) { return new CommentService(getCommentByIndexService.getCommentsByIndex(1)); }, deps:[GetCommentByIndexService] } ] }) export class ServiceComponent implements OnInit { constructor(private commentService: CommentService, ) { // 能够得到第二条评论数据 console.log(this.commentService.getComments()); } // ... }
useFactory
是一个方法,处理你想要的逻辑并返回。如果有依赖其他的服务,应当在deps
中注册。总结
- 令牌与提供者类名一致时,可简写(推荐);
- 使用
useValue
来提供一个简单值; - 如果要限制注入的数据类型,使用InjectionToken对象;
- 工厂提供者可自定义更丰富的服务,如果有依赖其他的服务,应当在
deps
中注册。
本文转载自:公众号 岩弈 Angular教程,版权归原作者所有,本博客仅以学习目的的传播渠道,不作版权和内容观点阐述,转载时根据场景需要有所改动。
最新评论