1. 程式人生 > >Angular6學習筆記8: 服務(Service)(1)

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

服務(Service)

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

問題:為什麼需要服務?


因為:元件不應該直接獲取或儲存資料,它們不應該瞭解是否在展示假資料。 它們應該聚焦於展示資料,而把資料訪問的職責委託給某個服務。


這次將建立一個 HeroService,應用中的所有類都可以使用它來獲取英雄列表。 不要使用 new 來建立此服務,而要依靠 Angular 的依賴注入機制把它注入到 HeroesComponent 的建構函式中

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

1.建立HeroService

使用 Angular CLI 建立一個名叫 hero 的服務。

ng generate service hero
 
  1. wjydeMacBook-Pro:demo wjy$ ng generate service hero

  2. CREATE src/app/hero.service.spec.ts (362 bytes)

  3. CREATE src/app/hero.service.ts (133 bytes)

 執行完這個命令以後,開啟src/app/hero.service.ts 中生成 HeroService,

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

  2.  
  3. @Injectable({

  4. providedIn: 'root'

  5. })

  6. export class HeroService {

  7.  
  8. constructor() { }

  9. }

@Injectable() 服務

這個新的服務匯入了 Angular 的Injectable  符號,並且給這個服務類添加了 @Injectable() 裝飾器。 它把這個類標記為依賴注入系統

的參與者之一。HeroService 類將會提供一個可注入的服務,並且它還可以擁有自己的待注入的依賴。 目前它還沒有依賴.

@Injectable() 裝飾器會接受該服務的元資料物件,就像 @Component() 對元件類的作用一樣。

2.在HeroService中獲取hero的資料

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

從元件中移除資料訪問邏輯,意味著將來任何時候你都可以改變目前的實現方式,而不用改動任何元件。

在HeroService中匯入 Hero 和 HEROES,並寫一個獲取hero列表的方法:getHeroes()

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

  2. import {Hero} from './hero';

  3. import {HEROES} from './mock-heroes';

  4.  
  5. @Injectable({

  6. providedIn: 'root'

  7. })

  8. export class HeroService {

  9.  
  10. constructor() {

  11. }

  12.  
  13. getHeroes(): Hero[] {

  14. return HEROES;

  15. }

  16. }

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 屬性的定義改為一句簡單的宣告。

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

  2. import {Hero} from '../hero';

  3.  
  4. @Component({

  5. selector: 'app-heroes',

  6. templateUrl: './heroes.component.html',

  7. styleUrls: ['./heroes.component.css']

  8. })

  9. export class HeroesComponent implements OnInit {

  10. hero: Hero = {

  11. id: 1,

  12. name: 'Windstorm',

  13. };

  14. heroes: Hero[];

  15. selectedHero: Hero;

  16.  
  17. constructor() {

  18. }

  19.  
  20. ngOnInit() {

  21. }

  22.  
  23. onSelect(hero: Hero): void {

  24. this.selectedHero = hero;

  25. }

  26. }

5.注入 HeroService

往建構函式中新增一個私有的 heroService,其型別為 HeroService

constructor(private heroService: HeroService) { }

新增 getHeroes()

 
  1. getHeroes(): void {

  2. this.heroes = this.heroService.getHeroes();

  3. }

6.在 ngOnInit 中呼叫getHeroes()

a.在構造方法中呼叫(不推薦)

在建構函式呼叫:getHeroes();

 
  1. constructor(private heroService: HeroService) {

  2. this.getHeroes();

  3. }

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

b.在 ngOnInit 生命週期鉤子中呼叫

在ngOnInit 呼叫:getHeroes();

 
  1. ngOnInit() {

  2. this.getHeroes();

  3. }

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

兩者的比較:

讓建構函式保持簡單,只做初始化操作,比如把建構函式的引數賦值給屬性。 建構函式不應該做任何事。 它肯定不能呼叫某個函式來向遠端服務(比如真實的資料服務)發起 HTTP 請求。

而是選擇在 ngOnInit 生命週期鉤子中呼叫 getHeroes(),之後交由 Angular 處理,它會在構造出 HeroesComponent 的例項之後的某個合適的時機呼叫 ngOnInit。