Angular 2 Service vs Angular 1 Service

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

在 Angular 1.x 中,咱們經過使用 .service() API 來建立服務。app

Service Definition

咱們使用 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);

Service DI

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 )

Angular 2

Service setup

首先定義 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() and DI

接下來咱們使用 @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

相關文章
相關標籤/搜索