摘要:然后我們在父組件上添加事件監聽,并傳入本地的在對應的中添加方法再來,我們在子組件上多導入和,并添加修飾器和調用這樣就實現了我們父子組件之間的事件傳遞啦,現在我們的頁面還是正常運行,并且刪除一條數據后,頁面數據會更新。
本文目錄
一、項目起步
二、編寫路由組件
三、編寫頁面組件
1.編寫單一組件
2.模擬數據
3.編寫主從組件
四、編寫服務
1.為什么需要服務
2.編寫服務
五、引入RxJS
1.關于RxJS
2.引入RxJS
3.改造數據獲取方式
六、改造組件
1.添加歷史記錄組件
2.添加和刪除歷史記錄
七、HTTP改造
1.引入HTTP
2.通過HTTP請求數據
3.通過HTTP修改數據
4.通過HTTP增加數據
5.通過HTTP刪除數據
6.通過HTTP查找數據
本項目源碼放在github
六、改造組件從這里開始,我們要使用RxJS來改造組件和添加新功能了,讓整個項目更加完善。
1.添加歷史記錄組件創建HistoryComponent組件
ng g component hostory
然后在app.component.html文件夾中添加組件:
2.添加增刪改查功能
這里我們要開始做書本的增刪改查功能,需要先創建一個HistoryService服務,方便我們實現這幾個功能:
創建HistoryService服務
ng g service history
然后在生成的ts文件中,增加add和clear方法,add方法用來添加歷史記錄到history數組中,clear方法則是清空history數組:
// history.service.ts export class HistoryService { history: string[] = []; add(history: string){ this.history.push(history); } clear(){ this.history = []; } }
使用HistoryService服務
在將這個服務,注入到BooksService中,并改造getBooks方法:
// books.service.ts import { HistoryService } from "./history.service"; constructor( private historyservice: HistoryService ) { } getBooks(): void{ this.historyservice.add("請求書本數據") this.booksservice.getBookList() .subscribe(books => this.books = books); }
也可以用相同方法,在IndexComponent中添加訪問首頁書本列表的記錄。
// index.component.ts import { HistoryService } from "../history.service"; constructor( private booksservice: BooksService, private historyservice: HistoryService ) { } getBooks(): void{ this.historyservice.add("訪問首頁書本列表"); this.booksservice.getBookList() .subscribe(books => this.books = books); }
接下來,將我們的HistoryService注入到HistoryComponent中,然后才能將歷史數據顯示到頁面上:
// history.component.ts import { HistoryService } from "../history.service"; export class HistoryComponent implements OnInit { constructor(private historyservice: HistoryService) { } ngOnInit() {} }
操作歷史:
{{item}}
代碼解釋:
*ngIf="historyservice.history.length",是為了防止還沒有拿到歷史數據,導致后面的報錯。
(click)="historyservice.clear()", 綁定我們服務中的clear事件,實現清除緩存。
*ngFor="let item of historyservice.history",將我們的歷史數據渲染到頁面上。
到了這一步,就能看到歷史數據了,每次也換到首頁,都會增加一條。
接下來,我們要在書本詳情頁也加上歷史記錄的統計,導入文件,注入服務,然后改造getBooks方法,實現歷史記錄的統計:
// detail.component.ts import { HistoryService } from "../history.service"; export class DetailComponent implements OnInit { constructor( private route: ActivatedRoute, private location: Location, private booksservice: BooksService, private historyservice: HistoryService ) { } //... getBooks(id: number): void { this.books = this.booksservice.getBook(id); this.historyservice.add(`查看書本${this.books.title},id為${this.books.id}`); console.log(this.books) } }
這時候就可以在歷史記錄中,看到這些操作的記錄了,并且清除按鈕也正常使用。
七、HTTP改造原本我只想寫到上一章,但是想到,我們實際開發中,哪有什么本地數據,基本上數據都是要從服務端去請求,所以這邊也有必要引入這一張,模擬實際的HTTP請求。
1.引入HTTP在這一章,我們使用Angular提供的 HttpClient 來添加一些數據持久化特性。
然后實現對書本數據進行獲取,增加,修改,刪除和查找功能。
HttpClient是Angular通過 HTTP 與遠程服務器通訊的機制。
這里我們為了讓HttpClient在整個應用全局使用,所以將HttpClient導入到根模塊app.module.ts中,然后把它加入 @NgModule.imports 數組:
import { HttpClientModule } from "@angular/common/http"; @NgModule({ //... imports: [ BrowserModule, AppRoutingModule, HttpClientModule ], //... })
這邊我們使用 內存 Web API(In-memory Web API) 模擬出的遠程數據服務器通訊。
注意: 這個內存 Web API 模塊與 Angular 中的 HTTP 模塊無關。
通過下面命令來安裝:
npm install angular-in-memory-web-api --save
然后在app.module.ts中導入 HttpClientInMemoryWebApiModule 和 InMemoryDataService 類(后面創建):
// app.module.ts import { HttpClientInMemoryWebApiModule } from "angular-in-memory-web-api"; import { InMemoryDataService } from "./in-memory-data.service"; @NgModule({ // ... imports: [ // ... HttpClientInMemoryWebApiModule.forRoot( InMemoryDataService, {dataEncapsulation:false} ) ], // ... }) export class AppModule { }
知識點:
forRoot() 配置方法接受一個 InMemoryDataService 類(初期的內存數據庫)作為參數。
然后我們要創建InMemoryDataService類:
ng g service InMemoryData
并將生成的in-memory-data.service.ts修改為:
// in-memory-data.service.ts import { Injectable } from "@angular/core"; import { InMemoryDbService } from "angular-in-memory-web-api"; import { Books } from "./books"; @Injectable({ providedIn: "root" }) export class InMemoryDataService implements InMemoryDbService { createDb(){ const books = [ { id: 1, url: "https://img3.doubanio.com/view/subject/m/public/s29988481.jpg", title: "像火焰像灰燼", author: "程姬", }, // 省略其他9條數據 ]; return {books}; } constructor() { } }
這里先總結InMemoryDbService所提供的RESTful API,后面都要用到:
例如如果url是api/books,那么
查詢所有成員:以GET方法訪問api/books
查詢某個成員:以GET方法訪問api/books/id,比如id是1,那么訪問api/books/1
更新某個成員:以PUT方法訪問api/books/id
刪除某個成員:以DELETE方法訪問api/books/id
增加一個成員:以POST方法訪問api/books
2.通過HTTP請求數據現在要為接下來的網絡請求做一些準備,先在books.service.ts中引入HTTP符號,然后注入HttpClient并改造:
// books.service.ts import { HttpClient, HttpHeaders} from "@angular/common/http"; // ... export class BooksService { constructor( private historyservice: HistoryService, private http: HttpClient ) { } private log(histories: string){ this.historyservice.add(`正在執行:${histories}`) } private booksUrl = "api/books"; // 提供一個API供調用 // ... }
這里我們還新增一個私有方法log和一個私有變量booksUrl。
接下來我們要開始發起http請求數據,開始改造getBookList方法:
// books.service.ts // ... getBookList(): Observable{ this.historyservice.add("請求書本數據") return this.http.get (this.booksUrl); } // ...
這里我們使用 http.get 替換了 of,其它沒修改,但是應用仍然在正常工作,這是因為這兩個函數都返回了 Observable
實際開發中,我們還需要考慮到請求的錯誤處理,要捕獲錯誤,我們就要使用 RxJS 的 catchError() 操作符來建立對 Observable 結果的處理管道(pipe)。
我們引入catchError 并改造原本getBookList方法:
// books.service.ts getBookList(): Observable{ this.historyservice.add("請求書本數據") return this.http.get (this.booksUrl).pipe( catchError(this.handleError ("getHeroes", [])) ); } private handleError (operation = "operation", result?: T) { return (error: any): Observable => { this.log(`${operation} 失敗: ${error.message}`); // 發出錯誤通知 return of(result as T); // 返回空結果避免程序出錯 }; }
知識點:
.pipe() 方法用來擴展 Observable 的結果。
catchError() 操作符會攔截失敗的 Observable。并把錯誤對象傳給錯誤處理器,錯誤處理器會處理這個錯誤。
handleError() 錯誤處理函數做了兩件事,發出錯誤通知和返回空結果避免程序出錯。
這里還需要使用tap操作符改造getBookList方法,來窺探Observable數據流,它會查看Observable的值,然后我們使用log方法,記錄一條歷史記錄。
tap 回調不會改變這些值本身。
// books.service.ts getBookList(): Observable3.通過HTTP修改數據{ return this.http.get (this.booksUrl) .pipe( tap( _ => this.log("請求書本數據")), catchError(this.handleError ("getHeroes", [])) ); }
這里我們需要在原來DetailComponent上面,添加一個輸入框、保存按鈕和返回按鈕,就像這樣:
修改信息:
這邊切記一點,一定要在app.module.ts中引入 FormsModule模塊,并在@NgModule的imports中引入,不然要報錯了。
// app.module.ts // ... import { FormsModule } from "@angular/forms"; @NgModule({ // ... imports: [ // ... FormsModule ], // ... })
input框綁定書本的標題books.title,而保存按鈕綁定一個save()方法,這里還要實現這個方法:
// detail.component.ts save(): void { this.historyservice.updateBooks(this.books) .subscribe(() => this.goBack()); } goBack(): void { this.location.back(); }
這里通過調用BooksService的updateBooks方法,將當前修改后的書本信息修改到源數據中,這里我們需要去books.service.ts中添加updateBooks方法:
// books.service.ts // ... updateBooks(books: Books): Observable{ return this.http.put(this.booksUrl, books, httpOptions).pipe( tap(_ => this.log(`修改書本的id是${books.id}`)), catchError(this.handleError (`getBooks請求是id為${books.id}`)) ) } // ...
知識點:
HttpClient.put() 方法接受三個參數:URL 地址、要修改的數據和其他選項。
httpOptions 常量需要定義在@Injectable修飾器之前。
現在,我們點擊首頁,選擇一本書進入詳情,修改標題然后保存,會發現,首頁上這本書的名稱也會跟著改變呢。這算是好了。
4.通過HTTP增加數據我們可以新增一個頁面,并添加上路由和按鈕:
ng g component add
添加路由:
// app-routing.module.ts // ... import { AddComponent } from "./add/add.component"; const routes: Routes = [ { path: "", redirectTo:"/index", pathMatch:"full" }, { path: "index", component: IndexComponent}, { path: "detail/:id", component: DetailComponent}, { path: "add", component: AddComponent}, ]
添加路由入口:
添加書本
編輯添加書本的頁面:
添加書本:
初始化添加書本的數據:
// add.component.ts // ... import { Books } from "../books"; import { BooksService } from "../books.service"; import { HistoryService } from "../history.service"; import { Location } from "@angular/common"; export class AddComponent implements OnInit { books: Books = { id: 0, url: "", title: "", author: "" } constructor( private location: Location, private booksservice: BooksService, private historyservice: HistoryService ) { } ngOnInit() {} add(books: Books): void{ books.title = books.title.trim(); books.author = books.author.trim(); this.booksservice.addBooks(books) .subscribe( book => { this.historyservice.add(`新增書本${books.title},id為${books.id}`); this.location.back(); }); } }
然后在books.service.ts中添加addBooks方法,來添加一本書本的數據:
// books.service.ts addBooks(books: Books): Observable{ return this.http.post (this.booksUrl, books, httpOptions).pipe( tap((newBook: Books) => this.log(`新增書本的id為${newBook.id}`)), catchError(this.handleError ("添加新書")) ); }
現在就可以正常添加書本啦。
5.通過HTTP刪除數據這里我們先為每個書本后面添加一個刪除按鈕,并綁定刪除事件delete:
X
// books.component.ts import { BooksService } from "../books.service"; export class BooksComponent implements OnInit { @Input() list: Books; constructor( private booksservice: BooksService ) { } // ... delete(books: Books): void { this.booksservice.deleteBooks(books) .subscribe(); } }
然后還要再books.service.ts中添加deleteBooks方法來刪除:
// books.service.ts deleteBooks(books: Books): Observable{ const id = books.id; const url = `${this.booksUrl}/${id}`; return this.http.delete (url, httpOptions).pipe( tap(_ => this.log(`刪除書本${books.title},id為${books.id}`)), catchError(this.handleError ("刪除書本")) ); }
這里需要在刪除書本結束后,通知IndexComponent將數據列表中的這條數據刪除,這里還需要再了解一下Angular 父子組件數據通信。
然后我們在父組件IndexComponent上添加change事件監聽,并傳入本地的funChange:
在對應的index.component.ts中添加funChange方法:
// index.component.ts funChange(books, $event){ this.books = this.books.filter(h => h.id !== books.id); }
再來,我們在子組件BooksComponent上多導入Output和EventEmitter,并添加@Output()修飾器和調用emit:
import { Component, OnInit, Input, Output, EventEmitter } from "@angular/core"; export class BooksComponent implements OnInit { // ... @Output() change = new EventEmitter() // ... delete(books: Books): void { this.booksservice.deleteBooks(books) .subscribe(()=>{ this.change.emit(books); }); } }
這樣就實現了我們父子組件之間的事件傳遞啦,現在我們的頁面還是正常運行,并且刪除一條數據后,頁面數據會更新。
6.通過HTTP查找數據還是在books.service.ts,我們添加一個方法getBooks,來實現通過ID來查找指定書本,因為我們是通過ID查找,所以返回的是單個數據,這里就是Observable
// books.service.ts getBooks(id: number): Observable{ const url = `${this.booksUrl}/${id}`; return this.http.get (url).pipe( tap( _ => this.log(`請求書本的id為${id}`)), catchError(this.handleError (`getBooks請求是id為${id}`)) ) }
注意,這里 getBooks 會返回 Observable
這個項目其實很簡單,但是我還是一步一步的寫下來,一方面讓自己更熟悉Angular,另一方面也是希望能幫助到更多朋友哈~
最終效果:
本部分內容到這結束
Author | 王平安 |
---|---|
pingan8787@qq.com | |
博 客 | www.pingan8787.com |
微 信 | pingan8787 |
每日文章推薦 | https://github.com/pingan8787... |
JS小冊 | js.pingan8787.com |
微信公眾號 | 前端自習課 |
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/102024.html
摘要:編寫單一組件我們首先寫一個書本信息的組件,代碼如下單個課本像火焰像灰燼程姬知識點是一個的復寫器指令,就像中的和中的。寫到這里,看看我們項目,還是一樣正常在運行,只是現在項目中組件分工更加明確了。 本文目錄 一、項目起步 二、編寫路由組件 三、編寫頁面組件 1.編寫單一組件 2.模擬數據 3.編寫主從組件 四、編寫服務 1.為什么需要服務 2.編寫服務 五、...
摘要:發布通過回調方法向發布事件。觀察者一個回調函數的集合,它知道如何去監聽由提供的值。 本文目錄 一、項目起步 二、編寫路由組件 三、編寫頁面組件 1.編寫單一組件 2.模擬數據 3.編寫主從組件 四、編寫服務 1.為什么需要服務 2.編寫服務 五、引入RxJS 1.關于RxJS 2.引入RxJS 3.改造數據獲取方式 六、改造組件 1.添...
摘要:啟動服務,并打開新窗口可簡寫創建新組件可簡寫創建新服務創建路由模塊其他另外還有很多的命令提供,詳細可以查閱官方文檔命令。引入路由模塊導出路由模塊的指令這里需要添加一個數組,并傳入,導出讓路由器的相關指令可以在中的組件中使用。 本文目錄 一、項目起步 二、編寫路由組件 三、編寫頁面組件 1.編寫單一組件 2.模擬數據 3.編寫主從組件 四、編寫服務 1.為什么需要服務 2....
摘要:最終代碼省略其他輸入類型用標識查詢類型需要至少定義一個不要會不顯示查詢這里需要轉成數組因為前面定義了返回值是類型相當于數據庫的添加操作相當于數據庫的更新操作省略其他現在我們可以啟動服務器,在上測試下效果了。 showImg(https://segmentfault.com/img/remote/1460000019142304?w=893&h=438); 看完復聯四,我整理了這份 Gr...
摘要:由于之前安裝的是的版本,需要卸載了,安裝最新的版本。清除緩存,確保卸載干凈具體參考安裝最新版本安裝成功后提示意思是版的需要版本最低,我之前的是的版本。先安裝,去下載安裝。在命令行輸入檢查是否安裝成功。 最近聽了大漠老師分享的angular6的講解(附個鏈接大漠老師課程:http://www.ngfans.net/topic/2...),像是沙漠中發現了綠洲一樣,決定好好學習一番,于是準...
閱讀 1357·2021-11-24 09:39
閱讀 1346·2021-11-04 16:12
閱讀 2686·2021-09-24 09:47
閱讀 3337·2021-09-01 10:50
閱讀 1477·2019-08-30 15:55
閱讀 1423·2019-08-30 15:43
閱讀 642·2019-08-30 11:08
閱讀 3578·2019-08-23 18:33