Angular Router 讓你能讀取並使用與路由相關聯的資訊,藉此建立反應敏捷且具上下文感知能力的元件。
透過 ActivatedRoute 取得目前路由的資訊
ActivatedRoute 是來自 @angular/router 的服務,提供與目前路由相關聯的全部資訊。
import {Component, inject} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
@Component({
selector: 'app-product',
})
export class Product {
private activatedRoute = inject(ActivatedRoute);
constructor() {
console.log(this.activatedRoute);
}
}
ActivatedRoute 能提供關於路由的各種不同資訊,一些常見的屬性包括:
| Property | Details |
|---|---|
url |
路由路徑的 Observable,以 UrlSegment 物件的陣列表示路徑的每個部分。 |
data |
一個 Observable,包含為該路由提供的 data 物件,也包含解析守衛所解析出的任何值。 |
params |
一個 Observable,包含該路由特有的必要與選擇性參數。 |
queryParams |
一個 Observable,包含所有路由皆可使用的查詢參數。 |
resources |
一個選擇性的唯讀 Resource 執行個體記錄,定義於路由上或由路由繼承而來(需要 withRouterResources())。 |
請參閱 ActivatedRoute API 文件,取得你可以透過路由存取之內容的完整清單。
了解路由快照
頁面導覽是隨著時間發生的事件,你可以擷取路由快照,來存取 Router 在某個時間點的狀態。
路由快照包含關於路由的必要資訊,包括它的參數、資料與子路由。此外,快照是靜態的,不會反映未來的變化。
以下是如何存取路由快照的範例:
import {Component, inject} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
@Component(/* ... */)
export class UserProfile {
readonly userId: string | null;
private route = inject(ActivatedRoute);
constructor() {
// Example URL: https://www.angular.dev/users/123?role=admin&status=active#contact
// Access route parameters from snapshot
this.userId = this.route.snapshot.paramMap.get('id');
// Access multiple route elements
const snapshot = this.route.snapshot;
console.log({
url: snapshot.url, // Array of UrlSegments matched by this route
// Route parameters object: {id: '123'}
params: snapshot.params,
// Query parameters object: {role: 'admin', status: 'active'}
queryParams: snapshot.queryParams, // Query parameters
});
}
}
請參閱 ActivatedRoute API 文件 與 ActivatedRouteSnapshot API 文件,取得你可以存取之所有屬性的完整清單。
讀取路由上的參數
開發者可以從路由利用兩種類型的參數:路由參數與查詢參數。
路由參數
路由參數讓你能透過 URL 將資料傳遞給元件。當你想根據 URL 中的識別碼(例如使用者 ID 或產品 ID)來顯示特定內容時,這非常有用。
你可以透過在參數名稱前加上冒號(:),來定義路由參數。
import {Routes} from '@angular/router';
import {Product} from './product';
const routes: Routes = [{path: 'product/:id', component: Product}];
你可以訂閱 route.params 來存取參數。
import {Component, inject, signal} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
@Component({
selector: 'app-product-detail',
template: `<h1>Product Details: {{ productId() }}</h1>`,
})
export class ProductDetail {
productId = signal('');
private activatedRoute = inject(ActivatedRoute);
constructor() {
// Access route parameters
this.activatedRoute.params.subscribe((params) => {
this.productId.set(params['id']);
});
}
}
查詢參數
查詢參數 提供了一種靈活的方式,透過 URL 傳遞選擇性資料,而不會影響路由結構。與路由參數不同,查詢參數可以在多次導覽事件之間持續存在,非常適合處理篩選、排序、分頁,以及其他具狀態性的 UI 元素。
// Single parameter structure
// /products?category=electronics
router.navigate(['/products'], {
queryParams: {category: 'electronics'},
});
// Multiple parameters
// /products?category=electronics&sort=price&page=1
router.navigate(['/products'], {
queryParams: {
category: 'electronics',
sort: 'price',
page: 1,
},
});
你可以使用 route.queryParams 來存取查詢參數。
以下是一個 ProductList 的範例,它會更新影響其產品清單顯示方式的查詢參數:
import {Component, inject} from '@angular/core';
import {ActivatedRoute, Router} from '@angular/router';
@Component({
selector: 'app-product-list',
template: `
<div>
<select (change)="updateSort($event)">
<option value="price">Price</option>
<option value="name">Name</option>
</select>
<!-- Products list -->
</div>
`,
})
export class ProductList {
private route = inject(ActivatedRoute);
private router = inject(Router);
constructor() {
// Access query parameters reactively
this.route.queryParams.subscribe((params) => {
const sort = params['sort'] || 'price';
const page = Number(params['page']) || 1;
this.loadProducts(sort, page);
});
}
updateSort(event: Event) {
const sort = (event.target as HTMLSelectElement).value;
// Update URL with new query parameter
this.router.navigate([], {
queryParams: {sort},
queryParamsHandling: 'merge', // Preserve other query parameters
});
}
}
在這個範例中,使用者可以使用下拉選單,依名稱或價格排序產品清單。與其相關聯的變更處理常式會更新 URL 的查詢參數,進而觸發變更事件,藉此讀取更新後的查詢參數,並更新產品清單。
如需更多資訊,請參閱 QueryParamsHandling 的官方文件。
矩陣參數
矩陣參數是屬於特定 URL 區段的選擇性參數,而不是套用到整個路由。與出現在 ? 之後並全域套用的查詢參數不同,矩陣參數使用分號(;),且只套用到個別的路徑區段。
矩陣參數非常適合在不影響路由定義或比對行為的情況下,將輔助資料傳遞給特定的路由區段。與查詢參數一樣,它們不需要在你的路由設定中定義。
// URL format: /path;key=value
// Multiple parameters: /path;key1=value1;key2=value2
// Navigate with matrix parameters
this.router.navigate(['/awesome-products', {view: 'grid', filter: 'new'}]);
// Results in URL: /awesome-products;view=grid;filter=new
使用 ActivatedRoute
import {Component, inject} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
@Component(/* ... */)
export class AwesomeProducts {
private route = inject(ActivatedRoute);
constructor() {
// Access matrix parameters via params
this.route.params.subscribe((params) => {
const view = params['view']; // e.g., 'grid'
const filter = params['filter']; // e.g., 'new'
});
}
}
NOTE: 除了使用 ActivatedRoute 之外,當使用 withComponentInputBinding 時,矩陣參數也會綁定到元件輸入上。
使用 RouterLinkActive 偵測目前啟用的路由
你可以使用 RouterLinkActive 指令,根據目前啟用的路由,動態地為導覽元素套用樣式。這在導覽元素中很常見,用來通知使用者目前啟用的是哪個路由。
<nav>
<a
class="button"
routerLink="/about"
routerLinkActive="active-button"
ariaCurrentWhenActive="page"
>
About
</a>
|
<a
class="button"
routerLink="/settings"
routerLinkActive="active-button"
ariaCurrentWhenActive="page"
>
Settings
</a>
</nav>
在這個範例中,當 URL 與對應的 routerLink 相符時,Angular Router 會將 active-button 類別套用到正確的錨點連結上,並將 ariaCurrentWhenActive 設定為 page。
如果你需要在單一元素上加入多個類別,你可以使用以空格分隔的字串,或使用陣列:
<!-- Space-separated string syntax -->
<a routerLink="/user/bob" routerLinkActive="class1 class2">Bob</a>
<!-- Array syntax -->
<a routerLink="/user/bob" [routerLinkActive]="['class1', 'class2']">Bob</a>
只設定 routerLinkActive 並不會設定 aria-current。請如上例所示設定 ariaCurrentWhenActive 輸入,讓視覺障礙使用者(他們可能無法察覺所套用的不同樣式)也能辨識出目前啟用的連結。
路由比對策略
在預設情況下,RouterLinkActive 會將路由中的任何祖先都視為相符。
<a [routerLink]="['/user/jane']" routerLinkActive="active-link"> User </a>
<a [routerLink]="['/user/jane/role/admin']" routerLinkActive="active-link"> Role </a>
當使用者造訪 /user/jane/role/admin 時,兩個連結都會帶有 active-link 類別。
只在精確符合路由時才套用 RouterLinkActive
如果你只想在精確相符時才套用該類別,你需要為 routerLinkActiveOptions 指令提供一個設定物件,其中包含 exact: true 這個值。
<a
[routerLink]="['/user/jane']"
routerLinkActive="active-link"
[routerLinkActiveOptions]="{exact: true}"
>
User
</a>
<a
[routerLink]="['/user/jane/role/admin']"
routerLinkActive="active-link"
[routerLinkActiveOptions]="{exact: true}"
>
Role
</a>
如果你想更精確地控制路由的比對方式,值得注意的是,exact: true 其實是整套比對選項的語法糖衣:
// `exact: true` is equivalent to
{
paths: 'exact',
fragment: 'ignored',
matrixParams: 'ignored',
queryParams: 'exact',
}
// `exact: false` is equivalent
{
paths: 'subset',
fragment: 'ignored',
matrixParams: 'ignored',
queryParams: 'subset',
}
如需更多資訊,請參閱 isActiveMatchOptions 的官方文件。
將 RouterLinkActive 套用到祖先元素上
RouterLinkActive 指令也可以套用到祖先元素上,讓開發者能隨心所欲地為其中的元素套用樣式。
<div routerLinkActive="active-link" [routerLinkActiveOptions]="{exact: true}">
<a routerLink="/user/jim">Jim</a>
<a routerLink="/user/bob">Bob</a>
</div>
如需更多資訊,請參閱 RouterLinkActive 的 API 文件。
檢查某個 URL 是否處於啟用狀態
isActive 函式會回傳一個 computed 訊號,用來追蹤給定的 URL 目前在 Router 中是否處於啟用狀態。隨著 Router 狀態的變化,這個訊號會自動更新。
import {Component, inject} from '@angular/core';
import {isActive, Router} from '@angular/router';
@Component({
template: `
<div [class.active]="isSettingsActive()">
<h2>Settings</h2>
</div>
`,
})
export class Panel {
private router = inject(Router);
isSettingsActive = isActive('/settings', this.router, {
paths: 'subset',
queryParams: 'ignored',
fragment: 'ignored',
matrixParams: 'ignored',
});
}