国产gaysexchina男同gay,japanrcep老熟妇乱子伦视频,吃奶呻吟打开双腿做受动态图,成人色网站,国产av一区二区三区最新精品

Hero guide 添加服務

2020-06-29 17:36 更新

英雄指南的 HeroesComponent 目前獲取和顯示的都是模擬數(shù)據(jù)。

本節(jié)課的重構完成之后,HeroesComponent 變得更精簡,并且聚焦于為它的視圖提供支持。這也讓它更容易使用模擬服務進行單元測試。

服務存在的意義

組件不應該直接獲取或保存數(shù)據(jù),它們不應該了解是否在展示假數(shù)據(jù)。 它們應該聚焦于展示數(shù)據(jù),而把數(shù)據(jù)訪問的職責委托給某個服務。

本節(jié)課,你將創(chuàng)建一個 HeroService,應用中的所有類都可以使用它來獲取英雄列表。 不要使用 new 關鍵字來創(chuàng)建此服務,而要依靠 Angular 的依賴注入機制把它注入到 HeroesComponent 的構造函數(shù)中。

服務是在多個“互相不知道”的類之間共享信息的好辦法。 你將創(chuàng)建一個 MessageService,并且把它注入到兩個地方:

  1. 注入到 HeroService 中,它會使用該服務發(fā)送消息

  1. 注入到 MessagesComponent 中,它會顯示其中的消息。當用戶點擊某個英雄時,它還會顯示該英雄的 ID。

創(chuàng)建 HeroService

使用 Angular CLI 創(chuàng)建一個名叫 hero 的服務。

ng generate service hero

該命令會在 "src/app/hero.service.ts" 中生成 HeroService 類的骨架,代碼如下:

Path:"src/app/hero.service.ts (new service)"

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


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


  constructor() { }


}

@Injectable() 服務

注意,這個新的服務導入了 Angular 的 Injectable 符號,并且給這個服務類添加了 @Injectable() 裝飾器。 它把這個類標記為依賴注入系統(tǒng)的參與者之一。HeroService 類將會提供一個可注入的服務,并且它還可以擁有自己的待注入的依賴。 目前它還沒有依賴,但是很快就會有了。

@Injectable() 裝飾器會接受該服務的元數(shù)據(jù)對象,就像 @Component() 對組件類的作用一樣。

獲取英雄數(shù)據(jù)

HeroService 可以從任何地方獲取數(shù)據(jù):Web 服務、本地存儲(LocalStorage)或一個模擬的數(shù)據(jù)源。

從組件中移除數(shù)據(jù)訪問邏輯,意味著將來任何時候你都可以改變目前的實現(xiàn)方式,而不用改動任何組件。 這些組件不需要了解該服務的內部實現(xiàn)。

這節(jié)課中的實現(xiàn)仍然會提供模擬的英雄列表。

導入 Hero 和 HEROES。

Path:"src/app/hero.service.ts"

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

添加一個 getHeroes 方法,讓它返回模擬的英雄列表。

Path:"src/app/hero.service.ts"

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

提供(provide) HeroService

你必須先注冊一個服務提供者,來讓 HeroService 在依賴注入系統(tǒng)中可用,Angular 才能把它注入到 HeroesComponent 中。所謂服務提供者就是某種可用來創(chuàng)建或交付一個服務的東西;在這里,它通過實例化 HeroService 類,來提供該服務。

為了確保 HeroService 可以提供該服務,就要使用注入器來注冊它。注入器是一個對象,負責當應用要求獲取它的實例時選擇和注入該提供者。

默認情況下,Angular CLI 命令 ng generate service 會通過給 @Injectable() 裝飾器添加 providedIn: 'root' 元數(shù)據(jù)的形式,用根注入器將你的服務注冊成為提供者。

@Injectable({
  providedIn: 'root',
})

注:
- 這是一個過渡性的代碼范例,它將會允許你提供并使用 HeroService。此刻的代碼和最終代碼相差很大。

當你在頂層提供該服務時,Angular 就會為 HeroService 創(chuàng)建一個單一的、共享的實例,并把它注入到任何想要它的類上。 在 @Injectable 元數(shù)據(jù)中注冊該提供者,還能允許 Angular 通過移除那些完全沒有用過的服務來進行優(yōu)化。

現(xiàn)在 HeroService 已經準備好插入到 HeroesComponent 中了。

修改 HeroesComponent

打開 HeroesComponent 類文件。

刪除 HEROES 的導入語句,因為你以后不會再用它了。 轉而導入 HeroService。

Path:"src/app/heroes/heroes.component.ts (import HeroService)"

import { HeroService } from '../hero.service';

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

Path:"src/app/heroes/heroes.component.ts"

heroes: Hero[];

注入 HeroService

往構造函數(shù)中添加一個私有的 heroService,其類型為 HeroService。

Path:"src/app/heroes/heroes.component.ts"

constructor(private heroService: HeroService) {}

這個參數(shù)同時做了兩件事:

  1. 聲明了一個私有 heroService 屬性。
  2. 把它標記為一個 HeroService 的注入點。

當 Angular 創(chuàng)建 HeroesComponent 時,依賴注入系統(tǒng)就會把這個 heroService 參數(shù)設置為 HeroService 的單例對象。

添加 getHeroes()

創(chuàng)建一個方法,以從服務中獲取這些英雄數(shù)據(jù)。

Path:"src/app/heroes/heroes.component.ts"

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

在 ngOnInit() 中調用它

你固然可以在構造函數(shù)中調用 getHeroes(),但那不是最佳實踐。

讓構造函數(shù)保持簡單,只做初始化操作,比如把構造函數(shù)的參數(shù)賦值給屬性。 構造函數(shù)不應該做任何事。 它當然不應該調用某個函數(shù)來向遠端服務(比如真實的數(shù)據(jù)服務)發(fā)起 HTTP 請求。

而是選擇在 ngOnInit 生命周期鉤子中調用 getHeroes(),之后 Angular 會在構造出 HeroesComponent 的實例之后的某個合適的時機調用 ngOnInit()。

Path:"src/app/heroes/heroes.component.ts"

getHeroes(): void {
 ngOnInit() {
  this.getHeroes();
}

刷新瀏覽器,該應用仍運行的一如既往。 顯示英雄列表,并且當你點擊某個英雄的名字時顯示出英雄詳情視圖。

可觀察(Observable)的數(shù)據(jù)

HeroService.getHeroes() 的函數(shù)簽名是同步的,它所隱含的假設是 HeroService 總是能同步獲取英雄列表數(shù)據(jù)。 而 HeroesComponent 也同樣假設能同步取到 getHeroes() 的結果。

Path:"src/app/heroes/heroes.component.ts"

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

這在真實的應用中幾乎是不可能的。 現(xiàn)在能這么做,只是因為目前該服務返回的是模擬數(shù)據(jù)。 不過很快,該應用就要從遠端服務器獲取英雄數(shù)據(jù)了,而那天生就是異步操作。

HeroService 必須等服務器給出響應, 而 getHeroes() 不能立即返回英雄數(shù)據(jù), 瀏覽器也不會在該服務等待期間停止響應。

HeroService.getHeroes() 必須具有某種形式的異步函數(shù)簽名。

這節(jié)課,HeroService.getHeroes() 將會返回 Observable,部分原因在于它最終會使用 Angular 的 HttpClient.get() 方法來獲取英雄數(shù)據(jù),而 HttpClient.get() 會返回 Observable。

可觀察對象版本的 HeroService

Observable 是 RxJS 庫中的一個關鍵類。

在稍后的 HTTP 教程中,你就會知道 Angular HttpClient 的方法會返回 RxJS 的 Observable。 這節(jié)課,你將使用 RxJS 的 of() 函數(shù)來模擬從服務器返回數(shù)據(jù)。

打開 "HeroService" 文件,并從 RxJS 中導入 Observableof 符號。

Path:"src/app/hero.service.ts (Observable imports)"

import { Observable, of } from 'rxjs';

getHeroes() 方法改成這樣:

Path:"src/app/hero.service.ts"

getHeroes(): Observable<Hero[]> {
  return of(HEROES);
}

of(HEROES) 會返回一個 Observable<Hero[]>,它會發(fā)出單個值,這個值就是這些模擬英雄的數(shù)組。

在 HeroesComponent 中訂閱

HeroService.getHeroes 方法之前返回一個 Hero[], 現(xiàn)在它返回的是 Observable<Hero[]>。

你必須在 HeroesComponent 中也向本服務中的這種形式看齊。

找到 getHeroes 方法,并且把它替換為如下代碼(和前一個版本對比顯示):

  1. Path:"heroes.component.ts (Observable)"
    getHeroes(): void {
      this.heroService.getHeroes()
          .subscribe(heroes => this.heroes = heroes);
    }

  1. Path:"heroes.component.ts (Original)"
    getHeroes(): void {
      this.heroes = this.heroService.getHeroes();
    }

Observable.subscribe() 是關鍵的差異點。

上一個版本把英雄的數(shù)組賦值給了該組件的 heroes 屬性。 這種賦值是同步的,這里包含的假設是服務器能立即返回英雄數(shù)組或者瀏覽器能在等待服務器響應時凍結界面。

HeroService 真的向遠端服務器發(fā)起請求時,這種方式就行不通了。

新的版本等待 Observable 發(fā)出這個英雄數(shù)組,這可能立即發(fā)生,也可能會在幾分鐘之后。 然后,subscribe() 方法把這個英雄數(shù)組傳給這個回調函數(shù),該函數(shù)把英雄數(shù)組賦值給組件的 heroes 屬性。

使用這種異步方式,當 HeroService 從遠端服務器獲取英雄數(shù)據(jù)時,就可以工作了。

顯示消息

這一節(jié)將指導你:

  • 添加一個 MessagesComponent,它在屏幕的底部顯示應用中的消息。

  • 創(chuàng)建一個可注入的、全應用級別的 MessageService,用于發(fā)送要顯示的消息。

  • MessageService 注入到 HeroService 中。

  • HeroService 成功獲取了英雄數(shù)據(jù)時顯示一條消息。

創(chuàng)建 MessagesComponent

使用 CLI 創(chuàng)建 MessagesComponent。

ng generate component messages

CLI 在 "src/app/messages" 中創(chuàng)建了組件文件,并且把 MessagesComponent 聲明在了 AppModule 中。

修改 AppComponent 的模板來顯示所生成的 MessagesComponent

Path:"src/app/message.service.ts"

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


@Injectable({
  providedIn: 'root',
})
export class MessageService {
  messages: string[] = [];


  add(message: string) {
    this.messages.push(message);
  }


  clear() {
    this.messages = [];
  }
}

該服務對外暴露了它的 messages 緩存,以及兩個方法:add() 方法往緩存中添加一條消息,clear() 方法用于清空緩存。

注入到 HeroService 中

在 HeroService 中導入 MessageService。

Path:"src/app/hero.service.ts (import MessageService)"

import { MessageService } from './message.service';

修改這個構造函數(shù),添加一個私有的 messageService 屬性參數(shù)。 Angular 將會在創(chuàng)建 HeroService 時把 MessageService 的單例注入到這個屬性中。

Path:"src/app/hero.service.ts"

constructor(private messageService: MessageService) { }

注:
- 這是一個典型的“服務中的服務”場景: 你把 MessageService 注入到了 HeroService 中,而 HeroService 又被注入到了 HeroesComponent 中。

從 HeroService 中發(fā)送一條消息

修改 getHeroes() 方法,在獲取到英雄數(shù)組時發(fā)送一條消息。

Path:"src/app/hero.service.ts"

getHeroes(): Observable<Hero[]> {
  // TODO: send the message _after_ fetching the heroes
  this.messageService.add('HeroService: fetched heroes');
  return of(HEROES);
}

從 HeroService 中顯示消息

MessagesComponent 可以顯示所有消息, 包括當 HeroService 獲取到英雄數(shù)據(jù)時發(fā)送的那條。

打開 MessagesComponent,并且導入 MessageService。

Path:"src/app/messages/messages.component.ts (import MessageService)"

import { MessageService } from '../message.service';

修改構造函數(shù),添加一個 public 的 messageService 屬性。 Angular 將會在創(chuàng)建 MessagesComponent 的實例時 把 MessageService 的實例注入到這個屬性中。

Path:"src/app/messages/messages.component.ts"

constructor(public messageService: MessageService) {}

這個 messageService 屬性必須是公共屬性,因為你將會在模板中綁定到它。

綁定到 MessageService

把 CLI 生成的 MessagesComponent 的模板改成這樣:

Path:"src/app/messages/messages.component.html"

<div *ngIf="messageService.messages.length">


  <h2>Messages</h2>
  <button class="clear"
          (click)="messageService.clear()">clear</button>
  <div *ngFor='let message of messageService.messages'> {{message}} </div>


</div>

這個模板直接綁定到了組件的 messageService 屬性上。

  • *ngIf 只有在有消息時才會顯示消息區(qū)。

  • *ngFor 用來在一系列 <div> 元素中展示消息列表。

  • Angular 的事件綁定把按鈕的 click 事件綁定到了 MessageService.clear()。

當你把 最終代碼 某一頁的內容添加到 messages.component.css 中時,這些消息會變得好看一些。

為 hero 服務添加額外的消息

下面的例子展示了當用戶點擊某個英雄時,如何發(fā)送和顯示一條消息,以及如何顯示該用戶的選取歷史。當你學到后面的路由一章時,這會很有幫助。

Path:"src/app/heroes/heroes.component.ts"

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


import { Hero } from '../hero';
import { HeroService } from '../hero.service';
import { MessageService } from '../message.service';


@Component({
  selector: 'app-heroes',
  templateUrl: './heroes.component.html',
  styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {


  selectedHero: Hero;


  heroes: Hero[];


  constructor(private heroService: HeroService, private messageService: MessageService) { }


  ngOnInit() {
    this.getHeroes();
  }


  onSelect(hero: Hero): void {
    this.selectedHero = hero;
    this.messageService.add(`HeroesComponent: Selected hero id=${hero.id}`);
  }


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

刷新瀏覽器,頁面顯示出了英雄列表。 滾動到底部,就會在消息區(qū)看到來自 HeroService 的消息。 點擊“清空”按鈕,消息區(qū)不見了。

查看最終代碼

  1. Path:"src/app/hero.service.ts"

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


    import { Observable, of } from 'rxjs';


    import { Hero } from './hero';
    import { HEROES } from './mock-heroes';
    import { MessageService } from './message.service';


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


      constructor(private messageService: MessageService) { }


      getHeroes(): Observable<Hero[]> {
        // TODO: send the message _after_ fetching the heroes
        this.messageService.add('HeroService: fetched heroes');
        return of(HEROES);
      }
    }

  1. Path:"src/app/message.service.ts"

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


    @Injectable({
      providedIn: 'root',
    })
    export class MessageService {
      messages: string[] = [];


      add(message: string) {
        this.messages.push(message);
      }


      clear() {
        this.messages = [];
      }
    }

  1. Path:"src/app/heroes/heroes.component.ts"

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


    import { Hero } from '../hero';
    import { HeroService } from '../hero.service';
    import { MessageService } from '../message.service';


    @Component({
      selector: 'app-heroes',
      templateUrl: './heroes.component.html',
      styleUrls: ['./heroes.component.css']
    })
    export class HeroesComponent implements OnInit {


      selectedHero: Hero;


      heroes: Hero[];


      constructor(private heroService: HeroService, private messageService: MessageService) { }


      ngOnInit() {
        this.getHeroes();
      }


      onSelect(hero: Hero): void {
        this.selectedHero = hero;
        this.messageService.add(`HeroesComponent: Selected hero id=${hero.id}`);
      }


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

  1. Path:"src/app/messages/messages.component.ts"

    import { Component, OnInit } from '@angular/core';
    import { MessageService } from '../message.service';


    @Component({
      selector: 'app-messages',
      templateUrl: './messages.component.html',
      styleUrls: ['./messages.component.css']
    })
    export class MessagesComponent implements OnInit {


      constructor(public messageService: MessageService) {}


      ngOnInit() {
      }


    }

  1. Path:"src/app/messages/messages.component.html"

    <div *ngIf="messageService.messages.length">


      <h2>Messages</h2>
      <button class="clear"
              (click)="messageService.clear()">clear</button>
      <div *ngFor='let message of messageService.messages'> {{message}} </div>


    </div>

  1. Path:"src/app/messages/messages.component.css"

    /* MessagesComponent's private CSS styles */
    h2 {
      color: red;
      font-family: Arial, Helvetica, sans-serif;
      font-weight: lighter;
    }
    body {
      margin: 2em;
    }
    body, input[text], button {
      color: crimson;
      font-family: Cambria, Georgia;
    }


    button.clear {
      font-family: Arial;
      background-color: #eee;
      border: none;
      padding: 5px 10px;
      border-radius: 4px;
      cursor: pointer;
      cursor: hand;
    }
    button:hover {
      background-color: #cfd8dc;
    }
    button:disabled {
      background-color: #eee;
      color: #aaa;
      cursor: auto;
    }
    button.clear {
      color: #333;
      margin-bottom: 12px;
    }

  1. Path:"src/app/app.module.ts"

    import { BrowserModule } from '@angular/platform-browser';
    import { NgModule } from '@angular/core';
    import { FormsModule } from '@angular/forms';
    import { AppComponent } from './app.component';
    import { HeroesComponent } from './heroes/heroes.component';
    import { HeroDetailComponent } from './hero-detail/hero-detail.component';
    import { MessagesComponent } from './messages/messages.component';


    @NgModule({
      declarations: [
        AppComponent,
        HeroesComponent,
        HeroDetailComponent,
        MessagesComponent
      ],
      imports: [
        BrowserModule,
        FormsModule
      ],
      providers: [
        // no need to place any providers due to the `providedIn` flag...
      ],
      bootstrap: [ AppComponent ]
    })
    export class AppModule { }

  1. Path:"src/app/app.component.html"

    <h1>{{title}}</h1>
    <app-heroes></app-heroes>
    <app-messages></app-messages>
以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號