1. 前言
开发中我们可能会遇到这样一个问题:路由到一个新的页面前可能需要某些数据才能在要加载的新页面请求数据,这个时候如果我们路由到新页面再去获取预先的数据有可能来不及或者是带来不好的用户体验。这个时候如果有一种办法能在即将加载新页面的时候就预准备好了必要数据,等到加载新页面的时候整好可以拿到数据,那就很完美了。Angular Router Resolve就是这样的一种存在!
以下是例子
2. 第1步:创建用户组件
创建一个用户模块,假设我们一进到页面就要先拿到用户数据。在组件内部,可以通过注入ActivatedRoute来加载预取数据。
1 | import { Component, OnInit } from '@angular/core'; |
2 | import { Observable } from 'rxjs'; |
3 | import { ActivatedRoute } from '@angular/router'; |
4 | import { User } from './user'; |
5 | import { ApiService } from './api.service'; |
6 | |
7 | ({ |
8 | selector: 'app-editor', |
9 | template: ` |
10 | <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> |
11 | <div class="row"> |
12 | <div class="col-md-3 mb-3" *ngFor="let user of users"> |
13 | <div class="card"> |
14 | <div class="card-body"> |
15 | <h5 class="card-title">{{user.name}}</h5> |
16 | <p class="card-text">{{user.username}}</p> |
17 | <a [href]="'http://www.'+user.website" class="btn btn-primary">{{user.website}}</a> |
18 | </div> |
19 | </div> |
20 | </div> |
21 | </div> |
22 | `, |
23 | styles: [``] |
24 | }) |
25 | export class UserComponent implements OnInit { |
26 | users: Observable<User[]>; |
27 | |
28 | constructor( |
29 | private api: ApiService, |
30 | private router: ActivatedRoute |
31 | ) { |
32 | this.users = this.router.snapshot.data.users; // 获取到预加载的数据 |
33 | console.log(this.users); |
34 | } |
35 | |
36 | ngOnInit() {} |
37 | |
38 | } |
3. 第2步:创建用户服务
创建一个service用于网络请求获取数据。
1 | import { Injectable } from '@angular/core'; |
2 | import { HttpClient } from '@angular/common/http'; |
3 | import { User } from './user'; |
4 | |
5 | () |
6 | export class ApiService { |
7 | url = 'https://jsonplaceholder.typicode.com/users'; |
8 | |
9 | constructor( |
10 | private http: HttpClient |
11 | ) { } |
12 | |
13 | getUsers() { |
14 | return this.http.get<User[]>(this.url); |
15 | } |
16 | } |
4. 第3步:创建用户模型
创建数据Modal,这里有快捷方式,VSCode也有对应插件:JSON to ,或者使用在线版本的:JsonToTs
1 | export class User { |
2 | id: number; |
3 | name: string; |
4 | username: string; |
5 | email: string; |
6 | address: Address; |
7 | phone: string; |
8 | website: string; |
9 | company: Company; |
10 | } |
11 | |
12 | export class Company { |
13 | name: string; |
14 | catchPhrase: string; |
15 | bs: string; |
16 | } |
17 | |
18 | export class Address { |
19 | street: string; |
20 | suite: string; |
21 | city: string; |
22 | zipcode: string; |
23 | geo: Geo; |
24 | } |
25 | |
26 | export class Geo { |
27 | lat: string; |
28 | lng: string; |
29 | } |
5. 第4步:创建路由Resolve
实现Resolve接口的同时要重写resolve()方法,方法有两参数:ActivatedRouteSnapshot 和RouterStateSnaphot,这里用不到,主要返回我们想要预加载的数据的Observable(或promise或数据本身)。
1 | import { Injectable } from '@angular/core'; |
2 | import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; |
3 | import { Observable } from 'rxjs'; |
4 | import { User } from './user'; |
5 | import { ApiService } from './api.service'; |
6 | |
7 | ({ |
8 | providedIn: 'root' // angular6新引入的装饰器配置,如果指定了'root'模式,就不用在任何@NgModule()装饰器中declarations(声明) |
9 | }) |
10 | export class UserResolveGuard implements Resolve<User[]> { |
11 | |
12 | constructor( |
13 | private apiService: ApiService |
14 | ) { } |
15 | |
16 | resolve( |
17 | route: ActivatedRouteSnapshot, |
18 | state: RouterStateSnapshot |
19 | ): Observable<any> | Promise<any> | any { |
20 | return this.apiService.getUsers(); |
21 | } |
22 | } |
6. 第5步:路由配置
在路由中,指定接受对象的resolve属性,它将通过路由器数据携带指定组件的预取或预加载数据。
1 | import { NgModule } from '@angular/core'; |
2 | import { Routes, RouterModule } from '@angular/router'; |
3 | import { UserComponent } from './user.component'; |
4 | import { UserResolveGuard } from './user.guard'; |
5 | |
6 | const routes: Routes = [ |
7 | { path: 'edit', component: UserComponent, resolve: { users: UserResolveGuard} } |
8 | ]; |
9 | |
10 | ({ |
11 | imports: [RouterModule.forRoot(routes)], |
12 | exports: [RouterModule] |
13 | }) |
14 | export class AppRoutingModule { } |