iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 28
0
Modern Web

Angular 全集中筆記系列 第 28

第 28 型 - 路由 (Router) - Resolve / 延遲載入 (Lazy Router)

  • 分享至 

  • xImage
  •  

上一篇利用路由機制傳遞參數來實作待辦事項的編輯功能,除了透過網址路徑來傳遞所需要的參數,還可以在路由定義中透過 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) 來依模組為單位載入所需要的檔案。


上一篇
第 27 型 - 路由 (Router) - 參數傳遞
下一篇
第 29 型 - 單元測試 (Unit Testing)
系列文
Angular 全集中筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言