一直想写关于 Angular 1.x 与 Angular 2.x (Angular 4.x 已发布) 区别的文章,方便 Angular 1.x 的用户快速的过渡到 Angular 2.x。在浏览文章的时候,发现 Todd Motto 大神,已经写了相关的系列文章。英文好的同窗,建议直接阅读 Creating an Angular 2 Injectable Service 原文哈,由于我并不打算完整地翻译,另外须要注意的是原文的示例是使用ES 2015,本文 Angular 2 示例是使用 TypeScript哈。废话很少说,接下来咱们开始进入正题。ios
Angular 1.xweb
Service definitiontypescript
Service DIbootstrap
Angular 2segmentfault
Service setup浏览器
@Injectable() and DI服务器
在 Angular 1.x 中,咱们经过使用 .service()
API 来建立服务。app
咱们使用 ES 2015 中的 Class
来定义服务,getTodos() 方法只是简单地返回 Todos 列表。在后续的部分,咱们会引入 HTTP
模块。ide
class TodoService { constructor() {} getTodos() { return [{ "id": 1, "label": "delectus aut autem", "completed": false },{ "id": 2, "label": "quis ut nam facilis et officia qui", "completed": false },{ "id": 3, "label": "fugiat veniam minus", "completed": false },{ "id": 4, "label": "et porro tempora", "completed": true },{ "id": 5, "label": "laboriosam mollitia et enim quasi adipisci quia provident illum", "completed": false }]; } } angular .module('app') // 获取已注册的app模块 .service('TodoService', TodoService); // 经过service API注册TodoService服务
接下来咱们来注入 $http
服务,在 Angular 1.x 中声明依赖项的方式有3种,分为以下:函数
// 方式一: 使用 $inject annotation 方式 - 严格DI var fn = function (a, b) {}; fn.$inject = ['a', 'b']; // 方式二: 使用 array-style annotations 方式 - 严格DI var fn = ['a', 'b', function (a, b) {}]; // 方式三: 使用隐式声明方式 var fn = function (a, b) {}; // 不推荐
咱们使用第一种方式来声明依赖,具体代码以下:
class TodoService { constructor($http) { this.$http = $http; } getTodos() { return [{..},{..},{..},{..},{..}]; } } TodoService.$inject = ['$http']; angular .module('app') .service('TodoService', TodoService);
const todo = { template: ` <div> My Todo List: <ul> <li ng-repeat="todo in $ctrl.todos"> {{ todo.label }} </li> </ul> </div> `, controller(TodoService) { $onInit() { this.todos = TodoService.getTodos(); } } };
上面代码中,咱们在 controller 中使用 $onInit
生命周期钩子,用于在组件初始化的时候,设置组件的初始数据。示例中的 getTodos() 是同步操做,若是使用 $http
服务从远程服务器获取数据的话,返回的是一个 Promise 对象,咱们就须要在 then()
方法中进行 todos 属性的赋值操做。
(备注:有兴趣了解 Angular 1.x DI 内容的话,能够参考我以前的文章 - Angular 2 DI - IoC & DI - 1 )
首先定义 TodoService 服务类 (使用TypeScript):
export class TodoService { getTodos(): Array<{ id: number, label: string, completed: boolean }> { return [{ "id": 1, "label": "delectus aut autem", "completed": false }, { "id": 2, "label": "quis ut nam facilis et officia qui", "completed": false }, { "id": 3, "label": "fugiat veniam minus", "completed": false }, { "id": 4, "label": "et porro tempora", "completed": true }, { "id": 5, "label": "laboriosam mollitia et enim quasi adipisci quia provident illum", "completed": false }]; } }
接下来咱们使用 @Injectable
类装饰器,来装饰 TodoSevice
类:
import {Injectable} from '@angular/core'; @Injectable() export default class TodoService { getTodos(): Array<{ id: number, label: string, completed: boolean }> { return [{..},{..},{..},{..},{..}]; } }
而后,咱们经过 @Component()
装饰器建立 todo 组件,为了跟 Angular 1.x 的示例同样,在组件初始化的时候,设置组件的初始数据,咱们须要在组件中引入 OnInit 接口,并在组件类中实现该接口。具体示例以下:
import { Component, OnInit } from '@angular/core'; import { TodoService } from './services/todo.service'; @Component({ selector: 'todo', template: ` <div> My Todo List: <ul> <li *ngFor="let todo of todos"> {{ todo.label }} </li> </ul> </div> ` }) export default class TodoComponent implements OnInit { public todos: Array<{ id: number, label: string, completed: boolean }>; constructor(public todoService: TodoService) { } // 使用构造方式,注入TodoService ngOnInit() { this.todos = this.todoService.getTodos(); // 获取待办事项列表 } }
app.component.ts
import { Component } from '@angular/core'; @Component({ selector: 'exe-app', template: ` <todo></todo> ` }) export class AppComponent { }
app.module.ts
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import TodoComponent from './todo.component'; import { AppComponent } from './app.component'; import { TodoService } from './services/todo.service'; @NgModule({ imports: [ BrowserModule ], declarations: [ TodoComponent, AppComponent ], providers: [TodoService] bootstrap: [ AppComponent ] }) export class AppModule { }
以上成功运行后,浏览器中的显示结果以下:
1.ngOnit 与 constructor 的区别和应用场景
在 Angular 2 中 constructor 通常用于依赖注入或执行简单的数据初始化操做,ngOnInit 钩子主要用于执行组件的其它初始化操做或获取组件输入的属性值。
详细内容请参考 - Angular 2 constructor & ngOnInit
2.@Injectable装饰器的做用
若是 TodoService 不依赖于其余对象,是能够不用使用 Injectable 类装饰器。当 TodoService 须要在构造函数中注入依赖对象,就须要使用 Injectable 类装饰器。比较推荐的作法无论是否有依赖对象,service 中都使用 Injectable 类装饰器。
详细内容请参考 - Angular 2 Inject