路由基础 #

一、路由概述 #

Angular路由允许在单页面应用中实现多视图导航,通过URL变化切换不同的组件视图。

text
┌─────────────────────────────────────────────────────┐
│                    Angular 应用                      │
├─────────────────────────────────────────────────────┤
│  ┌─────────────────────────────────────────────┐   │
│  │              Router Outlet                   │   │
│  │  ┌─────────────────────────────────────┐    │   │
│  │  │                                     │    │   │
│  │  │     根据URL显示对应组件              │    │   │
│  │  │                                     │    │   │
│  │  └─────────────────────────────────────┘    │   │
│  └─────────────────────────────────────────────┘   │
│  ┌─────────────────────────────────────────────┐   │
│  │  /home → HomeComponent                     │   │
│  │  /users → UsersComponent                   │   │
│  │  /users/:id → UserDetailComponent          │   │
│  └─────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────┘

二、路由配置 #

2.1 创建路由配置 #

typescript
import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { UsersComponent } from './users/users.component';
import { UserDetailComponent } from './user-detail/user-detail.component';

export const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'users', component: UsersComponent },
  { path: 'users/:id', component: UserDetailComponent },
  { path: '**', redirectTo: '' }
];

2.2 注册路由 #

app.routes.ts:

typescript
import { Routes } from '@angular/router';

export const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'about', component: AboutComponent }
];

app.config.ts:

typescript
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes)
  ]
};

2.3 路由出口 #

html
<!-- app.component.html -->
<nav>
  <a routerLink="/">首页</a>
  <a routerLink="/users">用户</a>
  <a routerLink="/about">关于</a>
</nav>

<router-outlet></router-outlet>

三、路由导航 #

3.1 routerLink指令 #

html
<!-- 基本导航 -->
<a routerLink="/home">首页</a>
<a routerLink="/users">用户列表</a>

<!-- 相对路径 -->
<a routerLink="./detail">详情</a>
<a routerLink="../list">返回列表</a>

<!-- 数组语法(推荐) -->
<a [routerLink]="['/users', userId]">用户详情</a>
<a [routerLink]="['/products', productId, 'edit']">编辑产品</a>

3.2 routerLinkActive #

html
<!-- 高亮当前路由 -->
<a routerLink="/home" routerLinkActive="active">首页</a>
<a routerLink="/users" routerLinkActive="active">用户</a>

<!-- 多个类名 -->
<a routerLink="/home" [routerLinkActive]="['active', 'highlighted']">首页</a>

<!-- 配置选项 -->
<a 
  routerLink="/home" 
  routerLinkActive="active"
  [routerLinkActiveOptions]="{ exact: true }">
  首页
</a>

3.3 编程式导航 #

typescript
import { Router } from '@angular/router';

@Component({
  template: `
    <button (click)="goToUsers()">前往用户列表</button>
    <button (click)="goToUserDetail(1)">查看用户详情</button>
  `
})
export class ExampleComponent {
  constructor(private router: Router) {}
  
  goToUsers() {
    this.router.navigate(['/users']);
  }
  
  goToUserDetail(id: number) {
    this.router.navigate(['/users', id]);
  }
  
  goBack() {
    this.router.navigate(['..']);
  }
}

3.4 带查询参数导航 #

typescript
// 导航带查询参数
this.router.navigate(['/users'], {
  queryParams: { page: 1, size: 10 }
});
// URL: /users?page=1&size=10

// 导航带片段
this.router.navigate(['/users'], {
  fragment: 'section-1'
});
// URL: /users#section-1

// 完整示例
this.router.navigate(['/users', userId], {
  queryParams: { tab: 'profile' },
  fragment: 'comments'
});
// URL: /users/123?tab=profile#comments

四、路由参数 #

4.1 路径参数 #

路由配置:

typescript
const routes: Routes = [
  { path: 'users/:id', component: UserDetailComponent },
  { path: 'products/:category/:id', component: ProductDetailComponent }
];

获取参数:

typescript
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

@Component({
  selector: 'app-user-detail',
  template: '<p>用户ID: {{ userId }}</p>'
})
export class UserDetailComponent implements OnInit {
  userId: string;
  
  constructor(private route: ActivatedRoute) {}
  
  ngOnInit() {
    // 方式1:快照获取(一次性)
    this.userId = this.route.snapshot.paramMap.get('id');
    
    // 方式2:订阅获取(参数变化时更新)
    this.route.paramMap.subscribe(params => {
      this.userId = params.get('id');
    });
  }
}

4.2 查询参数 #

typescript
import { ActivatedRoute } from '@angular/router';

@Component({
  template: '<p>页码: {{ page }}</p>'
})
export class UsersComponent implements OnInit {
  page: number;
  
  constructor(private route: ActivatedRoute) {}
  
  ngOnInit() {
    // 快照获取
    this.page = +this.route.snapshot.queryParamMap.get('page');
    
    // 订阅获取
    this.route.queryParamMap.subscribe(params => {
      this.page = +params.get('page') || 1;
    });
  }
}

4.3 获取所有参数 #

typescript
@Component({
  template: '...'
})
export class DetailComponent implements OnInit {
  constructor(private route: ActivatedRoute) {}
  
  ngOnInit() {
    // 路径参数
    this.route.params.subscribe(params => {
      console.log('路径参数:', params);
    });
    
    // 查询参数
    this.route.queryParams.subscribe(params => {
      console.log('查询参数:', params);
    });
    
    // 所有参数
    this.route.paramMap.subscribe(paramMap => {
      console.log('ID:', paramMap.get('id'));
    });
    
    this.route.queryParamMap.subscribe(queryParamMap => {
      console.log('Page:', queryParamMap.get('page'));
    });
  }
}

五、嵌套路由 #

5.1 配置嵌套路由 #

typescript
const routes: Routes = [
  {
    path: 'users',
    component: UsersComponent,
    children: [
      { path: '', component: UserListComponent },
      { path: ':id', component: UserDetailComponent },
      { path: ':id/edit', component: UserEditComponent }
    ]
  }
];

5.2 父组件模板 #

typescript
@Component({
  selector: 'app-users',
  template: `
    <h2>用户管理</h2>
    <nav>
      <a routerLink="./">用户列表</a>
      <a routerLink="./1">用户详情</a>
    </nav>
    <router-outlet></router-outlet>
  `
})
export class UsersComponent {}

5.3 多级嵌套 #

typescript
const routes: Routes = [
  {
    path: 'admin',
    component: AdminComponent,
    children: [
      {
        path: 'users',
        component: AdminUsersComponent,
        children: [
          { path: '', component: UserListComponent },
          { path: ':id', component: UserDetailComponent }
        ]
      },
      {
        path: 'products',
        component: AdminProductsComponent
      }
    ]
  }
];

六、路由懒加载 #

6.1 配置懒加载 #

typescript
const routes: Routes = [
  { path: '', component: HomeComponent },
  {
    path: 'admin',
    loadChildren: () => import('./admin/admin.module')
      .then(m => m.AdminModule)
  },
  {
    path: 'users',
    loadComponent: () => import('./users/users.component')
      .then(c => c.UsersComponent)
  }
];

6.2 懒加载模块 #

admin/admin.module.ts:

typescript
@NgModule({
  imports: [
    RouterModule.forChild([
      { path: '', component: AdminDashboardComponent },
      { path: 'settings', component: AdminSettingsComponent }
    ])
  ],
  declarations: [
    AdminDashboardComponent,
    AdminSettingsComponent
  ]
})
export class AdminModule {}

6.3 预加载策略 #

typescript
import { PreloadingStrategy, Route } from '@angular/router';
import { Observable, of } from 'rxjs';

export class CustomPreloadingStrategy implements PreloadingStrategy {
  preload(route: Route, load: () => Observable<any>): Observable<any> {
    if (route.data?.preload) {
      return load();
    }
    return of(null);
  }
}

// 配置
export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes, withPreloading(PreloadAllModules))
  ]
};

七、路由事件 #

7.1 监听路由事件 #

typescript
import { Component } from '@angular/core';
import { Router, NavigationStart, NavigationEnd, NavigationError } from '@angular/router';

@Component({
  selector: 'app-root',
  template: '...'
})
export class AppComponent {
  constructor(private router: Router) {
    this.router.events.subscribe(event => {
      if (event instanceof NavigationStart) {
        console.log('导航开始:', event.url);
      }
      
      if (event instanceof NavigationEnd) {
        console.log('导航结束:', event.url);
      }
      
      if (event instanceof NavigationError) {
        console.error('导航错误:', event.error);
      }
    });
  }
}

7.2 常用路由事件 #

事件 说明
NavigationStart 导航开始
NavigationEnd 导航结束
NavigationCancel 导航取消
NavigationError 导航错误
RoutesRecognized 路由识别
GuardsCheckStart 守卫检查开始
GuardsCheckEnd 守卫检查结束

八、路由数据 #

8.1 静态数据 #

typescript
const routes: Routes = [
  {
    path: 'admin',
    component: AdminComponent,
    data: {
      title: '管理后台',
      breadcrumb: '管理',
      requiresAuth: true
    }
  }
];
typescript
@Component({
  template: '<h1>{{ title }}</h1>'
})
export class AdminComponent implements OnInit {
  title: string;
  
  constructor(private route: ActivatedRoute) {}
  
  ngOnInit() {
    this.route.data.subscribe(data => {
      this.title = data['title'];
    });
  }
}

8.2 动态数据(Resolve) #

typescript
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class UserResolver implements Resolve<User> {
  constructor(private userService: UserService) {}
  
  resolve(route: ActivatedRouteSnapshot): Observable<User> {
    const id = route.paramMap.get('id');
    return this.userService.getUser(+id);
  }
}

// 路由配置
const routes: Routes = [
  {
    path: 'users/:id',
    component: UserDetailComponent,
    resolve: {
      user: UserResolver
    }
  }
];

// 组件中使用
@Component({
  template: '<p>{{ user?.name }}</p>'
})
export class UserDetailComponent implements OnInit {
  user: User;
  
  constructor(private route: ActivatedRoute) {}
  
  ngOnInit() {
    this.route.data.subscribe(data => {
      this.user = data['user'];
    });
  }
}

九、总结 #

概念 说明
Routes 路由配置数组
router-outlet 路由出口
routerLink 声明式导航
Router.navigate() 编程式导航
ActivatedRoute 当前路由信息
懒加载 按需加载模块
Resolve 路由前获取数据

下一步:路由守卫

最后更新:2026-03-26