【CuteJavaScript】Angular6入門項目(3.編寫服務和引入RxJS)

本文目錄

4、編寫服務

截止到這部分,咱們的BooksComponent組件獲取和顯示的都是本地模擬的數據。
接下來咱們要開始對這些進行重構,讓聚焦於爲它的視圖提供支持,這也讓它更容易使用模擬服務進行單元測試。html

1.爲何須要服務

咱們不該該讓組件來直接獲取或保存數據,它們應該聚焦於展現數據,而數據訪問的工做交給其餘服務來作。
這裏咱們須要建立一個名爲BooksService的服務,讓咱們應用中全部的類都使用它來獲取書本列表的數據,使用的時候,只須要將它經過Angular的依賴注入機制注入到須要用的組件的構造函數中。前端

知識點:
服務能夠實現多個不一樣組件之間信息共享,後面咱們還會將它注入到兩個地方:
BooksService中,使用該服務發送消息。
IndexService中,使用該服務來展現消息。git

接下來咱們使用命令行,建立BooksServicegithub

ng g service books

在生成的books.service.ts文件中:web

// books.service.ts
import { Injectable } from '@angular/core';
@Injectable({
  providedIn: 'root'
})

新導入了@Injectable裝飾器,是爲了讓BooksService提供一個可注入的服務,而且它還能夠擁有本身的待注入的依賴,簡單理解就是若是你的服務須要依賴,那麼你就須要導入它
而且它接收該服務的元數據對象。編程

2.編寫服務

接下來咱們開始編寫books.service.ts服務。數組

  • 導入服務所需組件

這裏咱們導入BooksBookList,並添加一個getBooks方法來返回全部書本的數據,而且還須要添加一個getBooks方法來返回指定id的書本信息:bash

// index.component.ts
import { Books } from './books';
import { BookList } from './mock-books';
@Injectable({
  providedIn: 'root'
})
export class BooksService {
  constructor() { }
  getBookList(): Books[] {
    return BookList;
  }
  getBook(id: number): Books{
    return BookList.find(book => book.id === id)
  }
}

在咱們使用這個服務以前,須要先註冊該服務,由於咱們在使用ng g service books命令建立服務時,CLI已經默認爲咱們添加了註冊了,這是方法就是上面代碼中的:服務器

providedIn: 'root'

表示將咱們的服務註冊在根注入器上,這樣咱們就能夠把這個服務注入到任何享用的類上了。微信

  • 修改IndexComponent

先刪除BookList的引入,並修改books屬性的定義:

// index.component.ts
import { BooksService } from '../books.service';
export class IndexComponent implements OnInit {
  books : Books[];
  ngOnInit() {}
}

而後注入咱們的BooksService服務,須要先往構造函數中添加一個私有的booksservice,使用注入的BooksService做爲類型,理解成一個注入點:

// index.component.ts
constructor(private booksservice: BooksService) { }

以後咱們須要添加一個getBooks方法來獲取這些書本數據,並在生命週期函數ngOnInit中調用:

export class IndexComponent implements OnInit {
  ngOnInit() {
    this.getBooks();
  }
  getBooks(): void{
    this.books = this.booksservice.getBookList();
  }
}
  • 修改DetailComponent
    咱們先改造書本詳情頁的HTML結構:
<!-- detail.component.html -->
<div *ngIf="books" class="detail">
  <h3>《{{books.title}}》介紹</h3>
  <div>
    <img src="{{books.url}}">
  </div>
  <p>書本標題: {{books.title}}</p>
  <p>書本做者: {{books.author}}</p>
  <p>書本id: {{books.id}}</p>
</div>
<div *ngIf="!books" class="detail">
  <h3>暫無信息</h3>
</div>

知識點
這裏使用了*ngIf指令,當條件爲true則顯示其HTML內容。

// detail.component.ts
import { Books } from '../books';
import { BooksService } from '../books.service';
export class DetailComponent implements OnInit {
  constructor(
    private route: ActivatedRoute,
    private location: Location,
    private booksservice: BooksService  // 引入BooksService服務
  ) { }

  books: Books;  // 定義books類型
  ngOnInit() {
    this.getDetail()
  }
  getDetail(): void{
    const id = +this.route.snapshot.paramMap.get('id');
    this.getBooks(id);
  }
  getBooks(id: number): void {
    this.books = this.booksservice.getBook(id);
  }
}

這段代碼,主要定義了getBooks方法,當剛進入頁面時,將書本id傳入getBooks方法,去BooksService去獲取對應id的書本信息,並複製給變量books,而後展現到頁面。

改造以後,咱們的頁面顯示依舊正常。

圖片3-2

可是咱們要知道,這背後的邏輯已經改變了。

5、引入RxJS改造項目

1.關於RxJS

這裏簡單介紹關鍵概念,具體能夠查看 RxJS 官網,也能夠參考 淺析Angular之RxJS

什麼是RxJS

RxJS全稱Reactive Extensions for JavaScript,中文意思: JavaScript的響應式擴展。
RxJS主要是提供一種更增強大和優雅的方式,來利用響應式編程的模式,實現JavaScript的異步編程。

RxJS優勢

  • 純淨性;
  • 流動性;

RxJS核心概念

RxJS 是基於觀察者模式和迭代器模式以函數式編程思惟來實現的。RxJS 中含有兩個基本概念:ObservablesObserver
Observables 做爲被觀察者,是一個值或事件的流集合;而 Observer 則做爲觀察者,根據 Observables 進行處理。它們之間的訂閱發佈關係(觀察者模式) 以下:
訂閱Observer 經過 Observable 提供的 subscribe() 方法訂閱 Observable
發佈Observable 經過回調 next 方法向 Observer 發佈事件。

———— 來源Angular修仙之路 RxJS Observable

另外這裏列出來一些核心,具體仍是看官網咯,而且下面使用到的時候會具體介紹。

  • Observable (可觀察對象): 表示一個概念,這個概念是一個可調用的將來值或事件的集合。
  • Observer(觀察者): 一個回調函數的集合,它知道如何去監聽由 Observable 提供的值。
  • Subscription (訂閱): 表示 Observable 的執行,主要用於取消 Observable 的執行。
  • Operators (操做符): 採用函數式編程風格的純函數 (pure function),使用像 mapfilterconcatflatMap 等這樣的操做符來處理集合。
  • Subject (主體): 至關於 EventEmitter,而且是將值或事件多路推送給多個 Observer 的惟一方式。
  • Schedulers (調度器): 用來控制併發而且是中央集權的調度員,容許咱們在發生計算時進行協調,例如 setTimeoutrequestAnimationFrame或其餘。

2.引入RxJS

在咱們的真實應用中,咱們必需要等到服務器響應後,咱們才能獲取到數據,所以這天生就須要用異步思惟來操做。

因爲Angular中已經自帶RxJS,因此咱們只要在須要使用的時候,引入便可使用:

3.改造數據獲取方式

瞭解完RxJS的一些概念後,咱們開始改造下這些書本的數據獲取方式。

  • 改造BooksService

首先咱們從 RxJS 中導入 Observableof 符號:

// books.service.ts
import { Observable, of } from 'rxjs';

知識點
Observable: 觀察者模式中的觀察者,具體能夠參考 Angular修仙之路 RxJS Observable
of: 用來獲取觀察者拿到的數據,一般是一個Observable

而後修改getBookList方法

// books.service.ts
getBookList(): Observable<Books[]> {
  return of(BookList);
}

這裏 of(BookList) 返回一個Observable<Books[]>,它會發出單個值,這個值就是這些模擬書本的數組。

  • 改造IndexComponent

這裏也要修改getBooks方法,使用subscribe去訂閱服務返回回來的值:

// index.component.ts
getBooks(): void{
  this.booksservice.getBookList()
    .subscribe(books => this.books = books);
}

因爲本來直接賦值數據,在實際場景中是不可能這樣同步的,因此這裏subscribe函數,會在Observable發出數據之後,再把書本列表傳到裏面的回調函數,再複製給books屬性。
使用這種異步方式,當 BooksService 從遠端服務器獲取英雄數據時,不用擔憂還沒拿到數據就執行後面。

下一步,咱們就要改造一下項目了。

本部份內容到這結束

Author 王平安
E-mail pingan8787@qq.com
博 客 www.pingan8787.com
微 信 pingan8787
每日文章推薦 https://github.com/pingan8787/Leo_Reading/issues
JS小冊 js.pingan8787.com
微信公衆號 前端自習課

前端自習課

相關文章
相關標籤/搜索