聊聊Angular Route中怎麼提前獲取資料

2022-07-13 22:00:31
Angular Route中怎麼提前獲取資料?下面本篇文章給大家介紹一下從 Angular Route 中提前獲取資料的方法,希望對大家有所幫助!

提前獲取意味著在資料呈現在螢幕之前獲取到資料。本文中,你將學到,在路由更改前怎麼獲取到資料。通過本文,你將學會使用 resolver, 在 Angular App 中應用 resolver,應用到一個公共的預載入導航。【相關教學推薦:《》】

你為什麼應該使用 Resolver

Resolver 在路由跟元件之間扮演著中介軟體服務的角色。假設你有一個表單,沒有資料時,你想向使用者一個空的表單,當在載入使用者資料時展示一個 loader,然後當資料返回時,填充表單並隱藏 loader

通常,我們都會在元件的 ngOnInit() 勾點函數中獲取資料。也就是說,元件載入完之後,我們發起資料請求。

ngOnInit() 中操作,我們需要在每個需要的元件載入後,在其路由頁面中新增 loader 展示。Resolver 可以簡化 loader 的新增使用。你可以只新增一個適用於每個路由的 loader,而不是每個路由中都新增 loader

本文將結合範例來解析 resolver 的知識點。以便於你可以牢記它並在專案中使用它。

在應用中使用 Resolver

為了在應用中使用 resolver,你需要準備一些介面。你可以通過 JSONPlaceholder 來模擬,而不需要自己開發。

JSONPlaceholder 是一個很棒的介面資源,你可以藉助它更好學習前端的相關概念而不被介面所約束。

現在,介面的問題解決了,我們可以開始 resolver 的應用了。一個 resolver 就是一箇中介軟體服務,所以我們將建立一個服務。

$ ng g s resolvers/demo-resolver --skipTests=true

--skipTests=true 跳過生成測試檔案

src/app/resolvers 資料夾中建立了一個服務。resolver 介面中有一個 resolve() 方法,它有兩個引數:routeActivatedRouteSnapshot 的範例)和 state(RouterStateSnapshot 的範例)。

loader 通常是在 ngOnInit() 中編寫所有的 AJAX 請求,但是邏輯將會在 resolver 中實現,替代 ngOnInit()

接著,建立一個服務來獲取 JSONPlaceholder 中列表資料。然後在 resolver 中底呼叫,接著在路由中設定 resolve資訊,(頁面將會等待)直到 resolver 被處理。在 resolver 被處理之後,我們可以通過路由來獲取資料然後展示在元件中。

建立服務並編寫邏輯獲取列表資料

$ ng g s 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 } from "@angular/core";
import { HttpClient } from "@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
} from "@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 g c 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 } from "@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
} from "@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,頁面中,你將看到下面的效果。

1.png

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 中。效果如下快照。

2.png

至此,你已經瞭解完怎麼應用 resolver 在你的專案中了。

總結

結合使用者體驗設計,在 resolver 的加持下,你可以提升你應用的表現。瞭解更多,你可以戳官網

本文是譯文,採用的是意譯的方式,其中加上個人的理解和註釋,原文地址是:

https://www.pluralsight.com/guides/prefetching-data-for-an-angular-route

更多程式設計相關知識,請存取:!!

以上就是聊聊Angular Route中怎麼提前獲取資料的詳細內容,更多請關注TW511.COM其它相關文章!