
提前獲取意味著在資料呈現在螢幕之前獲取到資料。本文中,你將學到,在路由更改前怎麼取得到資料。透過本文,你將學會使用resolver , 在Angular App中應用resolver ,應用到一個公共的預載導航。 【相關教學推薦:《angular教學】
ResolverResolver在路由跟元件之間扮演中介軟體服務的角色。假設你有一個表單,沒有資料時,你想要向使用者一個空的表單,當在載入使用者資料時顯示一個loader ,然後當資料回傳時,填入表單並隱藏loader 。
通常,我們都會在組件的ngOnInit()鉤子函數中取得資料。也就是說,元件載入完之後,我們發起資料請求。
在ngOnInit()中操作,我們需要在每個需要的元件載入後,在其路由頁面中加入loader展示。 Resolver可以簡化loader的添加使用。你可以只新增一個適用於每個路由的loader ,而不是每個路由中都新增loader 。
本文將結合範例來解析resolver的知識點。以便於你可以牢記它並在專案中使用它。
Resolver為了在應用程式中使用resolver ,你需要準備一些介面。你可以透過JSONPlaceholder 來模擬,而不需要自己開發。
JSONPlaceholder是一個很棒的介面資源,你可以藉助它來更好地學習前端的相關概念而不被介面所約束。
現在,介面的問題解決了,我們可以開始resolver的應用了。一個resolver就是一個中間件服務,所以我們將創造一個服務。
$ ng gs resolvers/demo-resolver --skipTests=true
--skipTests=true 跳過生成測試檔案
src/app/resolvers資料夾中建立了一個服務。 resolver介面中有一個resolve()方法,它有兩個參數: route ( ActivatedRouteSnapshot的實例)和state ( RouterStateSnapshot的實例)。
loader通常是在ngOnInit()中編寫所有的AJAX請求,但是邏輯將會在resolver中實現,替代ngOnInit() 。
接著,建立一個服務來取得JSONPlaceholder中列表資料。然後在resolver中底調用,接著在路由中配置resolve訊息,(頁面將會等待)直到resolver被處理。在resolver被處理之後,我們可以透過路由來取得資料然後展示在元件中。
$ ng gs services/posts --skipTests=true
現在,我們成功創建了服務,是時候編寫一個AJAX請求的邏輯了。
model的使用能夠幫助我們減少錯誤。
$ ng g class models/post --skipTests=true
post.ts
export class Post { id: number;
title: string;
body: string;
userId: string;
} model就緒,是時候取得貼文post的資料了。
post.service.ts
import { Injectable } 從 "@angular/core";
import { HttpClient } 從 "@angular/common/http";
import { Post } from "../models/post";
@Injectable({
providedIn: "root"
})
export class PostsService {
constructor(private _http: HttpClient) {}
getPostList() {
let URL = "https://jsonplaceholder.typicode.com/posts";
return this._http.get<Post[]>(URL);
}
}現在,這個服務隨時可被呼叫。
demo-resolver.service.ts
import { Injectable } from "@angular/core";
import {
Resolve,
ActivatedRouteSnapshot,
RouterStateSnapshot
} 從 "@angular/router";
import { PostsService } from "../services/posts.service";
@Injectable({
providedIn: "root"
})
export class DemoResolverService implements Resolve<any> {
constructor(private _postsService: PostsService) {}
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
return this._postsService.getPostList();
}
}帖子列表資料從resolver中返回。現在,你需要一個路由去設定resolver ,從路由取得數據,然後讓數據展示在元件中。為了進行路由跳轉,我們需要建立一個元件。
$ ng gc components/post-list --skipTests=true
為了路由可見,在app.component.ts新增router-outlet 。
<router-outlet></router-outlet>
現在,你可以設定app-routing.module.ts檔了。下面的片段程式碼將有助於你理解路由配置resolver 。
app-routing-module.ts
import { NgModule } from "@angular/core";
import { Routes, RouterModule } 從 "@angular/router";
import { PostListComponent } from "./components/post-list/post-list.component";
import { DemoResolverService } from "./resolvers/demo-resolver.service";
const routes: Routes = [
{
path: "posts",
component: PostListComponent,
resolve: {
posts: DemoResolverService
}
},
{
path: "",
redirectTo: "posts",
pathMatch: "full"
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {}一個resolve已經加入到路由配置中了,它將發起一個HTTP請求,然後當HTTP請求成功返回後,允許元件初始化。路由將組裝取得到的HTTP請求傳回的資料。
來向使用者展示一個請求正在進行,我們在AppComponent中編寫一個公共且簡單的loader 。你可以根據需要自訂。
app.component.html
<div class="loader" *ngIf="isLoader"> <div>Loading...</div> </div> <router-outlet></router-outlet>
app.component.ts
import { Component } from "@angular/core";
import {
Router,
RouterEvent,
NavigationStart,
NavigationEnd
} 從 "@angular/router";
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.scss"]
})
export class AppComponent {
isLoader: boolean;
constructor(private _router: Router) {}
ngOnInit() {
this.routerEvents();
}
routerEvents() {
this._router.events.subscribe((event: RouterEvent) => {
switch (true) {
case event instanceof NavigationStart: {
this.isLoader = true;
break;
}
case event instanceof NavigationEnd: {
this.isLoader = false;
break;
}
}
});
}
}當導覽開始, isLoader值被賦予true ,頁面中,你將看到下面的效果。

當resolver處理完之後,它將會被隱藏。
現在,是時候從路由中獲取值並將其顯示出來。
port-list.component.ts
import { Component, OnInit } from "@angular/core";
import { Router, ActivatedRoute } from "@angular/router";
import { Post } from "src/app/models/post";
@Component({
selector: "app-post-list",
templateUrl: "./post-list.component.html",
styleUrls: ["./post-list.component.scss"]
})
export class PostListComponent implements OnInit {
posts: Post[];
constructor(private _route: ActivatedRoute) {
this.posts = [];
}
ngOnInit() {
this.posts = this._route.snapshot.data["posts"];
}
}如上所示, post的值來自ActivatedRoute的快照資訊data 。這值都可以獲取,只要你在路由中配置了相同的資訊。
我們在HTML進行如下渲染。
<div class="post-list grid-container">
<div class="card" *ngFor="let post of posts">
<div class="title"><b>{{post?.title}}</b></div>
<div class="body">{{post.body}}</div>
</div>
</div> CSS片段樣式讓其看起來更美觀。
port-list.component.css
.grid-container {
display: grid;
grid-template-columns: calc(100% / 3) calc(100% / 3) calc(100% / 3);
}
.card {
margin: 10px;
box-shadow: black 0 0 2px 0px;
padding: 10px;
}推薦使用scss 預處理器編寫樣式
從路由中取得資料之後,它會被展示在HTML中。效果如下快照。

至此,你已經了解完怎麼應用resolver在你的專案中了。
結合使用者體驗設計,在resolver的加持下,你可以提升你應用程式的表現。了解更多,你可以戳官網。
本文是譯文,採用的是意譯的方式,其中加上個人的理解和註釋,原文地址是:
https://www.pluralsight.com/guides/prefetching-data-for-an-angular-route