16Angular依赖注入

2020-12-28  本文已影响0人  learninginto

依赖注入(DI)是一种设计模式,也有相应的框架,比如InversifyJS

在这里介绍Angular自己的DI框架,它会在实例化该类时向其提供该类所生命的依赖项

带修饰符的参数

在ts中,一个类的参数如果带上修饰符,那个参数就变成了类的实例属性

class Mobile{
    constructor(readonly name:string = '小米'){}
    logName(){
        console.log(this.name)
    }
}

上面的name有修饰符,那么它就是Mobile类的实例属性,等同于:

class Mobile{
    readony name:string
    constructor(){
        this.name = '小米'
    }
    logName(){
        console.log(this.name)
    }
}

实现过程

ng g s hero

被@Injectable装饰的类,就是一个可以被注入的类,也称为服务(为其他服务、组件、指令或管道提供服务)

import {Injectable} from '@angular/core'
import {HEROS} from './mock-heroes'
@Injectable({
    providedIn:'root'
})
export class HeroService {
    constructor(){}
    getHeroes(){
        return HEROS;
    }
}

在构造函数中直接声明,Angular框架帮我们完成注入(开箱即用),默认是单例模式(A、B模块同时注入时,得到的是同一个)

import {Renderer2} from '@angular/core'
constructor(private rd2:Renderer2)
@ViewChildren('img') imgs:QueryList<ElementRef>

ngAterViewInit():void{
    this.imgs.forEach(item=>{
      this.rd2.setStyle(item.nativeElement,'height','100px')
      //设置属性时为this.rd2.setProperty()
    })
}
  1. 在服务本身的@Injectable()的装饰器中
  2. 在NgModule的@NgModule()的装饰器中,providers数组,或import对应模块
ngOnInit(){
    const injector = Injector.create({
        providers:[
            {
                provide:Product,
                //useClass:Product
                useFactory:() => {
                    return new Product("xxx")
                },
                deps:[]
                //如果还依赖其他的内容,需要在deps数组中提供
            },
            //在这里写也可以
            {
                provide:PurchaseOrder,
                useClass:PurchaseOrder,
                deps:[Product]
            }
            //如果provide和useClass的名字相同,也可以这样 
            //PurchaseOrder
        ]
    })
}
  1. 在组件的@Component()装饰器中
@Component({
    selector:'',
    templateUrl:'',
    styleUrls:'[]',
    changeDetection:ChangeDetectionStragegy.OnPush,
    providers:[HeroService]
})

通常,在使用的时候不需要这么麻烦,只需要放在module.ts中的providers就可以

替代类

useClass和provide可以是不一样的类

providers:[
    {provide:LoggerService, useClass:BetterLoggerService}
]
值提供者

对于很简单的值,没必要把它做成一个类,可用useValue提供简单的值

providers:[{provide:Logger,useValue:'simpleValue'}]
非类令牌

上面的每个provide都是一个类,那么也可以用其它数据类型作为令牌

providers:[{provide:'httpApi', useValue:'123.com'}]
class AppComponent{
    constructor(@Inject('httpApi') readonly api){}
}
InjectionToken

当知道要注入的是什么类型时,可以用InjectionToken

interface AppConfig {
 apiEndpoint : string;
 title : string
}

无法用AppConfig作为令牌

[
    {
        provide:AppConfig,
        useValue:{
            apiEndPoint:'api.heros.com',
            title:'Dependency Injection'
        }
    }
]

但又想要限制值的类型,可以借助InjectionToken

import { InjectionToken } from '@angular/core'
//参数是该令牌的一个描述,可选择
export const APP_CONFIG = new InjectionToken<AppConfig>('app.config')
[
    {
        provide:APP_CONFIG,
        useValue:{
            apiEndPoint:'api.heros.com',
            title:'Dependency Injection'
        }
    }
]

注入方式

class AppComponent{
    constructor(@Inject(APP_CONFIG) config: Appconfig){
        this.title = config.title
    }
}
工厂提供者
import { Injectable } from '@angular/core';
import {UserService} from './user.service';
import {LoggerService} from './logger.service';

@Injectable()
export class UserLoggerService extends LoggerService {
  constructor(private userService: UserService, extra: string) {
    super();
    console.log('UserLoggerService', extra);
  }
  log(message: string) {
    const name = this.userService.user.name;
    super.log(`Message to ${name}: ${message}`);
  }
}
{
  provide: UserLoggerService,
  useFactory(userServe: UserService) {
    return new UserLoggerService(userServe, 'factory msg');
  },
  deps: [UserService] // 依赖其它服务的话,要列在这里
}
上一篇下一篇

猜你喜欢

热点阅读