第 28 型 - 路由 (Router) - Resolve / 延迟载入 (Lazy Router)

上一篇利用路由机制传递参数来实作待办事项的编辑功能,除了透过网址路径来传递所需要的参数,还可以在路由定义中透过 resolve 属性物件来指定 Resolve 服务,Angular 会先利用此服务取得资料後,才进行页面元件的载入。

利用路由 Resolve 属性预先取得资料

首先,在终端机执行 ng g s task/resolve/task-resolve 来建立 TaskResolveService,并在服务实作 Resolve<Task> 介面。

import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve } from '@angular/router';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class TaskResolveService implements Resolve<Task> {
  constructor() {}

  resolve(route: ActivatedRouteSnapshot): Observable<Task> | Promise<Task> | Task {}
}

接下来,会在 router() 方法实作待办事项资料取得,可以利用传入的 ActivatedRouteSnapshot 物件来取得待办事项编号。

import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve } from '@angular/router';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class TaskResolveService implements Resolve<Task> {
  constructor(private taskService: TaskRemoteService) {}

  resolve(route: ActivatedRouteSnapshot): Observable<Task> {
    const id = +route.paramMap.get('id');
    return this.taskService.get(id);
  }
}

然後在 app-routing.module.ts 中的待办事项编辑路由中,加入 resolve 物件属性,就可以让 Angular 在载入表单页面前取得待办事项资料。

const routes: Routes = [
  { path: '', pathMatch: 'full', redirectTo: 'main' },
  { path: 'main', component: MainPageComponent },
  { path: 'task-list', component: TaskPageComponent },
  { path: 'task-form', component: TaskFormComponent },
  {
    path: 'task-form/:id',
    component: TaskFormComponent,
    resolve: {
      task: TaskResolveService,
    },
  },
];

最後,在 task-form.component.ts 中,利用 ActivatedRoute 服务元件内的 data 属性来取得所传入的待办事项资料。

export class TaskFormComponent implements OnInit, OnDestroy {
  constructor(private fb: FormBuilder, private router: Router, private route: ActivatedRoute, private taskService: TaskRemoteService) {}

  ngOnInit(): void {
    this.route.data
      .pipe(
        map(({ task }: { task: Task }) => task),
        filter((task) => !!task),
        tap(() => this.tags.clear()),
        tap((task) => this.onAddTag(task.tags.length)),
        takeUntil(this.stop$)
      )
      .subscribe((task) => this.form.patchValue(task));
  }
}

延迟载入 (Lazy Loading)

利用 Chrome DevTool 可以看到目前所开发的程序,会封装成 main.js 载入至用户端。在开发较复杂的 Angular 应用程序时,有时会需要减少运行时所载入的 js 档案大小,以让使用者能更快速的看到页面内容。此时,就可以利用延迟载入 (Lazy Loading) 机制,在使用者选点页面时,才依模组为单位载入对应的 js 档案。

routing

首先,在 Task 模组中加入 task-routing.module.ts 档案,且将与待办事项相关的路由移至此,并在 Task 模组汇入。

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

import { TaskResolveService } from './resolve/task-resolve.service';
import { TaskFormComponent } from './task-form/task-form.component';
import { TaskPageComponent } from './task-page/task-page.component';

const routes: Routes = [
  { path: 'list', component: TaskPageComponent },
  { path: 'form', component: TaskFormComponent },
  {
    path: 'form/:id',
    component: TaskFormComponent,
    resolve: {
      task: TaskResolveService,
    },
  },
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule],
})
export class TaskRoutingModule {}

接着在 app-routing.module.ts 中利用 loadChildren 设定载入待办事项模组,当路由器导览到 task 路由时,会动态载入 Task 模组,并将 Task 模组内的路由加入配置中。另外,由於路由路径已调整,因此需要变更 app.component.html 中的导览列设定。

const routes: Routes = [
  { path: '', pathMatch: 'full', redirectTo: 'main' },
  { path: 'main', component: MainPageComponent },
  {
    path: 'task',
    loadChildren: () => import('./task/task.module').then((m) => m.TaskModule),
  },
];
<nav>
  <a [routerLink]="['main']" routerLinkActive="active">首页</a>
  <a [routerLink]="['task', 'list']" routerLinkActive="active">待办事项</a>
</nav>
<router-outlet></router-outlet>

需注意一点,由於 Task 模组将会被动态载入,所以在 app.module.ts 中需要移除本来汇入的 Task 模组。利用 Chrome DevTool 可以看到,原来的 main.js 档案大小减少,且在点选待办事项功能时会载入 task-task.module.js。

Lazy Loading

结论

这一篇利用 resolve 来预先取得页面所需要资料才载入页面元件;并利用延迟载入 (Lazy Loading) 来依模组为单位载入所需要的档案。


<<:  【这些年我似是非懂的 Javascript】Day 29 - 物件 # Part 5 # 特性存取的秘密

>>:  【Day-28】我们是怎麽开始的?:一间传统软件公司从 0 开始建置的 DevOps 文化(工具篇)- 敏捷看板

课堂笔记 - 深度学习 Deep Learning (16)

刚刚是一笔一笔资料带进去慢慢算出来,有另一种方式可以以次把资料全部带入并直接输出结果>>...

Day 25 : 插件篇 04 — 如何让 Obsidian 自动推荐关联笔记 (下)?介绍我的笔记架构与 Breadcrumbs 实战应用

介绍 这是 Obsidian 使用教学 — 应用篇的第 4 篇文章。 在 上一篇文章 中我介绍了 B...

自组NAS:针对unRaid

前面讲了那麽多,当然在部属unRaid还是要优先考虑设备的选择 当然用淘汰的旧电脑也是可以(小雨这次...

[Tableau Public] day 17:试着分析appstore资料集-2

某类型的App价格愈高,使用者平均评价也会有正相关吗? 这是个蛮有趣的议题,照理来说愈贵的app功能...

System Design: 读书心得4

正在写~ Problem: Need to increase Messenger’s perform...