简介
依赖注入是重要的程序设计模式。 Angular 有自己的依赖注入框架,离开了它,几乎没法构建 Angular 应用。 它使用得非常广泛,以至于几乎每个人都会把它简称为 DI。
注入器与提供器
注入器
//注入器 Constructor(private productService: ProductService ){ }
说明:
一般是在组件或者是服务中写入端代码,如果一个组件或者服务中的 constructor 注入为空。 就代表着这个组件或者服务没有注入任何的服务。
提供器
//提供器写法一 Providers:[ProductService] //提供器写法二 Providers:[{provide: ProductService,userClass:ProductService}] //提供器写法三 Providers:[{ provide: ProductService,userClass:AnotherProductService }] //提供器写法四 Providers:[{ provide: ProductService,userFactory: () => { /*新建服务的方法*/ } }]
说明:
写法一:使用这种方法是默认的写法(也是最精简的写法),直接提供一个 ProuctService。 写法二:使用这种方法和默认的写法是一个意思。 provide: ProductService就是提供的是 ProductService服务。 userClass:ProductService 就是我们new 这个服务对象的时候,new的是 ProductService。 写法三:使用这种方式,就是提供器提供的是 ProductService,但是 new 服务对象的时候, new 的是 AnotherProductService。 写法四:使用工厂模式创建提供器
寻找依赖注入的逻辑
在代码中找注入的方法: 1.在具体的组件或者服务中的 constructor 方法中找注入的服务 2.根据 1 中注入的服务找 提供器 3.跟据2 中的提供器找到对应的注入服务类 例: 注入器为 :Constructor(private productService: ProductService ){ } 就去找对应的 providers(提供器) 如果提供器为:Providers:[ProductService] 那么注入的就是 ProductService 如果提供器为:Providers:[{ provide: ProductService,userClass:AnotherProductService }] 那么注入的就是 AnotherProductService
依赖注入的层级结构
一方面,NgModule 中的提供商是被注册到根注入器。这意味着在 NgModule 中注册的提供商可以被整个应用访问。 另一方面,在应用组件中注册的提供商只在该组件及其子组件中可用。
关于 @Injectable()
@Injectable() 标识一个类可以被注入器实例化。 通常,在试图实例化没有被标识为@Injectable()的类时,注入器会报错。 官方建议: 建议:为每个服务类都添加 @INJECTABLE() 建议:为每个服务类都添加@Injectable(),包括那些没有依赖严格来说并不需要它的。因为: 面向未来: 没有必要记得在后来添加依赖的时候添加 @Injectable()。 一致性:所有的服务都遵循同样的规则,不需要考虑为什么某个地方少了一个。 "注意": 总是使用@Injectable()的形式,不能只用@Injectable。 如果忘了括号,应用就会神不知鬼不觉的报错!
最简单的例子
根模块中注入
目的:在新建的工程中将数据从Service中注入到component中,并且在界面上面展示出来 1.新建一个工程: ng new di 2.新建 product1 组件: ng g c product1 3.新建 product 服务(在shared 路径下面新建 product 服务): ng g service shared/product 或者 ng g s shared/product
/* 增加 class Product, 以及返回 Product对象供外部调用的方法 getProduct() getProduct方法需要返回一个 Product 。如果需要让外部访问到当前的 Service ,就需要加上一个注解 @Injectable() */ import { Injectable } from '@angular/core'; @Injectable() export class ProductService { constructor() { } getProduct(): Product { return new Product(1,"IPhone X","最牛逼的全面屏手机",8388); } } export class Product{ constructor( public id: number,public name: string,public desc: string,public price: number ){} }
修改 product1.component.ts
/* 在当前的 Product 类中增加 变量 product 以及 注入 ProductService,在初始化的钩子中 调用 ProductService 的 getProduct 方法,返回一个 Product */ import { Component,OnInit } from '@angular/core'; import {Product,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(); } }
修改 product1.component.html
<!-- 修改界面,用于界面展示 --> <div> <div>商品编码:{{product.id}}</div> <div>商品名称:{{product.name}}</div> <div>商品描述:{{product.desc}}</div> <div>商品价格:{{product.price}}</div> </div>
修改 app.conponent.html
<!-- 将 product.html 加入到 当前界面 --> <h1> 依赖注入的例子 </h1> <div> <app-product1></app-product1> </div>
修改 app.modules.ts
/*添加 Product.service.ts 到 providers 中,在这个地方注入是叫做 “从根组件中注入”,然后所有的都可以访问到。*/ import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { HttpModule } from '@angular/http'; import { AppComponent } from './app.component'; import { Product1Component } from './product1/product1.component'; import {ProductService} from "app/shared/product.service"; @NgModule({ declarations: [ AppComponent,Product1Component ],imports: [ BrowserModule,FormsModule,HttpModule ],providers: [ProductService],bootstrap: [AppComponent] }) export class AppModule { }
图示: