Ionic导航组件 #
一、标签页组件(Tabs) #
1.1 基本用法 #
html
<!-- tabs.page.html -->
<ion-tabs>
<ion-tab-bar slot="bottom">
<ion-tab-button tab="home">
<ion-icon name="home"></ion-icon>
<ion-label>首页</ion-label>
</ion-tab-button>
<ion-tab-button tab="search">
<ion-icon name="search"></ion-icon>
<ion-label>搜索</ion-label>
</ion-tab-button>
<ion-tab-button tab="cart">
<ion-icon name="cart"></ion-icon>
<ion-label>购物车</ion-label>
<ion-badge>3</ion-badge>
</ion-tab-button>
<ion-tab-button tab="profile">
<ion-icon name="person"></ion-icon>
<ion-label>我的</ion-label>
</ion-tab-button>
</ion-tab-bar>
</ion-tabs>
1.2 路由配置 #
typescript
// 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: 'cart',
loadChildren: () => import('../cart/cart.module').then(m => m.CartPageModule)
},
{
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 {}
1.3 标签页样式 #
html
<!-- 顶部标签栏 -->
<ion-tabs>
<ion-tab-bar slot="top">
<!-- 标签按钮 -->
</ion-tab-bar>
</ion-tabs>
<!-- 自定义样式 -->
<ion-tabs>
<ion-tab-bar slot="bottom" class="custom-tab-bar">
<ion-tab-button tab="home">
<ion-icon name="home"></ion-icon>
<ion-label>首页</ion-label>
</ion-tab-button>
</ion-tab-bar>
</ion-tabs>
scss
// 自定义标签栏样式
.custom-tab-bar {
--background: #ffffff;
--color: #999999;
--color-selected: #3880ff;
height: 60px;
padding-bottom: env(safe-area-inset-bottom);
}
ion-tab-button {
--color: #999999;
--color-selected: #3880ff;
--color-focused: #3880ff;
ion-icon {
font-size: 24px;
}
ion-label {
font-size: 12px;
}
}
1.4 标签页徽章 #
html
<!-- 带徽章的标签 -->
<ion-tab-button tab="notifications">
<ion-icon name="notifications"></ion-icon>
<ion-label>通知</ion-label>
<ion-badge color="danger">5</ion-badge>
</ion-tab-button>
1.5 编程式切换 #
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) {}
goToCart() {
this.router.navigate(['/tabs/cart']);
}
goToProfile() {
this.router.navigateByUrl('/tabs/profile');
}
}
二、侧边菜单组件(Menu) #
2.1 基本用法 #
html
<!-- app.component.html -->
<ion-app>
<ion-menu side="start" contentId="main-content">
<ion-header>
<ion-toolbar>
<ion-title>菜单</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<ion-item routerLink="/home">
<ion-icon name="home" slot="start"></ion-icon>
<ion-label>首页</ion-label>
</ion-item>
<ion-item routerLink="/settings">
<ion-icon name="settings" slot="start"></ion-icon>
<ion-label>设置</ion-label>
</ion-item>
<ion-item routerLink="/about">
<ion-icon name="information-circle" slot="start"></ion-icon>
<ion-label>关于</ion-label>
</ion-item>
</ion-list>
</ion-content>
</ion-menu>
<ion-router-outlet id="main-content"></ion-router-outlet>
</ion-app>
2.2 菜单类型 #
html
<!-- 覆盖式菜单 -->
<ion-menu type="overlay" side="start" contentId="main-content">
<!-- 菜单内容 -->
</ion-menu>
<!-- 推出式菜单 -->
<ion-menu type="push" side="start" contentId="main-content">
<!-- 菜单内容 -->
</ion-menu>
<!-- 显示式菜单 -->
<ion-menu type="reveal" side="start" contentId="main-content">
<!-- 菜单内容 -->
</ion-menu>
2.3 双侧菜单 #
html
<ion-app>
<!-- 左侧菜单 -->
<ion-menu side="start" menuId="left-menu" contentId="main-content">
<ion-header>
<ion-toolbar>
<ion-title>左侧菜单</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<!-- 菜单项 -->
</ion-content>
</ion-menu>
<!-- 右侧菜单 -->
<ion-menu side="end" menuId="right-menu" contentId="main-content">
<ion-header>
<ion-toolbar>
<ion-title>右侧菜单</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<!-- 菜单项 -->
</ion-content>
</ion-menu>
<ion-router-outlet id="main-content"></ion-router-outlet>
</ion-app>
2.4 菜单控制 #
typescript
import { Component } from '@angular/core';
import { MenuController } from '@ionic/angular';
@Component({
selector: 'app-home',
templateUrl: 'home.page.html'
})
export class HomePage {
constructor(private menuCtrl: MenuController) {}
// 打开菜单
openMenu() {
this.menuCtrl.open('left-menu');
}
// 关闭菜单
closeMenu() {
this.menuCtrl.close();
}
// 切换菜单
toggleMenu() {
this.menuCtrl.toggle('left-menu');
}
// 启用/禁用菜单
enableMenu(enable: boolean) {
this.menuCtrl.enable(enable, 'left-menu');
}
}
2.5 菜单按钮 #
html
<!-- 工具栏菜单按钮 -->
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-menu-button></ion-menu-button>
</ion-buttons>
<ion-title>标题</ion-title>
</ion-toolbar>
</ion-header>
<!-- 指定菜单 -->
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-menu-button menu="left-menu"></ion-menu-button>
</ion-buttons>
<ion-buttons slot="end">
<ion-menu-button menu="right-menu"></ion-menu-button>
</ion-buttons>
<ion-title>标题</ion-title>
</ion-toolbar>
</ion-header>
2.6 菜单样式 #
scss
ion-menu {
--background: #ffffff;
--width: 280px;
ion-header {
ion-toolbar {
--background: #3880ff;
--color: #ffffff;
}
}
ion-item {
--background: transparent;
--color: #333333;
&:hover {
--background: #f5f5f5;
}
}
}
三、模态框组件(Modal) #
3.1 基本用法 #
typescript
import { Component } from '@angular/core';
import { ModalController } from '@ionic/angular';
import { DetailModalComponent } from './detail-modal/detail-modal.component';
@Component({
selector: 'app-home',
templateUrl: 'home.page.html'
})
export class HomePage {
constructor(private modalCtrl: ModalController) {}
async openModal() {
const modal = await this.modalCtrl.create({
component: DetailModalComponent,
componentProps: {
id: 1,
title: '详情'
}
});
await modal.present();
const { data, role } = await modal.onWillDismiss();
if (role === 'confirm') {
console.log('确认:', data);
}
}
}
3.2 模态框组件 #
typescript
// detail-modal.component.ts
import { Component, Input } from '@angular/core';
import { ModalController } from '@ionic/angular';
@Component({
selector: 'app-detail-modal',
template: `
<ion-header>
<ion-toolbar>
<ion-title>{{ title }}</ion-title>
<ion-buttons slot="end">
<ion-button (click)="close()">
<ion-icon name="close"></ion-icon>
</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content>
<p>详情内容...</p>
<ion-button expand="block" (click)="confirm()">确认</ion-button>
</ion-content>
`
})
export class DetailModalComponent {
@Input() id!: number;
@Input() title!: string;
constructor(private modalCtrl: ModalController) {}
close() {
this.modalCtrl.dismiss(null, 'cancel');
}
confirm() {
this.modalCtrl.dismiss({ result: 'success' }, 'confirm');
}
}
3.3 模态框样式 #
typescript
// 全屏模态框
const modal = await this.modalCtrl.create({
component: DetailModalComponent,
cssClass: 'my-custom-modal'
});
// 底部弹出模态框
const modal = await this.modalCtrl.create({
component: DetailModalComponent,
breakpoints: [0, 0.5, 1],
initialBreakpoint: 0.5
});
// 卡片式模态框
const modal = await this.modalCtrl.create({
component: DetailModalComponent,
presentingElement: await this.modalCtrl.getTop()
});
scss
// 自定义模态框样式
.my-custom-modal {
--height: 80%;
--width: 90%;
--border-radius: 16px;
--box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
}
3.4 模态框动画 #
typescript
const modal = await this.modalCtrl.create({
component: DetailModalComponent,
enterAnimation: myEnterAnimation,
leaveAnimation: myLeaveAnimation
});
四、弹出框组件(Popover) #
4.1 基本用法 #
typescript
import { Component } from '@angular/core';
import { PopoverController } from '@ionic/angular';
import { MyPopoverComponent } from './my-popover/my-popover.component';
@Component({
selector: 'app-home',
templateUrl: 'home.page.html'
})
export class HomePage {
constructor(private popoverCtrl: PopoverController) {}
async showPopover(ev: any) {
const popover = await this.popoverCtrl.create({
component: MyPopoverComponent,
event: ev,
translucent: true
});
await popover.present();
const { data } = await popover.onWillDismiss();
console.log('选择:', data);
}
}
html
<!-- 触发弹出框 -->
<ion-button (click)="showPopover($event)">
显示选项
</ion-button>
4.2 弹出框组件 #
typescript
// my-popover.component.ts
import { Component } from '@angular/core';
import { PopoverController } from '@ionic/angular';
@Component({
selector: 'app-my-popover',
template: `
<ion-list>
<ion-item button (click)="select('edit')">
<ion-icon name="create" slot="start"></ion-icon>
<ion-label>编辑</ion-label>
</ion-item>
<ion-item button (click)="select('delete')">
<ion-icon name="trash" slot="start" color="danger"></ion-icon>
<ion-label color="danger">删除</ion-label>
</ion-item>
<ion-item button (click)="select('share')">
<ion-icon name="share" slot="start"></ion-icon>
<ion-label>分享</ion-label>
</ion-item>
</ion-list>
`
})
export class MyPopoverComponent {
constructor(private popoverCtrl: PopoverController) {}
select(action: string) {
this.popoverCtrl.dismiss({ action });
}
}
4.3 弹出框位置 #
typescript
const popover = await this.popoverCtrl.create({
component: MyPopoverComponent,
event: ev,
side: 'right', // left, right, top, bottom
alignment: 'center' // start, center, end
});
4.4 弹出框样式 #
scss
ion-popover {
--background: #ffffff;
--box-shadow: 0 5px 20px rgba(0, 0, 0, 0.15);
--width: 200px;
--border-radius: 8px;
}
五、导航控制器 #
5.1 页面导航 #
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');
}
// 根页面
goRoot() {
this.navCtrl.navigateRoot('/login');
}
// 返回上一页
goBackOne() {
this.navCtrl.back();
}
}
5.2 导航传参 #
typescript
// 发送页面
goToDetail() {
this.navCtrl.navigateForward(['/detail', 1], {
queryParams: {
from: 'home',
type: 'edit'
}
});
}
// 接收页面
import { ActivatedRoute } from '@angular/router';
export class DetailPage implements OnInit {
id: string = '';
from: string = '';
constructor(private route: ActivatedRoute) {}
ngOnInit() {
this.id = this.route.snapshot.paramMap.get('id') || '';
this.route.queryParams.subscribe(params => {
this.from = params['from'];
});
}
}
六、导航栏组件 #
6.1 基本导航栏 #
html
<ion-header>
<ion-toolbar>
<ion-title>页面标题</ion-title>
</ion-toolbar>
</ion-header>
6.2 带按钮的导航栏 #
html
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button defaultHref="/home"></ion-back-button>
</ion-buttons>
<ion-title>详情页</ion-title>
<ion-buttons slot="end">
<ion-button (click)="edit()">
<ion-icon name="create" slot="icon-only"></ion-icon>
</ion-button>
<ion-button (click)="more()">
<ion-icon name="ellipsis-vertical" slot="icon-only"></ion-icon>
</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
6.3 搜索栏 #
html
<ion-header>
<ion-toolbar>
<ion-searchbar
placeholder="搜索..."
(ionInput)="onSearch($event)"
(ionCancel)="onCancel()">
</ion-searchbar>
</ion-toolbar>
</ion-header>
6.4 段选择器 #
html
<ion-header>
<ion-toolbar>
<ion-segment (ionChange)="onSegmentChange($event)">
<ion-segment-button value="all">
<ion-label>全部</ion-label>
</ion-segment-button>
<ion-segment-button value="active">
<ion-label>进行中</ion-label>
</ion-segment-button>
<ion-segment-button value="completed">
<ion-label>已完成</ion-label>
</ion-segment-button>
</ion-segment>
</ion-toolbar>
</ion-header>
七、页面生命周期 #
7.1 Ionic生命周期 #
typescript
import { Component, OnInit } from '@angular/core';
import {
IonViewWillEnter,
IonViewDidEnter,
IonViewWillLeave,
IonViewDidLeave
} from '@ionic/angular';
@Component({
selector: 'app-detail',
templateUrl: 'detail.page.html'
})
export class DetailPage implements OnInit {
// Angular生命周期
ngOnInit() {
console.log('组件初始化');
}
ngOnDestroy() {
console.log('组件销毁');
}
// Ionic生命周期
ionViewWillEnter() {
console.log('页面即将进入');
}
ionViewDidEnter() {
console.log('页面已进入');
}
ionViewWillLeave() {
console.log('页面即将离开');
}
ionViewDidLeave() {
console.log('页面已离开');
}
}
7.2 生命周期流程 #
text
页面导航流程:
进入页面:
ngOnInit → ionViewWillEnter → ionViewDidEnter
离开页面:
ionViewWillLeave → ionViewDidLeave → ngOnDestroy
返回页面:
ionViewWillEnter → ionViewDidEnter
八、最佳实践 #
8.1 导航结构 #
text
推荐结构:
├── tabs/
│ ├── home/
│ ├── search/
│ └── profile/
├── auth/
│ ├── login/
│ └── register/
└── detail/
8.2 懒加载 #
typescript
// 路由懒加载
const routes: Routes = [
{
path: 'detail/:id',
loadChildren: () => import('./detail/detail.module')
.then(m => m.DetailPageModule)
}
];
8.3 路由守卫 #
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]
}
];
九、总结 #
9.1 组件对比 #
| 组件 | 用途 | 特点 |
|---|---|---|
| Tabs | 底部标签导航 | 固定导航、徽章支持 |
| Menu | 侧边菜单 | 左右菜单、多种类型 |
| Modal | 模态框 | 全屏/半屏、数据传递 |
| Popover | 弹出框 | 上下文菜单、选项 |
9.2 下一步 #
掌握了导航组件后,接下来让我们学习 数据展示组件,了解Ionic的数据展示方式!
最后更新:2026-03-28