Angular6學習筆記8: 服務(Service)(1)
服務(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();
-
}
這樣也會達到之前應用的效果,如圖
b.在 ngOnInit 生命週期鉤子中呼叫
在ngOnInit 呼叫:getHeroes();
-
ngOnInit() {
-
this.getHeroes();
-
}
這樣也會達到之前應用的效果,如圖
兩者的比較:
讓建構函式保持簡單,只做初始化操作,比如把建構函式的引數賦值給屬性。 建構函式不應該做任何事。 它肯定不能呼叫某個函式來向遠端服務(比如真實的資料服務)發起 HTTP 請求。
而是選擇在 ngOnInit 生命週期鉤子中呼叫 getHeroes(),之後交由 Angular 處理,它會在構造出 HeroesComponent 的例項之後的某個合適的時機呼叫 ngOnInit。