Skip to content

Routing (一) | Angular 新手練功日誌

· 6 min

Angular 預設是一個單頁應用程式(SPA),為了實現不同頁面內容的切換,提供了強大的路由功能。透過路由,使用者可以根據網址(URL)的變化,動態顯示不同的元件,就像在多個頁面之間切換一樣,但實際上不需要重新載入整個網頁。這就是 client-side routing 的特點。

建立路由#

可以在 app.routes.ts 中透過建立 Routes 陣列來定義路由設定,每個路由物件包含以下主要的屬性

export const routes: Routes = [
{
path: '',
component: HomeComponent
},
{
path: 'tasks',
component: TasksComponent
}
]

建立完路由後,需要在 main.ts 中使用 provideRouter 來註冊路由設定,這樣應用程式才能識別並處理路由。

bootstrapApplication(AppComponent, {
providers: [provideRouter(routes)]
})

最後需要在應用程式的根元件模板中加入 router-outlet,來顯示根據路由設定所對應的元件內容。路由切換時,會在這個標籤內動態載入對應的元件。

需在元件中引入 RouterOutlet,才能在模板中使用 <router-outlet> 標籤。

import { RouterOutlet } from '@angular/router';
@Component({
...
imports: [RouterOutlet]
...
})
<router-outlet />

路由導航#

使用 router-link 指令來建立導航連結,點擊後會改變 URL 並觸發路由切換。

需要引入 RouterLink 指令,才能在模板中使用 routerLink 屬性。

import { RouterLink } from '@angular/router';
@Component({
...
imports: [RouterLink]
...
})
<a routerLink="/tasks">任務列表</a>

使用 .. 來導航到上一層父路由

queryParams:用來設定查詢參數

task-detail.component.html
<!-- 實際網址會變成 /users?ref=dashboard -->
<a [routerLink]="['..']" [queryParams]="{ ref: 'dashboard' }">返回使用者列表</a>

routerLinkActive 指令,用來為當前路由匹配的連結添加 CSS 類別,通常用於標示當前頁面。

需要引入 RouterLinkActive 指令,才能在模板中使用 routerLinkActive 屬性。

import { RouterLinkActive } from '@angular/router';
@Component({
...
imports: [RouterLinkActive]
...
})
<a routerLink="/tasks" routerLinkActive="active">任務列表</a>

需要在元件中使用程式導航時,可使用 Router 來直接導航到指定的路由。

export class SomeComponent {
private router = inject(Router);
goToTasks() {
this.router.navigate(['/tasks']);
}
}

若是提交表格後,想要禁止使用者使用瀏覽器的返回按鈕回到前一頁,可以使用 replaceUrl 選項來取代當前的歷史紀錄條目。

this.router.navigate(['/'], { replaceUrl: true });

動態路由#

可以在路由路徑中使用 :parameterName 來定義動態路由參數。

: 後面的參數名稱,可以自訂,但要與取得參數時使用的名稱一致。

{
path: 'tasks/:taskId', <domain>/tasks/1
component: TaskDetailComponent
}

在使用動態路由時,繫結連結需要傳入參數值時,可以使用字串拼接或陣列語法。

<a [routerLink]="'/tasks/' + task.id">{{ task.title }}</a>
<a [routerLink]="['/tasks', task.id]">{{ task.title }}</a>

而在元件中取得路由參數或查詢參數有兩種方式:

  1. 使用 input 可以取得路由參數或查詢參數

需要在 provideRouter 時使用 withComponentInputBinding,來啟用 input 綁定路由參數的功能。

bootstrapApplication(AppComponent, {
providers: [provideRouter(routes,withComponentInputBinding())]
})
export class TaskDetailComponent {
taskId = input<string>(); // 取得路由參數 taskId
query = input<string | null>(); // 取得查詢參數 query
// 例如: /tasks/1?query=angular
}
  1. 使用 ActivatedRoute 服務

paramMap:用來取得路由參數的 Observable 物件,可觀察路由參數的變化。

export class TaskDetailComponent {
private activatedRoute = inject(ActivatedRoute);
this.activatedRoute.paramMap.subscribe({
next: (params) => {
// 取得路由參數 taskId
conole.log(params.get('taskId'));
// 取得查詢參數 query
console.log(params['query']);
}
});
}

巢狀路由#

可以在路由設定中定義子路由,來建立巢狀的路由結構。

{
path: 'user/:userId',
component: UserComponent,
children: [
{
path: 'tasks,
component: TaskDetailComponent
}
]
}

也需要在父元件的模板中加入 <router-outlet>,來顯示子路由對應的元件。

<h2>任務列表</h2>
<router-outlet></router-outlet>

在巢狀路由中路徑是相對於父路由的,所以在內部中導航時,可不需要加上父元件的路徑。

<!-- 不需要加上父元件的路徑 -->
<a [routerLink]="[task]">{{ task.title }}</a>

若需要巢狀路由繼承父路由的參數的話,可以在 provideRouter 時使用 withRouterConfig 來設定 paramsInheritanceStrategy 路由引數的繼承策略,這樣才可以使用 input 的方式來取得父路由的參數。

bootstrapApplication(AppComponent, {
providers: [provideRouter(routes,withComponentInputBinding(),withRouterConfig({
paramsInheritanceStrategy: 'always'
}))]
})

結論#

今天介紹了 Angular 路由的基本概念與使用方式,包含建立路由、導航、動態路由以及巢狀路由等。明天會繼續介紹進階的路由相關功能。