Ionic 模态窗口(Modal)完整实战指南
(Ionic 7+,支持 Angular / React / Vue 都通用)
ion-modal 是 Ionic 最强大的弹窗组件,比 alert 更灵活、比 popover 更大、支持任意页面内容!
1. 基本使用(90% 场景都这么写)
// 在任意页面或服务中注入
import { ModalController } from '@ionic/angular';
constructor(private modalCtrl: ModalController) {}
// 打开模态窗口
async openModal() {
const modal = await this.modalCtrl.create({
component: DetailPage, // 要弹出的页面组件
componentProps: { // 传参给弹窗页面
id: 123,
name: '张三'
},
cssClass: 'my-modal', // 自定义样式
backdropDismiss: true, // 点击背景关闭
showBackdrop: true, // 显示背景遮罩
mode: 'ios', // 强制 iOS 风格
// animated: false // 关闭动画(调试用)
});
await modal.present();
// 接收弹窗返回的数据
const { data, role } = await modal.onWillDismiss();
if (role === 'confirm') {
console.log('用户点击了确定,返回数据:', data);
}
}
2. 被弹出的页面(DetailPage)怎么接收参数和返回数据?
// detail.page.ts
import { Component, Input } from '@angular/core';
import { ModalController } from '@ionic/angular';
@Component({
selector: 'app-detail',
templateUrl: 'detail.page.html'
})
export class DetailPage {
@Input() id: number;
@Input() name: string;
constructor(private modalCtrl: ModalController) {}
// 关闭并返回数据
confirm() {
this.modalCtrl.dismiss({
selectedItem: '苹果',
count: 5
}, 'confirm');
}
// 取消关闭
cancel() {
this.modalCtrl.dismiss(null, 'cancel');
}
}
<!-- detail.page.html -->
<ion-header>
<ion-toolbar>
<ion-title>商品详情</ion-title>
<ion-buttons slot="end">
<ion-button (click)="cancel()">关闭</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<h2>ID: {{ id }}</h2>
<p>你好,{{ name }}!</p>
<ion-button expand="block" (click)="confirm()">确认购买</ion-button>
</ion-content>
3. 超实用样式大全(直接复制就美)
| 样式需求 | 代码写法 | 效果说明 |
|---|---|---|
| 小窗口(50% 宽) | cssClass: 'small-modal' | 登录、表单 |
| 全屏模态 | cssClass: 'full-modal' | 图片预览、地图 |
| 底部抽屉式 | cssClass: 'bottom-modal', breakpoints: [0, 0.4, 0.8, 1], initialBreakpoint: 0.4 | 评论、分享 |
| 从底部滑出 | enterAnimation, leaveAnimation | 微信式弹窗 |
| 透明背景 | --background: transparent | 自定义动画 |
推荐:底部抽屉式模态(超火!)
const modal = await this.modalCtrl.create({
component: CommentPage,
breakpoints: [0, 0.3, 0.5, 0.8, 1], // 可停留的高度
initialBreakpoint: 0.5, // 初始高度 50%
handle: true, // 显示顶部拖拽条
backdropDismiss: true
});
4. 自定义动画(从底部滑入)
import { AnimationController } from '@ionic/angular';
async openBottomModal() {
const modal = await this.modalCtrl.create({
component: SharePage,
enterAnimation: this.enterAnimation,
leaveAnimation: this.leaveAnimation
});
await modal.present();
}
// 自定义进入动画
enterAnimation = (baseEl: HTMLElement) => {
const backdrop = baseEl.querySelector('ion-backdrop')!;
const wrapper = baseEl.querySelector('.modal-wrapper')!;
const backdropAnimation = this.animationCtrl
.create()
.addElement(backdrop)
.fromTo('opacity', 0, 0.6);
const wrapperAnimation = this.animationCtrl
.create()
.addElement(wrapper)
.fromTo('transform', 'translateY(100%)', 'translateY(0)')
.fromTo('border-radius', '20px 20px 0 0', '0');
return this.animationCtrl
.create()
.addElement(baseEl)
.duration(400)
.easing('cubic-bezier(0.36,0.66,0.04,1)')
.addAnimation([backdropAnimation, wrapperAnimation]);
};
5. 全局封装(推荐放 service)
// modal.service.ts
@Injectable({ providedIn: 'root' })
export class ModalService {
constructor(private modalCtrl: ModalController) {}
async open(component: any, props?: any, cssClass = '') {
const modal = await this.modalCtrl.create({
component,
componentProps: props,
cssClass,
backdropDismiss: true
});
await modal.present();
return modal;
}
async openBottom(component: any, props?: any) {
return this.open(component, props, 'bottom-modal');
}
}
6. 常见问题速查
| 问题 | 解决方案 |
|---|---|
| 键盘遮挡输入框 | ion-content 加 scroll-y="true" |
| 模态窗口内容不滚动 | 在弹窗页面加 <ion-content> |
| 想让模态窗口不可关闭 | backdropDismiss: false + 提供关闭按钮 |
| 多个模态叠加 | 支持!后打开的在上层 |
| 关闭所有模态 | this.modalCtrl.dismiss(null, null, null, true) |
7. 一句话总结最优雅写法
const modal = await this.modalCtrl.create({
component: MyPage,
componentProps: { id: 1 },
breakpoints: [0, 0.5, 1],
initialBreakpoint: 0.5,
handle: true
});
await modal.present();
const { data } = await modal.onDidDismiss();
这样写出来的模态窗口,iOS 是毛玻璃抽屉,Android 是丝滑上滑,体验完美!
需要我直接发你一个「图片预览 + 手势缩放 + 底部评论抽屉」的完整可运行模板吗?一句话就发~