constructor(private ProductService:productService){...}//注入器
//提供器
providers:[productService]
providers:[{provide:productService,useClass:productService}]
providers:[{provide:productService,useClass:AnotherProductService}]
providers:[{provide:productService,useFactory:() =>{...}}]
首先我们来看一个简单的例子
ng g service shared/product //创建一个服务
在创建好的项目里的shared文件里的product.service.ts写入
import { Injectable } from '@angular/core';
@Injectable() //这个装饰器的作用是决定着ProductService可以通过构造函数注入其它的服务,
// 现在是ProductService能否注入到其它的服务中去,是由模块的提供器决定的
//如app.modules.ts的 providers: [ProductService],
export class ProductService {
//这里是想实现服务注入到服务
constructor() {}
getProduct():Product{
return new Product(0,"iphone7",5899,"最新款苹果手机")
}
}
export class Product {
constructor(
public id:number,
public title:string,
public price:number,
public desc:string
){}
}
然后在product1.component.ts通过构造函数创建注入器
import { Component, OnInit } from '@angular/core';
import {Product} from "../shared/product.service";
import {ProductService} from "../shared/product.service";
@Component({
selector: 'app-product1',
templateUrl: './product1.component.html',
styleUrls: ['./product1.component.css']
})
export class Product1Component implements OnInit {
product: Product;
constructor(private productService:ProductService) { }
ngOnInit() {
this.product = this.productService.getProduct();
}
}
在然后在app.component.ts里面创建提供器
providers: [ProductService]
接下来在product1.componet.html里面绑好数据
<div>
<h1>商品详情</h1>
<h2>名称:{{product.title}}</h2>
<h2>价格:{{product.price}}</h2>
<h2>描述:{{product.desc}}</h2>
</div>
最后在app.component.html里面注册product1组件
<app-product1></app-product1>
提供器的作用域
上文我们是把提供器放在app.component.ts中,这次我们把提供器放在自身的组件当中,唯一的区别是把提供器放在product2.component.ts中
@Component({
selector: 'app-product2',
templateUrl: './product2.component.html',
styleUrls: ['./product2.component.css'],
providers:[{
provide:ProductService(指定了一个token),useClass:AnotherProductService (实 例化一个对象)
}]
})
export class Product2Component implements OnInit {
product: Product;
constructor(private productService:ProductService) { }
ngOnInit() {
this.product = this.productService.getProduct();
}
}
关于提供器的作用域的几个注意点
- 提供器如果声明在app.component.ts模块中,那么它的作用域对于所有组件来说都是可见的
- 提供器如果声明在组件当中,那么只有它本身的组件及子组件是可见的
- 如果定义了相同的token,组件的token会覆盖模块的token
- 优先将提供器声明在模块中
服务之间的注入
新建服务命令
ng g service shared/logger
logger.service.ts
@Injectable()
export class LoggerService {
constructor() { }
log(message:string){
console.log(message);
}
}
product.service.ts
import { Injectable } from '@angular/core';
import {LoggerService} from "./logger.service"
@Injectable() /
export class ProductService {
//这里是想实现服务注入到服务
constructor(public logger:LoggerService) {}
getProduct(): Product{
this.logger.log("getProduct方法被调用");
return new Product(0,"iphone7",5899,"最新款苹果手机")
}
}
export class Product {
constructor(
public id:number,
public title:string,
public price:number,
public desc:string
){}
}
在another.service.ts中这里会报一个错误,引起的原因是在构造函数的声明没有和父类保持一致
解决办法是:因为another使用的是product服务,product.service.ts的构造函数声明了logger服务,another作为子类与父类保持一致,所以也要在构造函数里面进行声明
@Injectable()
export class AnotherProductService implements ProductService{
getProduct():Product {
return new Product(1,"iphoneX",8888,"买不起买不起")
}
constructor(public logger:LoggerService) {
}
}
使用工厂模式声明提供器
providers: [{
provide:ProductService,
useFactory:() =>{
let logger = new LoggerService();
let dev = Math.random()>0.5;
if(dev){
return new ProductService(logger);
}else{
return new AnotherProductService(logger);
}
}
},LoggerService],
bootstrap: [AppComponent]
})
一般来说可以传值
providers: [{
provide:ProductService,
useFactory:(logger:LoggerService,isDev) =>{
if(isDev){
return new ProductService(logger);
}else{
return new AnotherProductService(logger);
}
},
deps:[LoggerService,"IS_DEV_ENV"]
},LoggerService,{
provide:"IS_DEV_ENV",useValue:false
}],
bootstrap: [AppComponent]
})
也可以传一个对象
providers: [{
provide:ProductService,
useFactory:(logger:LoggerService,appConfig) => {
if(appConfig.isDev){
return new ProductService(logger);
}else{
return new AnotherProductService(logger);
}
},
deps:[LoggerService,"APP_CONFIG"]
},LoggerService,{
provide:"APP_CONFIG",useValue:{isDev:false}
}]
等下,究竟发生了什么事。让我们看看product2.component.ts中的主要代码
export class Product2Component implements OnInit {
product: Product;
constructor(private productService:ProductService) { }
ngOnInit() {
this.product = this.productService.getProduct();
}
}
梳理下整个过程。首先在商品组件里面的构造函数里声明了productService的token来注入服务,Ng看到之后会去找ProductService对象的提供器,然这个对象是使用工厂模式来实例化的,然后又发现这个工厂需要依赖于另外一个服务,根据这个服务的提供器声明去找,直到把所有的组件都组装好,而productComponent这个组件完全是透明的,服务和组件隔离开来,让组件更好地复用。
注入器及其层次关系
子组件会根据自己的注入器查看本身有没有注册提供器,如果没有的话,就会根据注入器的token(这里的token是一个服务)查父组件app.component.ts的注入器上是否有合适的提供器,如果还是没有,则继续往上找,找到应用层注入器,看应用级的注入器有没有合适的提供器,即使app.modules.ts。如果还是没有,则会抛出异常。还有一点,值得注意的是,Angluar只能通过构造函数来注入,其他语言中不止局限于这一种。