Ionic路由基础 #

一、路由概述 #

1.1 Ionic路由系统 #

Ionic使用Angular Router作为路由系统:

text
路由系统
    │
    ├── 路由配置
    │   ├── 路由定义
    │   ├── 路由参数
    │   └── 子路由
    │
    ├── 导航方法
    │   ├── routerLink
    │   ├── Router.navigate
    │   └── NavController
    │
    ├── 路由守卫
    │   ├── CanActivate
    │   ├── CanDeactivate
    │   └── Resolve
    │
    └── 路由事件
        ├── NavigationStart
        ├── NavigationEnd
        └── NavigationError

1.2 路由文件 #

typescript
// app-routing.module.ts
import { NgModule } from '@angular/core';
import { PreloadAllModules, RouterModule, Routes } from '@angular/router';

const routes: Routes = [
  {
    path: '',
    redirectTo: 'home',
    pathMatch: 'full'
  },
  {
    path: 'home',
    loadChildren: () => import('./home/home.module').then(m => m.HomePageModule)
  },
  {
    path: 'detail/:id',
    loadChildren: () => import('./detail/detail.module').then(m => m.DetailPageModule)
  }
];

@NgModule({
  imports: [
    RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })
  ],
  exports: [RouterModule]
})
export class AppRoutingModule {}

二、路由配置 #

2.1 基本路由 #

typescript
const routes: Routes = [
  // 重定向
  {
    path: '',
    redirectTo: 'home',
    pathMatch: 'full'
  },
  
  // 基本路由
  {
    path: 'home',
    component: HomePage
  },
  
  // 懒加载路由
  {
    path: 'about',
    loadChildren: () => import('./about/about.module').then(m => m.AboutPageModule)
  }
];

2.2 路由参数 #

typescript
const routes: Routes = [
  // 必需参数
  {
    path: 'detail/:id',
    component: DetailPage
  },
  
  // 多个参数
  {
    path: 'user/:userId/post/:postId',
    component: PostPage
  },
  
  // 可选参数(通过queryParams)
  {
    path: 'search',
    component: SearchPage
  }
];

2.3 子路由 #

typescript
const routes: Routes = [
  {
    path: 'settings',
    component: SettingsPage,
    children: [
      {
        path: '',
        redirectTo: 'profile',
        pathMatch: 'full'
      },
      {
        path: 'profile',
        component: ProfileSettingsComponent
      },
      {
        path: 'security',
        component: SecuritySettingsComponent
      },
      {
        path: 'notifications',
        component: NotificationSettingsComponent
      }
    ]
  }
];

2.4 命名路由出口 #

typescript
const routes: Routes = [
  {
    path: 'home',
    component: HomePage,
    children: [
      {
        path: 'detail/:id',
        component: DetailComponent,
        outlet: 'sidebar'
      }
    ]
  }
];
html
<!-- 主路由出口 -->
<ion-router-outlet></ion-router-outlet>

<!-- 命名路由出口 -->
<ion-router-outlet name="sidebar"></ion-router-outlet>

三、页面导航 #

3.1 routerLink导航 #

html
<!-- 基本导航 -->
<ion-button routerLink="/home">首页</ion-button>

<!-- 带参数导航 -->
<ion-button [routerLink]="['/detail', item.id]">详情</ion-button>

<!-- 带查询参数 -->
<ion-button 
  [routerLink]="['/search']"
  [queryParams]="{ keyword: 'ionic', page: 1 }">
  搜索
</ion-button>

<!-- 导航并替换历史 -->
<ion-button 
  routerLink="/login"
  routerLinkActive="active"
  [replaceUrl]="true">
  登录
</ion-button>

3.2 Router.navigate #

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

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html'
})
export class HomePage {
  constructor(private router: Router) {}
  
  // 基本导航
  goToAbout() {
    this.router.navigate(['/about']);
  }
  
  // 带参数导航
  goToDetail(id: number) {
    this.router.navigate(['/detail', id]);
  }
  
  // 带查询参数
  goToSearch() {
    this.router.navigate(['/search'], {
      queryParams: { keyword: 'ionic', page: 1 }
    });
  }
  
  // 导航并替换历史
  goToLogin() {
    this.router.navigate(['/login'], {
      replaceUrl: true
    });
  }
  
  // 相对导航
  goToChild() {
    this.router.navigate(['./child'], { relativeTo: this.route });
  }
  
  goToParent() {
    this.router.navigate(['../'], { relativeTo: this.route });
  }
}

3.3 NavController导航 #

typescript
import { Component } from '@angular/core';
import { NavController } from '@ionic/angular';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html'
})
export class HomePage {
  constructor(private navCtrl: NavController) {}
  
  // 前进导航(带动画)
  goForward() {
    this.navCtrl.navigateForward('/detail/1');
  }
  
  // 后退导航(带动画)
  goBack() {
    this.navCtrl.navigateBack('/home');
  }
  
  // 设置根页面
  setRoot() {
    this.navCtrl.navigateRoot('/login');
  }
  
  // 返回上一页
  goBackOne() {
    this.navCtrl.back();
  }
  
  // 返回到特定页面
  goBackTo() {
    this.navCtrl.pop();
  }
}

四、路由参数获取 #

4.1 获取路径参数 #

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

@Component({
  selector: 'app-detail',
  templateUrl: 'detail.page.html'
})
export class DetailPage implements OnInit {
  id: string = '';
  
  constructor(private route: ActivatedRoute) {}
  
  ngOnInit() {
    // 方式1:快照获取
    this.id = this.route.snapshot.paramMap.get('id') || '';
    
    // 方式2:订阅获取(参数变化时更新)
    this.route.paramMap.subscribe(params => {
      this.id = params.get('id') || '';
    });
  }
}

4.2 获取查询参数 #

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

@Component({
  selector: 'app-search',
  templateUrl: 'search.page.html'
})
export class SearchPage implements OnInit {
  keyword: string = '';
  page: number = 1;
  
  constructor(private route: ActivatedRoute) {}
  
  ngOnInit() {
    // 方式1:快照获取
    this.keyword = this.route.snapshot.queryParamMap.get('keyword') || '';
    this.page = Number(this.route.snapshot.queryParamMap.get('page')) || 1;
    
    // 方式2:订阅获取
    this.route.queryParamMap.subscribe(params => {
      this.keyword = params.get('keyword') || '';
      this.page = Number(params.get('page')) || 1;
    });
  }
}

4.3 获取路由数据 #

typescript
// 路由配置
const routes: Routes = [
  {
    path: 'detail/:id',
    component: DetailPage,
    data: {
      title: '详情页',
      showBackButton: true
    }
  }
];

// 组件获取
@Component({
  selector: 'app-detail',
  templateUrl: 'detail.page.html'
})
export class DetailPage implements OnInit {
  title: string = '';
  
  constructor(private route: ActivatedRoute) {}
  
  ngOnInit() {
    // 获取路由数据
    this.title = this.route.snapshot.data['title'];
    
    // 或订阅
    this.route.data.subscribe(data => {
      this.title = data['title'];
    });
  }
}

五、路由守卫 #

5.1 CanActivate守卫 #

typescript
// auth.guard.ts
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { AuthService } from './auth.service';

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {
  constructor(
    private auth: AuthService,
    private router: Router
  ) {}
  
  canActivate(): boolean {
    if (this.auth.isLoggedIn()) {
      return true;
    }
    
    this.router.navigate(['/login']);
    return false;
  }
}

// 路由配置
const routes: Routes = [
  {
    path: 'profile',
    loadChildren: () => import('./profile/profile.module').then(m => m.ProfilePageModule),
    canActivate: [AuthGuard]
  }
];

5.2 CanDeactivate守卫 #

typescript
// unsaved-changes.guard.ts
import { Injectable } from '@angular/core';
import { CanDeactivate } from '@angular/router';
import { AlertController } from '@ionic/angular';

export interface CanComponentDeactivate {
  canDeactivate: () => boolean;
}

@Injectable({
  providedIn: 'root'
})
export class UnsavedChangesGuard implements CanDeactivate<CanComponentDeactivate> {
  constructor(private alertCtrl: AlertController) {}
  
  async canDeactivate(component: CanComponentDeactivate): Promise<boolean> {
    if (component.canDeactivate && component.canDeactivate()) {
      return true;
    }
    
    const alert = await this.alertCtrl.create({
      header: '确认离开',
      message: '您有未保存的更改,确定要离开吗?',
      buttons: [
        {
          text: '取消',
          role: 'cancel'
        },
        {
          text: '确定',
          handler: () => {
            return true;
          }
        }
      ]
    });
    
    await alert.present();
    return false;
  }
}

// 组件实现
@Component({
  selector: 'app-edit',
  templateUrl: 'edit.page.html'
})
export class EditPage implements CanComponentDeactivate {
  hasUnsavedChanges = false;
  
  canDeactivate(): boolean {
    return !this.hasUnsavedChanges;
  }
}

5.3 Resolve守卫 #

typescript
// user.resolve.ts
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { UserService } from './user.service';

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

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

// 组件获取
@Component({
  selector: 'app-user',
  templateUrl: 'user.page.html'
})
export class UserPage implements OnInit {
  user: any;
  
  constructor(private route: ActivatedRoute) {}
  
  ngOnInit() {
    this.user = this.route.snapshot.data['user'];
  }
}

六、路由事件 #

6.1 监听路由事件 #

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

@Component({
  selector: 'app-root',
  templateUrl: 'app.component.html'
})
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.log('导航错误:', event.error);
      }
    });
  }
}

6.2 路由事件类型 #

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

七、路由模块 #

7.1 模块路由配置 #

typescript
// home/home.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { HomePage } from './home.page';
import { HomeRoutingModule } from './home-routing.module';

@NgModule({
  imports: [
    CommonModule,
    FormsModule,
    IonicModule,
    HomeRoutingModule
  ],
  declarations: [HomePage]
})
export class HomePageModule {}

// home/home-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomePage } from './home.page';

const routes: Routes = [
  {
    path: '',
    component: HomePage
  }
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class HomeRoutingModule {}

7.2 Tabs路由配置 #

typescript
// tabs/tabs.router.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { TabsPage } from './tabs.page';

const routes: Routes = [
  {
    path: '',
    component: TabsPage,
    children: [
      {
        path: 'home',
        loadChildren: () => import('../home/home.module').then(m => m.HomePageModule)
      },
      {
        path: 'search',
        loadChildren: () => import('../search/search.module').then(m => m.SearchPageModule)
      },
      {
        path: 'profile',
        loadChildren: () => import('../profile/profile.module').then(m => m.ProfilePageModule)
      },
      {
        path: '',
        redirectTo: '/tabs/home',
        pathMatch: 'full'
      }
    ]
  }
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class TabsPageRoutingModule {}

八、最佳实践 #

8.1 路由命名规范 #

typescript
// 推荐:小写+连字符
const routes: Routes = [
  { path: 'user-profile', component: UserProfilePage },
  { path: 'order-detail', component: OrderDetailPage }
];

// 不推荐:驼峰命名
const routes: Routes = [
  { path: 'userProfile', component: UserProfilePage }
];

8.2 懒加载 #

typescript
// 推荐:懒加载
const routes: Routes = [
  {
    path: 'detail',
    loadChildren: () => import('./detail/detail.module').then(m => m.DetailPageModule)
  }
];

// 不推荐:直接加载
const routes: Routes = [
  {
    path: 'detail',
    component: DetailPage
  }
];

8.3 路由数据 #

typescript
// 使用路由数据传递配置
const routes: Routes = [
  {
    path: 'detail/:id',
    component: DetailPage,
    data: {
      title: '详情页',
      showBackButton: true,
      animation: 'slide-up'
    }
  }
];

九、总结 #

9.1 路由要点 #

要点 说明
路由配置 定义路由映射关系
页面导航 routerLink、Router、NavController
路由参数 路径参数、查询参数
路由守卫 CanActivate、CanDeactivate、Resolve
路由事件 监听导航过程

9.2 下一步 #

掌握了路由基础后,接下来让我们学习 页面导航,深入了解Ionic的导航机制!

最后更新:2026-03-28