依赖注入
依赖注入(DependencyInJection 简称DI)依然在线竞拍为例子 控制反转:Inversionof Control 简称:IOC Varproducr =new Product(); product依赖Product; 依赖注入模式及使用的好处,angular如何实现依赖注入 注入器的层级关系 松耦合和可重用性,提高可测试性 实现依赖注入: 注入器:每个组件都有一个注入器,负责注入组件需要的对象 注入器: constructor( private productService:ProductService) {...} 提供器:不同的写法 providers:[{provider:ProductService,useClass:ProductService}] providers:[ProductService]//如果provider和useClass一样可以简写成这样 providers:[{provider:ProductService,useClass:AnotherProductService}] 解释:联动注入器,其实真正的实例化是AnotherProductService,原因是注入器中的ProductService,根据提供器中的ProductService来匹配要注入的对象和提供器的,然后根据useClass提供什么类,就实例化什么类!(简洁一句话就是:真正的注入的是useClass这个类) provider:[{provide:ProductService,useFactory:()=>{...}}] 解释:就是通过工厂方法返回的实例,然后将返回的实例注入到注入器中 实例演示:
新建一个项目ngnew di 新建组件ng gcomponent product1 新建服务ng gservice shared/product 修改product.service.ts import { Injectable } from '@angular/core'; @Injectable() export class ProductService { constructor() { } //添加的地方-------------------------------- getProduct():Product{ return new Product(0,"iPhone",5899,"最新版") } //-------------------------- } //添加到类 export class Product{ constructor( public id:number, public title:string, public price:number, public desc:string ){ } } 在app.module.ts中引入 providers: [ProductService], 修改product1的控制器product1.component.ts 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> <h1>商品详情</h1> <h2>名称:{{product.title}}</h2> <h2>价格:{{product.price}}</h2> <h2>描述:{{product.desc}}</h2> </div> 修改app.component.html <div> <div> <h1>基本的依赖注入</h1> </div> <div> <app-product1></app-product1> </div> </div> 运行程序:结果截图 新建组件ng g component product2 新建服务ng g service shared/anotherProduct 修改another-product.service.ts控制器 import { Injectable } from '@angular/core'; import { ProductService,Product } from './product.service'; @Injectable() //实现productService接口 export class AnotherProductService implements ProductService{ getProduct(): Product { return new Product(1,"三星手机",4899,"最新版手机"); } constructor() { } } 修改product2.component.ts控制器 import { Component,ProductService } from '../shared/product.service'; import { AnotherProductService} from '../shared/another-product.service'; @Component({ selector: 'app-product2', templateUrl: './product2.component.html', styleUrls: ['./product2.component.css'], //添加一个注入器,让他实例化AnotherProductService类,是another-product.service.ts中的一个类 providers:[{ provide:ProductService,useClass:AnotherProductService }] }) export class Product2Component implements OnInit { product:Product; constructor(private productService:ProductService) { } ngOnInit() { this.product=this.productService.getProduct(); } } 修改product2.component.html <div> <h1>商品详情</h1> <h2>名称:{{product.title}}</h2> <h2>价格:{{product.price}}</h2> <h2>描述:{{product.desc}}</h2> </div> 修改app.component.html <div> <div> <h1>基本的依赖注入</h1> </div> <div> <app-product1></app-product1> <app-product2></app-product2> </div> </div> 总结注入器的作用域规则 第一点:一个提供器声明在模块时,是对所有组件可见的,所有组件都是可以注入的 第二点:声明在组件内的时候,只对组件和子组件可见其他组件不能注入 第三点:声明在模块的提供器和声明在组件内的提供器时,组件内的可以覆盖模块中的 提供器 第四点:我们应该优先把提供器声明在模块中,只有需要对其他组件不可见时才声明在组件中,但这种情况是非常罕见的。 ------------------------------------------------- product.service.ts控制器 @Injectable() export class ProductService { constructor() { } getProduct():Product{ return new Product(0,"最新版") } } 图中的productService可以注入别的服务(通过构造函数将其他服务注入到本服务中),本服务能不能注入到别的服务是看本服务有没有在providers属性中声明决定的, @Injectable()这个装饰器只要有@Injectable(),服务就能将别的服务注入进来 @Injectable() export classProductService { @Injectable()这个装饰器的意思是,其他服务也可以注入到这个服务中,建议给每个服务都添加这个装饰器。 问题:为啥我组件上没有声明这个装饰器也可以注入服务,因为@Component装饰器是@Injectable()装饰器的子类。 而这个服务是否可以注入到其他服务中,是根据他是否声明在app.module.ts中的providers属性中决定的。 import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { Product1Component } from './product1/product1.component'; import { ProductService } from './shared/product.service'; import { Product2Component } from './product2/product2.component'; @NgModule({ declarations: [ AppComponent, Product1Component, Product2Component ], imports: [ BrowserModule ], providers: [ProductService], bootstrap: [AppComponent] }) export class AppModule { } 服务之间如何互相注入 新建服务ng g service shared/logger import { Injectable } from '@angular/core'; @Injectable() export class LoggerService { constructor() { } log(message:string){ console.log(message); } } 修改 app.module.ts providers: [ProductService,LoggerService], 修改product.service.ts import { Injectable } from '@angular/core'; import { LoggerService } from './logger.service'; @Injectable() export class ProductService { constructor(private logger:LoggerService) { } getProduct():Product{ this.logger.log("getproduct方法被调用"); return new Product(0,"最新版") } } export class Product{ constructor( public id:number, public desc:string ){ } } 运行结果: 重构Auction 1、编写ProductService 包含3个方法:getProducts(),getProduct(id)以及getCommentsForProduct(id); 2、修改路由配置。在从商品列表进入商品详情时不在传输商品名称,修改传输商品ID。 3、注入ProductService并使用其服务。 添加一个服务:ng g service shared/product 修改product.service.ts import { Injectable } from '@angular/core'; @Injectable() export class ProductService { //数组 private products:Product[]=[ new Product(1,"第一个商品",1.99,3.5,"我是学习Angular",["电子","物电"]),//ID 商品名称,价格,星级,商品描述,商品类别 new Product(2,"第二个商品",1.5, new Product(3,"第三个商品",2.5, new Product(4,"第四个商品", new Product(5,"第五个商品", new Product(6,"第六个商品",4.5,"物电"]) ]; private comments:Comment[]=[//商品评论的实体,包括商品评论的信息 new Comment(1,1,"2018年4月23日17:14:08","张三",3,"东西很好"), new Comment(2,"李四","东西挺好"), new Comment(3,"王五","东西还行"), new Comment(4,"赵柳","东西不错") ] constructor() { } //第一个方法,返回这个数组信息 getProducts():Product[]{ return this.products; } //根据商品的id,返回相应的商品 getProduct(id:number):Product { return this.products.find((product)=>product.id==id); } //根据商品的id,返回所有的评论信息(filter:是过滤) getCommentsForProdutId(id:number):Comment[]{ return this.comments.filter((comment:Comment)=>comment.productid==id); } } export class Product{ constructor( public id:number, public rating:number, public desc:string, public categories:Array<string> ){} } //商品评论的类 export class Comment{ constructor(public id:number, public productid:number, public timestamp:string, public user:string, public content:string ){ } } 解释:主要就是将数据移植到这里来,Product,就是一个实体 修改路由配置:修改app.module.ts(之前传的是商品的名称,现在传的是id,所以修改两处 {第一处:path:'product/:productId',component:ProductDetailComponent}中的prodTitle改成productId 第二处:providers: [ProductService]) //------------------------------------------------------------------------- 部分代码:如下 import { ProductService } from './shared/product.service'; const routeConfig:Routes=[ {path:'',component:HomeComponent}, {path:'product/:productId',component:ProductDetailComponent} ] 修改商品组件的模板上:product.component.html <!--let product of products绑定后台的数据--> <div *ngFor="let product ofproducts" class="col-md-4 col-sm-4 col-lg-4"> <div class="thumbnail"> <!-- <img src="http://placehold.it/320X150">--> <img[src]="imgUrl"><!--属性绑定 --> <div class="caption"> <h4class="pull-right">{{product.price}}元</h4> <h4><a [routerLink]="['/product',product.id]">{{product.title}}</a></h4> <p>{{product.desc}}</p> </div> <div> <app-stars [rating]="product.rating"></app-stars> <!-- <app-stars>{{product.rating}}</app-stars>--> </div> </div> </div> 商品详情的组件上,修改控制器:product-detail.component.ts export class ProductDetailComponentimplementsOnInit { product:Product; comments:Comment[]; constructor(private routeInfo:ActivatedRoute, private productService:ProductService) { } ngOnInit() { let productId:number=this.routeInfo.snapshot.params["productId"] //this.productTitle=this.routeInfo.snapshot.params["prodTitle"] } } 注入productService并且使用其服务:修改app.module.ts providers: [ProductService],//把服务声明在模块的providers的属性中 然后在商品组件中构造函数中注入productService修改product.component.ts constructor(private productService:ProductService) { } 详细代码: import { Component,OnInit } from '@angular/core'; import { ProductService,Product } from '../shared/product.service'; @Component({ selector: 'app-product', templateUrl: './product.component.html', styleUrls: ['./product.component.css'] }) export class ProductComponent implements OnInit { private products:Product[]; private imgUrl='http://placehold.it/320X150'; constructor(private productService:ProductService) { } ngOnInit() {//组件实例化的钩子 this.products=this.productService.getProducts(); } } 然后接着在修改product-detail.component.ts this.product=this.productService.getProduct(productId); 然后接着修改product-detail.component.html <div class="thumbnail"> <img src="http://placehold.it/820X230"> <h4 class="pull-right">{{product.price}}</h4> <h4>{{product.title}}</h4> <p>{{product.desc}}</p> <div> <p class="pull-right">{{comments.length}}</p> <p> <app-stars [rating]="product.rating"></app-stars> </p> </div> </div> <div class="well"> <div class="row" *ngFor="let comment ofcomments"> <hr> <div class="col-md-12"> <app-stars [rating]="comment.rating"></app-stars> <span>{{comment.user}}</span> <span>{{comment.timestamp}}</span> <p></p> <p>{{comment.content}}</p> </div> </div> </div> (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |