1. 路由基础配置
Angular 路由基于 Routes 数组配置,每条路由规则将 URL 路径映射到一个组件。配置完后通过 provideRouter(routes) 注册到应用。
// app.routes.ts
import { Routes } from '@angular/router';
import { HomeComponent } from './pages/home.component';
import { NotFoundComponent } from './pages/not-found.component';
export const routes: Routes = [
// 基础路由
{ path: '', component: HomeComponent }, // 首页
{ path: 'about', component: AboutComponent }, // 关于页
// 带参数的路由
{ path: 'users/:id', component: UserDetailComponent },
// 懒加载(Standalone 组件)
{
path: 'dashboard',
loadComponent: () =>
import('./pages/dashboard.component')
.then(m => m.DashboardComponent)
},
// 懒加载(路由组)
{
path: 'admin',
loadChildren: () =>
import('./admin/admin.routes')
.then(m => m.adminRoutes)
},
// 重定向
{ path: 'home', redirectTo: '', pathMatch: 'full' },
// 通配符(404 页面,放最后)
{ path: '**', component: NotFoundComponent },
];
在模板中使用路由
<!-- app.component.html -->
<nav>
<!-- routerLink 指令 -->
<a routerLink="/">首页</a>
<a routerLink="/dashboard">仪表盘</a>
<a [routerLink]="['/users', userId]">用户详情</a>
<!-- routerLinkActive:激活时添加 CSS 类 -->
<a routerLink="/about" routerLinkActive="active">关于</a>
</nav>
<!-- 路由出口:匹配的组件渲染在此处 -->
<router-outlet />
2. 路由懒加载
懒加载(Lazy Loading)是大型应用必须采用的优化策略:只在用户访问对应路由时才下载相关代码,减少初始加载体积。
loadComponent:懒加载单个组件
// 懒加载单个 Standalone 组件(Angular 14+)
{
path: 'profile',
loadComponent: () =>
import('./profile/profile.component')
.then(c => c.ProfileComponent)
}
loadChildren:懒加载路由组
// admin.routes.ts — 管理后台的子路由
import { Routes } from '@angular/router';
export const adminRoutes: Routes = [
{ path: '', redirectTo: 'users', pathMatch: 'full' },
{
path: 'users',
loadComponent: () =>
import('./users/user-list.component')
.then(c => c.UserListComponent)
},
{
path: 'settings',
loadComponent: () =>
import('./settings/settings.component')
.then(c => c.SettingsComponent)
},
];
// app.routes.ts 中引用
{
path: 'admin',
canActivate: [authGuard], // 路由守卫
loadChildren: () =>
import('./admin/admin.routes')
.then(m => m.adminRoutes)
}
3. 路由守卫
路由守卫控制是否允许激活或离开某条路由,常用于权限验证、未保存表单提示等场景。Angular 14+ 推荐使用函数式守卫(替代类守卫)。
CanActivate — 访问前验证
// auth.guard.ts — 函数式路由守卫(现代写法)
import { inject } from '@angular/core';
import { CanActivateFn, Router } from '@angular/router';
import { AuthService } from './auth.service';
export const authGuard: CanActivateFn = (route, state) => {
const auth = inject(AuthService);
const router = inject(Router);
if (auth.isLoggedIn()) {
return true;
}
// 未登录:跳转到登录页,并记录目标 URL
return router.createUrlTree(
['/login'],
{ queryParams: { returnUrl: state.url } }
);
};
// 角色守卫
export const adminGuard: CanActivateFn = () => {
const auth = inject(AuthService);
return auth.user()?.role === 'admin';
};
CanDeactivate — 离开前确认
import { CanDeactivateFn } from '@angular/router';
export interface CanComponentDeactivate {
canDeactivate(): boolean;
}
export const unsavedChangesGuard: CanDeactivateFn<CanComponentDeactivate> =
(component) => {
if (component.canDeactivate()) {
return true;
}
return confirm('有未保存的修改,确定要离开吗?');
};
// 在路由中使用
{
path: 'edit/:id',
component: EditComponent,
canDeactivate: [unsavedChangesGuard]
}
4. 路由参数与查询参数
import { Component, inject, OnInit, signal } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { toSignal } from '@angular/core/rxjs-interop';
@Component({
selector: 'app-user-detail',
standalone: true,
template: `
@if (user()) {
<h1>{{ user()!.name }}</h1>
} @else {
<p>加载中...</p>
}
`
})
export class UserDetailComponent implements OnInit {
private route = inject(ActivatedRoute);
private router = inject(Router);
// 读取路由参数(/users/:id)
userId = toSignal(this.route.params, { initialValue: {} });
// 读取查询参数(?tab=settings)
queryParams = toSignal(this.route.queryParams, { initialValue: {} });
user = signal<User | null>(null);
ngOnInit() {
const id = this.route.snapshot.paramMap.get('id');
// 使用 id 加载用户数据...
}
goBack() {
this.router.navigate(['/users']);
}
switchTab(tab: string) {
this.router.navigate([], {
queryParams: { tab },
queryParamsHandling: 'merge' // 合并现有查询参数
});
}
}
5. 子路由
// 带子路由的配置
{
path: 'users',
component: UsersComponent, // 布局组件(含 <router-outlet>)
children: [
{ path: '', component: UserListComponent },
{ path: ':id', component: UserDetailComponent },
{ path: ':id/edit', component: UserEditComponent },
]
}
<!-- users.component.html — 布局组件 -->
<div class="users-layout">
<aside class="sidebar">
<!-- 侧边导航 -->
</aside>
<main>
<router-outlet /> <!-- 子路由渲染在此 -->
</main>
</div>
6. 实战:企业应用路由架构
// app.routes.ts — 完整企业应用路由示例
export const routes: Routes = [
// 公开路由
{ path: 'login', loadComponent: () => import('./auth/login.component').then(c => c.LoginComponent) },
{ path: 'register', loadComponent: () => import('./auth/register.component').then(c => c.RegisterComponent) },
// 需要认证的路由(使用布局组件包裹)
{
path: '',
component: MainLayoutComponent,
canActivate: [authGuard],
children: [
{ path: '', redirectTo: 'dashboard', pathMatch: 'full' },
{ path: 'dashboard', loadComponent: () => import('./dashboard/dashboard.component').then(c => c.DashboardComponent) },
{
path: 'users',
loadChildren: () => import('./users/users.routes').then(m => m.userRoutes)
},
{
path: 'admin',
canActivate: [adminGuard],
loadChildren: () => import('./admin/admin.routes').then(m => m.adminRoutes)
},
]
},
{ path: '**', loadComponent: () => import('./pages/not-found.component').then(c => c.NotFoundComponent) },
];
本章小结:Angular 路由是构建 SPA 的关键。懒加载 loadComponent/loadChildren 减少初始包体积,函数式路由守卫实现权限控制,子路由实现布局嵌套。下一章深入 HTTP 数据请求。