天天看點

Angular6學習筆記8: 服務(Service)(1)服務(Service)

服務(Service)

繼學習筆記7,可以使用主從元件,現在繼續學習(服務)Service;

問題:為什麼需要服務?

因為:元件不應該直接擷取或儲存資料,它們不應該了解是否在展示假資料。 它們應該聚焦于展示資料,而把資料通路的職責委托給某個服務。

這次将建立一個 

HeroService

,應用中的所有類都可以使用它來擷取英雄清單。 不要使用 

new

 來建立此服務,而要依靠 Angular 的依賴注入機制把它注入到 

HeroesComponent

 的構造函數中

服務是在多個“互相不知道”的類之間共享資訊的好辦法。

1.建立HeroService

使用 Angular CLI 建立一個名叫 

hero

 的服務。

ng generate service hero
           
wjydeMacBook-Pro:demo wjy$ ng generate service hero
CREATE src/app/hero.service.spec.ts (362 bytes)
CREATE src/app/hero.service.ts (133 bytes)
           

 執行完這個指令以後,打開

src/app/hero.service.ts

 中生成 

HeroService,

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class HeroService {

  constructor() { }
}
           

@Injectable() 服務

這個新的服務導入了 Angular 的Injectable  符号,并且給這個服務類添加了 

@

Injectable

()

 裝飾器。 它把這個類标記為依賴注入系統的參與者之一。

HeroService

 類将會提供一個可注入的服務,并且它還可以擁有自己的待注入的依賴。 目前它還沒有依賴.

@

Injectable

()

 裝飾器會接受該服務的中繼資料對象,就像 

@Component()

 對元件類的作用一樣。

2.在HeroService中擷取hero的資料

HeroService

 可以從任何地方擷取資料:Web 服務、本地存儲(LocalStorage)或一個模拟的資料源。

從元件中移除資料通路邏輯,意味着将來任何時候你都可以改變目前的實作方式,而不用改動任何元件。

在HeroService中導入 

Hero

 和 

HEROES,并寫一個擷取hero清單的方法:getHeroes()

import {Injectable} from '@angular/core';
import {Hero} from './hero';
import {HEROES} from './mock-heroes';

@Injectable({
  providedIn: 'root'
})
export class HeroService {

  constructor() {
  }

  getHeroes(): Hero[] {
    return HEROES;
  }
}
           

3.提供(provide) 

HeroService

在要求 Angular 把 

HeroService

 注入到 

HeroesComponent

 之前,你必須先把這個服務提供給依賴注入系統。通過注冊提供商來做到這一點。提供商用來建立和傳遞服務,在這個例子中,它會對 

HeroService

 類進行執行個體化,以提供該服務,需要確定 

HeroService

 已經作為該服務的提供商進行過注冊。 你要用一個注入器注冊它。注入器就是一個對象,負責在需要時選取和注入該提供商。預設情況下,Angular CLI 指令 

ng generate service

 會通過給 

@Injectable

 裝飾器添加中繼資料的形式,為該服務把提供商注冊到根注入器上。如果你看看 

HeroService

 緊前面的 

@Injectable()

 語句定義,就會發現 

providedIn

 中繼資料的值是 'root',當你在頂層提供該服務時,Angular 就會為 

HeroService

 建立一個單一的、共享的執行個體,并把它注入到任何想要它的類上。 在 

@Injectable

 中繼資料中注冊該提供商,還能讓 Angular 可以通過移除那些完全沒有用過的服務,來進行優化。

注意:如果需要,可以在不同的層次上注冊提供商 —— 在 

HeroesComponent

 中、在 

AppComponent

 中,或在 

AppModule

 中。 比如,可以通過附加 

--module=app

 參數來告訴 CLI 要自動在子產品級提供該服務。

ng generate service hero --module=app
           

4.修改 

HeroesComponent

打開 

HeroesComponent

 類檔案。

删除 

HEROES

 的導入語句,因為你以後不會再用它了。 轉而導入 

HeroService,

把 

heroes

 屬性的定義改為一句簡單的聲明。

import {Component, OnInit} from '@angular/core';
import {Hero} from '../hero';

@Component({
  selector: 'app-heroes',
  templateUrl: './heroes.component.html',
  styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {
  hero: Hero = {
    id: 1,
    name: 'Windstorm',
  };
  heroes: Hero[];
  selectedHero: Hero;

  constructor() {
  }

  ngOnInit() {
  }

  onSelect(hero: Hero): void {
    this.selectedHero = hero;
  }
}
           

5.注入 

HeroService

往構造函數中添加一個私有的 

heroService

,其類型為 

HeroService

constructor(private heroService: HeroService) { }
           

添加 getHeroes()

getHeroes(): void {
  this.heroes = this.heroService.getHeroes();
}
           

6.在 

ngOnInit

 中調用getHeroes()

a.在構造方法中調用(不推薦)

在構造函數調用:getHeroes();

constructor(private heroService: HeroService) {
    this.getHeroes();
  }
           

這樣也會達到之前應用的效果,如圖

Angular6學習筆記8: 服務(Service)(1)服務(Service)

b.在 ngOnInit 生命周期鈎子中調用

在ngOnInit 調用:getHeroes();

ngOnInit() {
    this.getHeroes();
  }
           

這樣也會達到之前應用的效果,如圖

Angular6學習筆記8: 服務(Service)(1)服務(Service)

兩者的比較:

讓構造函數保持簡單,隻做初始化操作,比如把構造函數的參數指派給屬性。 構造函數不應該做任何事。 它肯定不能調用某個函數來向遠端服務(比如真實的資料服務)發起 HTTP 請求。

而是選擇在 ngOnInit 生命周期鈎子中調用 getHeroes(),之後交由 Angular 處理,它會在構造出 HeroesComponent 的執行個體之後的某個合适的時機調用 ngOnInit。