Ionic页面导航 #

一、导航概述 #

1.1 Ionic导航系统 #

Ionic提供两种导航方式:

text
导航系统
    │
    ├── URL路由(推荐)
    │   ├── Angular Router
    │   ├── URL驱动
    │   └── 支持浏览器历史
    │
    └── NavController
        ├── 栈式导航
        ├── push/pop操作
        └── 动画支持

1.2 导航栈 #

text
导航栈示例:

[Login] → [Home] → [Detail] → [Settings]

当前页面: Settings
返回顺序: Settings → Detail → Home → Login

二、页面跳转 #

2.1 声明式导航 #

html
<!-- 使用routerLink -->
<ion-button routerLink="/home">首页</ion-button>

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

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

<!-- 列表项导航 -->
<ion-item [routerLink]="['/detail', item.id]">
  <ion-label>{{ item.name }}</ion-label>
</ion-item>

<!-- 卡片导航 -->
<ion-card [routerLink]="['/product', product.id]">
  <ion-card-header>
    <ion-card-title>{{ product.name }}</ion-card-title>
  </ion-card-header>
</ion-card>

2.2 编程式导航 #

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) {}
  
  // 基本跳转
  navigateToAbout() {
    this.router.navigate(['/about']);
  }
  
  // 带路径参数
  navigateToDetail(id: string) {
    this.router.navigate(['/detail', id]);
  }
  
  // 带查询参数
  navigateToSearch() {
    this.router.navigate(['/search'], {
      queryParams: { 
        keyword: 'ionic',
        page: 1 
      }
    });
  }
  
  // 带路由数据
  navigateWithData() {
    this.router.navigate(['/detail', 1], {
      state: {
        data: { name: 'Ionic' }
      }
    });
  }
  
  // 替换当前历史
  navigateAndReplace() {
    this.router.navigate(['/home'], {
      replaceUrl: true
    });
  }
}

2.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();
  }
  
  // 返回到特定页面
  goBackToRoot() {
    this.navCtrl.goBack('/home');
  }
}

三、参数传递 #

3.1 路径参数 #

typescript
// 发送页面
goToDetail(id: string) {
  this.router.navigate(['/detail', id]);
}

// 接收页面
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() {
    // 快照获取
    this.id = this.route.snapshot.paramMap.get('id') || '';
    
    // 订阅获取
    this.route.paramMap.subscribe(params => {
      this.id = params.get('id') || '';
      this.loadDetail(this.id);
    });
  }
  
  loadDetail(id: string) {
    // 加载详情数据
  }
}

3.2 查询参数 #

typescript
// 发送页面
goToSearch() {
  this.router.navigate(['/search'], {
    queryParams: {
      keyword: 'ionic',
      category: 'mobile',
      page: 1
    }
  });
}

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

3.3 路由状态 #

typescript
// 发送页面
import { Router } from '@angular/router';

goToDetail(product: any) {
  this.router.navigate(['/detail', product.id], {
    state: {
      product: product
    }
  });
}

// 接收页面
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';

@Component({
  selector: 'app-detail',
  templateUrl: 'detail.page.html'
})
export class DetailPage implements OnInit {
  product: any;
  
  constructor(private router: Router) {}
  
  ngOnInit() {
    const navigation = this.router.getCurrentNavigation();
    const state = navigation?.extras.state;
    this.product = state?.['product'];
  }
}

3.4 服务共享数据 #

typescript
// data.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class DataService {
  private productSource = new BehaviorSubject<any>(null);
  currentProduct = this.productSource.asObservable();
  
  setProduct(product: any) {
    this.productSource.next(product);
  }
  
  getProduct() {
    return this.productSource.value;
  }
  
  clearProduct() {
    this.productSource.next(null);
  }
}

// 发送页面
import { DataService } from './data.service';

export class ListPage {
  constructor(
    private router: Router,
    private dataService: DataService
  ) {}
  
  goToDetail(product: any) {
    this.dataService.setProduct(product);
    this.router.navigate(['/detail', product.id]);
  }
}

// 接收页面
export class DetailPage implements OnInit {
  product: any;
  
  constructor(
    private route: ActivatedRoute,
    private dataService: DataService
  ) {}
  
  ngOnInit() {
    // 从服务获取
    this.product = this.dataService.getProduct();
    
    // 或订阅
    this.dataService.currentProduct.subscribe(product => {
      this.product = product;
    });
  }
}

四、返回处理 #

4.1 返回按钮 #

html
<!-- 基本返回按钮 -->
<ion-header>
  <ion-toolbar>
    <ion-buttons slot="start">
      <ion-back-button defaultHref="/home"></ion-back-button>
    </ion-buttons>
    <ion-title>详情页</ion-title>
  </ion-toolbar>
</ion-header>

<!-- 自定义返回按钮 -->
<ion-header>
  <ion-toolbar>
    <ion-buttons slot="start">
      <ion-button (click)="goBack()">
        <ion-icon name="arrow-back" slot="icon-only"></ion-icon>
      </ion-button>
    </ion-buttons>
    <ion-title>详情页</ion-title>
  </ion-toolbar>
</ion-header>
typescript
import { Component } from '@angular/core';
import { NavController } from '@ionic/angular';

@Component({
  selector: 'app-detail',
  templateUrl: 'detail.page.html'
})
export class DetailPage {
  constructor(private navCtrl: NavController) {}
  
  goBack() {
    this.navCtrl.back();
  }
}

4.2 返回数据 #

typescript
// 详情页返回数据
import { Component } from '@angular/core';
import { NavController } from '@ionic/angular';

@Component({
  selector: 'app-detail',
  templateUrl: 'detail.page.html'
})
export class DetailPage {
  constructor(private navCtrl: NavController) {}
  
  saveAndReturn() {
    // 保存数据
    this.saveData();
    
    // 返回并传递数据
    this.navCtrl.navigateBack('/home', {
      state: {
        saved: true,
        data: this.formData
      }
    });
  }
}

// 首页接收返回数据
import { Component } from '@angular/core';
import { Router } from '@ionic/angular';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html'
})
export class HomePage {
  constructor(private router: Router) {
    this.router.events.subscribe(event => {
      if (event instanceof NavigationEnd) {
        const navigation = this.router.getCurrentNavigation();
        const state = navigation?.extras.state;
        if (state?.['saved']) {
          // 处理返回数据
          this.refreshData();
        }
      }
    });
  }
}

4.3 确认返回 #

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

@Component({
  selector: 'app-edit',
  templateUrl: 'edit.page.html'
})
export class EditPage {
  hasChanges = false;
  
  constructor(
    private alertCtrl: AlertController,
    private navCtrl: NavController
  ) {}
  
  async confirmBack() {
    if (!this.hasChanges) {
      this.navCtrl.back();
      return;
    }
    
    const alert = await this.alertCtrl.create({
      header: '确认离开',
      message: '您有未保存的更改,确定要离开吗?',
      buttons: [
        {
          text: '取消',
          role: 'cancel'
        },
        {
          text: '放弃更改',
          handler: () => {
            this.navCtrl.back();
          }
        },
        {
          text: '保存并离开',
          handler: () => {
            this.saveData();
            this.navCtrl.back();
          }
        }
      ]
    });
    
    await alert.present();
  }
}

五、导航生命周期 #

5.1 Ionic生命周期 #

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

@Component({
  selector: 'app-detail',
  templateUrl: 'detail.page.html'
})
export class DetailPage {
  // 页面即将进入
  ionViewWillEnter() {
    console.log('页面即将进入');
    // 刷新数据
    this.refreshData();
  }
  
  // 页面已进入
  ionViewDidEnter() {
    console.log('页面已进入');
    // 页面动画完成
  }
  
  // 页面即将离开
  ionViewWillLeave() {
    console.log('页面即将离开');
    // 保存临时数据
  }
  
  // 页面已离开
  ionViewDidLeave() {
    console.log('页面已离开');
    // 清理资源
  }
}

5.2 生命周期流程 #

text
首次进入页面:
ngOnInit → ionViewWillEnter → ionViewDidEnter

离开页面:
ionViewWillLeave → ionViewDidLeave

返回页面:
ionViewWillEnter → ionViewDidEnter

销毁页面:
ionViewWillLeave → ionViewDidLeave → ngOnDestroy

5.3 生命周期使用场景 #

生命周期 使用场景
ionViewWillEnter 刷新数据、重置状态
ionViewDidEnter 启动动画、开始定时器
ionViewWillLeave 保存数据、暂停操作
ionViewDidLeave 清理资源、停止定时器

六、导航动画 #

6.1 页面过渡动画 #

typescript
import { AnimationController } from '@ionic/angular';

// 自定义进入动画
const enterAnimation = (baseEl: HTMLElement) => {
  const animationCtrl = new AnimationController();
  
  return animationCtrl
    .create()
    .addElement(baseEl)
    .duration(300)
    .fromTo('opacity', '0', '1')
    .fromTo('transform', 'translateX(100%)', 'translateX(0)');
};

// 自定义离开动画
const leaveAnimation = (baseEl: HTMLElement) => {
  return enterAnimation(baseEl).direction('reverse');
};

6.2 导航方向 #

typescript
// 前进导航(从右滑入)
this.navCtrl.navigateForward('/detail');

// 后退导航(从左滑入)
this.navCtrl.navigateBack('/home');

// 根页面(淡入)
this.navCtrl.navigateRoot('/login');

七、导航最佳实践 #

7.1 导航结构 #

text
推荐导航结构:
├── /tabs
│   ├── /tabs/home
│   ├── /tabs/search
│   └── /tabs/profile
├── /auth
│   ├── /auth/login
│   └── /auth/register
├── /detail/:id
└── /settings

7.2 参数传递选择 #

方式 适用场景 特点
路径参数 必需参数 URL可见、可收藏
查询参数 可选参数 URL可见、可分享
路由状态 复杂对象 URL不可见
服务共享 跨组件共享 全局可访问

7.3 返回处理建议 #

typescript
// 推荐:使用ionViewWillEnter刷新
ionViewWillEnter() {
  this.loadData();
}

// 不推荐:在ngOnInit中刷新
ngOnInit() {
  this.loadData(); // 返回时不会执行
}

八、总结 #

8.1 导航要点 #

要点 说明
页面跳转 routerLink、Router.navigate、NavController
参数传递 路径参数、查询参数、路由状态
返回处理 ion-back-button、NavController.back()
生命周期 ionViewWillEnter/Leave
导航动画 前进、后退、根页面

9.2 下一步 #

掌握了页面导航后,接下来让我们学习 Tabs导航,了解Ionic的标签页导航系统!

最后更新:2026-03-28