一直想寫關於 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