掌握Angular2的依赖注入
更好阅读体验,请看原文 在读这篇文章之前,你要先了解一下什么是依赖注入,网上关于这个的解释很多,大家可以自行Google.
我们这一篇文章还是以QuickStart项目为基础,从头开始讲解怎么在Angular2中使用依赖注入,如果你按照本篇文章中讲解的示例亲自走一遍的话,你一定能够掌握如何在Angular2中使用依赖注入.好,废话不多说,开始我们今天的旅行吧! 我们首先将项目中的内联模板替换为一个模板文件,使用 @Component({ selector: 'my-app',//template: '<h1>My First Angular2 Travel</h1>',templateUrl: 'app/templates/app.html' }) 接下来我们给自己的页面添加一些展示的数据,我们首先新建一个文件 export class User{ constructor( private name:string,private age:number,private email:string ){} } 然后我们在组件中引入这个类,然后创建我们的显示数据: import {User} from "./classes/User"; // ... export class AppComponent { users: User[] = [ new User('dreamapple',22,'2312674832@qq.com'),new User('dreamapplehappy',18,'2313334832@qq.com') ] } 别忘了在模板中添加一些展示数据使用的html代码: <h1>依赖注入</h1> <ul> <li *ngFor="let user of users"> 用户的姓名: {{user.name}}; 用户的年龄: {{user.age}}; 用户的邮箱: {{user.email}} </li> </ul> 然后我们就会看到,在页面中显示出来了我们想要的那些数据: Angular2的依赖注入 一般情况下在Web应用中,我们要展示的数据都是从后台服务器动态获取的,所以我们来模拟一下这个过程;我们在这里就要使用服务的依赖注入了,我们首先创建文件 import {User} from "../classes/User"; export var Users:User[] = [ new User('dreamapple1',21,'2451731631@qq.com'),new User('dreamapple2','2451731632@qq.com'),new User('dreamapple3',23,'2451731633@qq.com'),new User('dreamapple4',24,'2451731634@qq.com'),new User('dreamapple5',25,'2451731635@qq.com'),new User('dreamapple6',26,'2451731636@qq.com') ] 我们使用了 接下来我们要创建一个获取用户数据的服务,我们创建一个新的文件 import {Injectable} from '@angular/core'; import {Users} from "../mock/user-data.mock"; @Injectable() export class UserService { getUsers() { return Users; } } 大家关于上面的代码部分会有一些疑问,我们来给大家解释一下:首先我们使用了刚才我们创造的模拟数据 我们接下来要在 import {UserService} from "./services/user.service"; import {User} from "./classes/User"; //... @Component({ selector: 'my-app',templateUrl: 'app/templates/app.html',providers: [ UserService ] }) export class AppComponent { users: User[]; constructor(private userService: UserService) { this.users = userService.getUsers(); } } 对上面代码的一些解释:我们使用 运行一下,然后我们就会看到下面的页面,表示一切成功. 如果这个时候你试图把 这是因为,我们的 很多Web程序都会需要一个日志服务,所以我们来新建一个服务 import {Injectable} from '@angular/core'; @Injectable() export class Logger{ logs: string[] = []; log(msg) { this.logs.push(msg); console.warn('From logger class: ' + msg); } } 然后我们在 import {Injectable} from '@angular/core'; import {Users} from "../mock/user-data.mock"; import {Logger} from "./logger.service"; @Injectable() export class UserService { constructor(private logger: Logger) { } getUsers() { this.logger.log('get users'); return Users; } } 可以看到,我们把 @Component({ selector: 'my-app',providers: [ Logger,// 添加Logger依赖 UserService ] }) 然后我们可以在页面中看到: 如果这个时候,我们注释掉 所以,就像上面所说的;我们还是给每一个服务类添加 接下来我们来讨论一下在 我们上面所说的那种提供服务的方式其实是最简单的一种方式,接下来我们讨论注册不同的服务提供商的方法;首先第一种就是我们上面所说的那种了,其实它是一种简写的方式;详细的方式应该是这样的: [{ provide: Logger,useClass: Logger }] 其中 我们可以试着替换 import {Injectable} from '@angular/core'; @Injectable() export class BetterLogger{ logs: string[] = []; log(msg) { this.logs.push(msg); console.warn('From better logger class: ' + msg); } } 然后在 @Component({ selector: 'my-app',providers: [ //Logger,[{provide: Logger,useClass: BetterLogger}],UserService ] }) 我们可以看到,控制台的输出是: 从中可以看到,我们使用了 [ LoggerHelper,{ provide: Logger,useClass: Logger }] 接下来我们来创建一个 import {Injectable} from '@angular/core'; @Injectable() export class LoggerHelper { constructor() { console.warn('Just a logger helper!'); } } 我们在 @Component({ selector: 'my-app',//[{provide: Logger,[LoggerHelper,{provide: Logger,// 带有依赖的注册商 UserService ] }) 然后我们在 import {Injectable} from '@angular/core'; import {LoggerHelper} from "./logger-helper.service"; @Injectable() export class BetterLogger{ logs: string[] = []; constructor(private loggerHelper: LoggerHelper) { } log(msg) { this.logs.push(msg); console.warn('From better logger class: ' + msg); } } 然后可以看到我们的控制台的输出结果是: 说明我们正确的使用了依赖;还有我们可以使用别名来使用相同的提供商,这种方式可以解决一些问题;尤其是当我们想让某个老的组件使用一个新的服务,就好比我们想让 [{ provide: BetterLogger,[{ provide: Logger,useExisting: BetterLogger}] 看到了吗,我们使用 @Component({ selector: 'my-app',{provide: BetterLogger,useExisting: BetterLogger}],UserService ] }) 然后我们在 console.warn('BetterLogger Constructor'); 我们还要在 constructor(private logger: Logger,private betterLogger: BetterLogger) { } 最后我们可以看到控制台的打印结果是: Just a logger helper! BetterLogger Constructor From better logger class: get users 但是一旦我们使用了 Just a logger helper! BetterLogger Constructor BetterLogger Constructor From better logger class: get users 说明我们创建了两个 [2016-8-20:续写] 值提供商:我们可以使用更简便的方法来注册一个提供商,那就是使用 let loggerValue = { logs: ['Hello','World'],log: (msg) => { console.warn('From values: ' + msg); },hello: () => { console.log('Just say hello!'); } }; export {loggerValue}; 那我们如何注册这个提供商呢?我们使用 // ... providers: [ //Logger,//[LoggerHelper,useValue: loggerValue},//{provide: Logger,useValue: loggerValue1},// 我们使用了useValue选项 UserService ] // ... 还要记住把 // ... getUsers() { this.logger.log('get users'); //noinspection TypeScriptUnresolvedFunction this.logger.hello(); return Users; } // ... 然后我们会看到控制台的输出是: // ... From values: get users Just say hello! // ... 表明我们这种方式注册提供商成功了. 当然我们也可以使用一个字符串了,这些读者可以自行尝试;或者观看这个示例. 工厂提供商:有时我们需要动态创建这个依赖值,因为它所需要的信息我们直到最后一刻才能确定;我们如何注册一个工厂提供商呢?不着急,我们一步一步来:我们首先来创建一个验证权限的文件, import {Injectable} from '@angular/core'; @Injectable() export class Authorize { isAuthorized: boolean; constructor(){ this.isAuthorized = Math.random() > 0.5 ? true: false; } getIsAuthorized() { return this.isAuthorized; } } 好吧,我承认这样写有点随意,暂时先这样吧;我们的目的是为了告诉大家如何使用工厂提供商,暂时简化权限验证这一块;从上面的代码我们可以大概了解到,这个服务就是为了获取当前用户的权限情况;然后我们来配置我们的 // ... let UserService2Provider = (logger: Logger,authorize: Authorize) => { return new UserService2(logger,authorize.getIsAuthorized()); }; // ... 可以看到,我们的 import {Injectable} from '@angular/core'; import {Users} from "../mock/user-data.mock"; import {Logger} from "./logger.service"; @Injectable() export class UserService2 { isAuthorized: boolean; constructor(private logger: Logger,isAuthorized: boolean) { this.isAuthorized = isAuthorized; } getUsers() { if(this.isAuthorized){ this.logger.log('get users'); return Users; } else { this.logger.log('not isAuthorized!'); return []; } } } 可以看到这个服务类和 // ... providers: [ //Logger,UserService,Authorize,// 不可缺少 { provide: UserService2,useFactory: UserService2Provider,deps: [Logger,Authorize] } ] // ... 还要记住,要添加 // ... export class AppComponent { users: User[]; constructor(private userService: UserService,private userService2: UserService2) { this.users = userService.getUsers(); console.log(this.userService2.getUsers()); } } 刷新浏览器,你会看到有时它会输出: From values: not isAuthorized! [] 有时它会输出: From values: get users [User,User,User] 那么说明,我们这种方式注册 也许大家会有一些疑问,我们在类的构造函数中使用 import {Component,Injector} from '@angular/core'; 我们先从 // ... export class AppComponent { users: User[]; private userService2: UserService2; //constructor(private userService: UserService,private userService2: UserService2) { // this.users = userService.getUsers(); // // console.log(this.userService2.getUsers()); //} constructor(private userService: UserService,private injector: Injector) { this.users = userService.getUsers(); this.userService2 = this.injector.get(UserService2); console.log(this.userService2.getUsers()); } } 所以可以看出来,这些繁琐的活我们全部都让 非类依赖我们上面的讲解全部都是把一个类作为一个依赖来进行服务的依赖注入,但是假如我们想要的不是一个类,而是一些值,或者对象;我们应该怎么办?我们先来写出这么一个文件 export interface AppConfig { title: string,apiEndPoint: string } export const AppConf: AppConfig = { title: 'Dreamapple',apiEndPoint: 'https://hacking-with-angular.github.io/' }; 按照上面的使用 // ... {provide: AppConfig,useValue: AppConf} // ... constructor(private userService: UserService,private userService2: UserService2,private appConf: AppConfig) { this.users = userService.getUsers(); console.log(this.userService2.getUsers()); console.log(this.appConf); } // ... 但是我们这样做却没有达到我们想要的效果;控制台报错: Error: ReferenceError: AppConfig is not defined(…) 因为接口 // 首先导入 OpaqueToken和Inject import {Component,Injector,OpaqueToken,Inject} from '@angular/core'; // 引入AppConf,并且使用OpaqueToken import {AppConf} from "./config/app-config"; let APP_CONFIG = new OpaqueToken('./config/app-config'); // 在providers中进行配置 {provide: APP_CONFIG,useValue: AppConf} // 在类中使用 constructor(private userService: UserService,@Inject(APP_CONFIG) appConf: AppConfig) { this.users = userService.getUsers(); console.log(this.userService2.getUsers()); console.log(appConf); } 对上面的代码的一些解释首先我们使用 最后我们来讲解一下 // 导入 Optonal import {Injectable,Optional} from '@angular/core'; import {Users} from "../mock/user-data.mock"; import {Logger} from "./logger.service"; import {BetterLogger} from "./better-logger.service"; @Injectable() export class UserService { constructor(private logger: Logger,// 使用@Optional标记 @Optional()private betterLogger: BetterLogger) { } getUsers() { this.logger.log('get users'); //noinspection TypeScriptUnresolvedFunction this.logger.hello(); // 存在betterLogger时的处理 if(this.betterLogger) { this.betterLogger.log('optional'); } //console.log(this.logger); return Users; } } 至此,整篇文章已经结束了;如果你坚持读到了这里,那说明你也是一个很有耐心的人;如果你有什么问题可以在这里提出. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |