🧭 Angular Router:導航與路由管理
📌 路由模組設定
Angular Router 讓你在單一頁面中切換不同的「視圖」,實現 SPA(Single Page Application)。
// app.routes.ts
import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';
import { ProductListComponent } from './products/product-list.component';
import { ProductDetailComponent } from './products/product-detail.component';
import { NotFoundComponent } from './not-found/not-found.component';
export const routes: Routes = [
{ path: '', component: HomeComponent }, // 首頁
{ path: 'about', component: AboutComponent }, // /about
{ path: 'products', component: ProductListComponent }, // /products
{ path: 'products/:id', component: ProductDetailComponent }, // /products/123
{ path: '**', component: NotFoundComponent } // 404 萬用路由(放最後)
];
// app.config.ts — Standalone 模式設定
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
export const appConfig: ApplicationConfig = {
providers: [provideRouter(routes)]
};
📌 RouterLink 與 router-outlet
<!-- app.component.html -->
<nav>
<!-- routerLink 取代傳統的 <a href>,不會重新載入頁面 -->
<a routerLink="/" routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}">首頁</a>
<a routerLink="/about" routerLinkActive="active">關於</a>
<a routerLink="/products" routerLinkActive="active">產品</a>
</nav>
<!-- router-outlet 是路由的「出口」,符合的元件會顯示在這裡 -->
<router-outlet></router-outlet>
<footer>版權所有 © 2024</footer>
💡
routerLinkActive="active"會在目前路由符合時自動加上activeCSS 類別。
📌 路由參數與查詢參數
路由參數(Route Parameters)
// product-detail.component.ts
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-product-detail',
template: `
<h2>產品詳情</h2>
<p>產品 ID:{{ productId }}</p>
`
})
export class ProductDetailComponent implements OnInit {
productId = '';
constructor(private route: ActivatedRoute) { }
ngOnInit() {
// 方法 1:快照(適合不會變的參數)
this.productId = this.route.snapshot.paramMap.get('id') ?? '';
// 方法 2:Observable(適合同一元件中參數會改變的情況)
this.route.paramMap.subscribe(params => {
this.productId = params.get('id') ?? '';
// 重新載入資料...
});
}
}
查詢參數(Query Parameters)
<!-- 傳遞查詢參數 /products?category=phone&sort=price -->
<a routerLink="/products" [queryParams]="{category: 'phone', sort: 'price'}">
手機(按價格排序)
</a>
// 讀取查詢參數
this.route.queryParamMap.subscribe(params => {
const category = params.get('category'); // 'phone'
const sort = params.get('sort'); // 'price'
});
📌 子路由(Child Routes)
// 路由設定
export const routes: Routes = [
{
path: 'admin',
component: AdminLayoutComponent,
children: [
{ path: '', component: AdminDashboardComponent }, // /admin
{ path: 'users', component: AdminUsersComponent }, // /admin/users
{ path: 'settings', component: AdminSettingsComponent } // /admin/settings
]
}
];
<!-- admin-layout.component.html -->
<div class="admin-layout">
<aside>
<a routerLink="/admin">儀表板</a>
<a routerLink="/admin/users">使用者管理</a>
<a routerLink="/admin/settings">系統設定</a>
</aside>
<main>
<router-outlet></router-outlet> <!-- 子路由的出口 -->
</main>
</div>
📌 路由守衛(Guards)
// auth.guard.ts
import { inject } from '@angular/core';
import { CanActivateFn, Router } from '@angular/router';
import { AuthService } from './auth.service';
// CanActivate — 進入路由前檢查(最常用)
export const authGuard: CanActivateFn = (route, state) => {
const authService = inject(AuthService);
const router = inject(Router);
if (authService.isLoggedIn()) {
return true; // 允許進入
}
// 未登入 → 導向登入頁,並記住原本要去的頁面
return router.createUrlTree(['/login'], {
queryParams: { returnUrl: state.url }
});
};
// 在路由設定中使用守衛
export const routes: Routes = [
{ path: 'admin', component: AdminComponent, canActivate: [authGuard] },
{ path: 'login', component: LoginComponent }
];
📌 懶載入模組(Lazy Loading)
// 懶載入 — 只有進入該路由時才下載對應的程式碼
export const routes: Routes = [
{
path: 'admin',
loadComponent: () => import('./admin/admin.component')
.then(m => m.AdminComponent)
},
{
path: 'reports',
loadChildren: () => import('./reports/reports.routes')
.then(m => m.REPORT_ROUTES) // 載入整個子路由模組
}
];
💡 效能優化:懶載入讓首頁只下載必要的程式碼,其他頁面的程式碼按需載入。 這對大型應用特別重要——使用者不需要一次下載所有程式碼。
📌 程式化導航
import { Router } from '@angular/router';
@Component({ /* ... */ })
export class MyComponent {
constructor(private router: Router) { }
goToProduct(id: number) {
// 程式碼中觸發導航
this.router.navigate(['/products', id]);
}
goToSearch(term: string) {
this.router.navigate(['/search'], {
queryParams: { q: term }
});
}
}
📌 小結
Routes陣列定義路徑和元件的對應關係<router-outlet>是路由元件的顯示區域- 路由參數
:id用於動態路徑,查詢參數用於篩選 - 子路由實現嵌套的頁面佈局
- 路由守衛控制存取權限(如登入驗證)
- 懶載入大幅提升首頁載入速度