本文目錄
- 一、專案起步
- 二、編寫路由元件
- 三、編寫頁面元件
- 四、編寫服務
- 1.為什麼需要服務
- 2.編寫服務
- 五、引入RxJS
- 1.關於RxJS
- 2.引入RxJS
- 3.改造資料獲取方式
- 六、改造元件
- 1.新增歷史記錄元件
- 2.新增和刪除歷史記錄
- 七、HTTP改造
- 1.引入HTTP
- 2.通過HTTP請求資料
- 3.通過HTTP修改資料
- 4.通過HTTP增加資料
- 5.通過HTTP刪除資料
- 6.通過HTTP查詢資料
本專案原始碼放在github
四、編寫服務
截止到這部分,我們的BooksComponent
元件獲取和顯示的都是本地模擬的資料。
接下來我們要開始對這些進行重構,讓聚焦於為它的檢視提供支援,這也讓它更容易使用模擬服務進行單元測試。
1.為什麼需要服務
我們不應該讓元件來直接獲取或儲存資料,它們應該聚焦於展示資料,而資料訪問的工作交給其他服務來做。
這裡我們需要建立一個名為BooksService
的服務,讓我們應用中所有的類都使用它來獲取書本列表的資料,使用的時候,只需要將它通過Angular的依賴注入機制注入到需要用的元件的建構函式中。
知識點:
服務可以實現多個不同元件之間資訊共享,後面我們還會將它注入到兩個地方:
BooksService
中,使用該服務傳送訊息。
IndexService
中,使用該服務來展示訊息。
接下來我們使用命令列,建立BooksService
:
ng g service books
複製程式碼
在生成的books.service.ts
檔案中:
// books.service.ts
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
複製程式碼
新匯入了@Injectable
裝飾器,是為了讓BooksService
提供一個可注入的服務,並且它還可以擁有自己的待注入的依賴,簡單理解就是如果你的服務需要依賴,那麼你就需要匯入它。
並且它接收該服務的後設資料物件。
2.編寫服務
接下來我們開始編寫books.service.ts
服務。
- 匯入服務所需元件
這裡我們匯入Books
和BookList
,並新增一個getBooks
方法來返回所有書本的資料,並且還需要新增一個getBooks
方法來返回指定id的書本資訊:
// 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
,然後展示到頁面。
改造之後,我們的頁面顯示依舊正常。
但是我們要知道,這背後的邏輯已經改變了。
五、引入RxJS改造專案
1.關於RxJS
這裡簡單介紹關鍵概念,具體可以檢視 RxJS 官網,也可以參考 淺析Angular之RxJS。
什麼是RxJS
RxJS全稱Reactive Extensions for JavaScript
,中文意思: JavaScript的響應式擴充套件。
RxJS主要是提供一種更加強大和優雅的方式,來利用響應式程式設計的模式,實現JavaScript的非同步程式設計。
RxJS優點
- 純淨性;
- 流動性;
RxJS核心概念
RxJS 是基於觀察者模式和迭代器模式以函數語言程式設計思維來實現的。RxJS 中含有兩個基本概念:Observables
與 Observer
。
Observables
作為被觀察者,是一個值或事件的流集合;而 Observer
則作為觀察者,根據 Observables
進行處理。它們之間的訂閱釋出關係(觀察者模式) 如下:
訂閱:Observer
通過 Observable
提供的 subscribe()
方法訂閱 Observable
。
釋出:Observable
通過回撥 next
方法向 Observer
釋出事件。
———— 來源Angular修仙之路 RxJS Observable
另外這裡列出來一些核心,具體還是看官網咯,並且下面使用到的時候會具體介紹。
Observable
(可觀察物件): 表示一個概念,這個概念是一個可呼叫的未來值或事件的集合。Observer
(觀察者): 一個回撥函式的集合,它知道如何去監聽由Observable
提供的值。Subscription
(訂閱): 表示Observable
的執行,主要用於取消Observable
的執行。Operators
(操作符): 採用函數語言程式設計風格的純函式 (pure function
),使用像map
、filter
、concat
、flatMap
等這樣的操作符來處理集合。Subject
(主體): 相當於EventEmitter
,並且是將值或事件多路推送給多個Observer
的唯一方式。Schedulers
(排程器): 用來控制併發並且是中央集權的排程員,允許我們在發生計算時進行協調,例如setTimeout
或requestAnimationFrame
或其他。
2.引入RxJS
在我們的真實應用中,我們必須要等到伺服器響應後,我們才能獲取到資料,因此這天生就需要用非同步思維來操作。
由於Angular中已經自帶RxJS,所以我們只要在需要使用的時候,引入即可使用:
3.改造資料獲取方式
瞭解完RxJS的一些概念後,我們開始改造下這些書本的資料獲取方式。
- 改造
BooksService
首先我們從 RxJS 中匯入 Observable
和 of
符號:
// 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 | 王平安 |
---|---|
pingan8787@qq.com | |
博 客 | www.pingan8787.com |
微 信 | pingan8787 |
每日文章推薦 | https://github.com/pingan8787/Leo_Reading/issues |
JS小冊 | js.pingan8787.com |
微信公眾號 | 前端自習課 |