前言导读
之前我写过一篇关于 openCustomDialog 自定义弹窗的文档 ,但是在后面的开发过程中发现这个管理起来特别麻烦,所以我就写了这个进阶版本,能够更好管理弹窗的现实和隐藏 以及弹窗清栈操作等等。 使用 BaseDialog + DialogManager 来管理的我们的弹窗
效果图
用到的技术点
openCustomDialog 来实现,自定义弹窗 openCustomDialog 可以看之前的文章
鸿蒙next openCustomDialog 实现不依赖UI的自定义弹窗
HarmonyOS 弹窗管理系统使用文档
一、概述
本弹窗管理系统采用 BaseDialog + DialogManager 架构,实现了弹窗的统一管理、复用和扩展。
架构特点
- 单例模式:DialogManager 采用单例设计,全局统一管理
- 泛型支持:BaseDialog 支持泛型参数,灵活适配不同弹窗
- 弹窗栈管理:使用栈结构管理弹窗层级,支持多弹窗叠加
- 自动适配:自动检测屏幕方向,适配横竖屏布局
二、文件结构
pages/
├── BaseDialog.ets # 弹窗基类
├── DialogManger.ets # 弹窗管理器
└── PrivacyPolicyDialog.ets # 隐私政策弹窗示例
三、核心类说明
3.1 BaseDialog
弹窗基类,封装通用弹窗逻辑。
| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
show(params, options?) | params: T, options?: DialogOptions | Promise | 显示弹窗 |
hide() | - | Promise | 隐藏弹窗 |
update(params) | params: T | void | 更新弹窗内容 |
getIsShowing() | - | boolean | 获取弹窗显示状态 |
getDialogType() | - | DialogType | 获取弹窗类型 |
3.2 DialogManager
弹窗管理器,统一管理所有弹窗。
| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
getInstance() | - | DialogManager | 获取单例实例 |
init() | - | DialogManager | 初始化管理器 |
registerDialog(type, builder) | DialogType, WrappedBuilder | DialogManager | 注册弹窗 |
show(type, params?, options?) | DialogType, T?, DialogOptions? | Promise | 显示弹窗 |
hide(type) | DialogType | Promise | 隐藏弹窗 |
hideAll() | - | Promise | 隐藏所有弹窗 |
hideTop() | - | Promise | 隐藏最顶层弹窗 |
isShowing(type) | DialogType | boolean | 检查弹窗是否显示 |
hasDialogShowing() | - | boolean | 检查是否有弹窗显示 |
3.3 DialogType 枚举
export enum DialogType {
PRIVACY_POLICY = 'privacy_policy', // 隐私政策弹窗
USER_PROTOCOL = 'user_protocol', // 用户协议弹窗
EXIT_CONFIRM = 'exit_confirm', // 退出确认弹窗
LOADING = 'loading', // 加载弹窗
ALERT = 'alert', // 提示弹窗
CONFIRM = 'confirm', // 确认弹窗
CUSTOM = 'custom' // 自定义弹窗
}
3.4 DialogOptions 配置
export interface DialogOptions {
alignment?: DialogAlignment; // 弹窗位置,默认 Center
isModal?: boolean; // 是否模态,默认 true
autoCancel?: boolean; // 点击遮罩是否关闭,默认 false
keyboardAvoidMode?: KeyboardAvoidMode; // 键盘避让模式,默认 NONE
maskColor?: ResourceColor; // 遮罩颜色
onWillDismiss?: (action) => void; // 弹窗即将关闭回调
}
四、使用示例
4.1 初始化(在 EntryAbility 中)
import { DialogManager } from '../pages/DialogManger';
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// 初始化弹窗管理器
DialogManager.getInstance().init();
}
}
4.2 显示/隐藏弹窗
import { DialogManager } from '../pages/DialogManger';
import { DialogType } from '../pages/BaseDialog';
// 方式一:使用便捷方法
await DialogManager.getInstance().showPrivacyPolicyDialog();
await DialogManager.getInstance().hidePrivacyPolicyDialog();
// 方式二:使用通用方法
await DialogManager.getInstance().show(DialogType.PRIVACY_POLICY);
await DialogManager.getInstance().hide(DialogType.PRIVACY_POLICY);
// 方式三:带参数显示
const params = new PrivacyPolicyParams();
params.title = "自定义标题";
await DialogManager.getInstance().show(DialogType.PRIVACY_POLICY, params);
4.3 自定义弹窗配置
import { DialogOptionsImpl } from '../pages/BaseDialog';
const options = new DialogOptionsImpl();
options.alignment = DialogAlignment.Bottom;
options.isModal = true;
options.autoCancel = true;
options.maskColor = '#80000000';
await DialogManager.getInstance().show(DialogType.PRIVACY_POLICY, params, options);
4.4 批量关闭弹窗
// 关闭所有弹窗
await DialogManager.getInstance().hideAll();
// 关闭最顶层弹窗
await DialogManager.getInstance().hideTop();
4.5 查询弹窗状态
// 检查特定弹窗是否显示
if (DialogManager.getInstance().isShowing(DialogType.PRIVACY_POLICY)) {
console.log('隐私政策弹窗正在显示');
}
// 检查是否有任何弹窗显示
if (DialogManager.getInstance().hasDialogShowing()) {
console.log(`当前有 ${DialogManager.getInstance().getShowingCount()} 个弹窗`);
}
// 获取所有正在显示的弹窗类型
const showingDialogs = DialogManager.getInstance().getShowingDialogs();
五、自定义弹窗开发指南
5.1 创建弹窗参数类
import { IBaseDialogParams } from './BaseDialog';
export class MyDialogParams implements IBaseDialogParams {
flag?: boolean; // 必须:屏幕方向标志
title?: string; // 自定义参数
content?: string;
onConfirm?: () => void;
onCancel?: () => void;
constructor() {
this.title = "默认标题";
}
}
5.2 创建弹窗组件
@Component
export struct MyDialog {
param: MyDialogParams = new MyDialogParams();
build() {
Column() {
Text(this.param.title)
.fontSize(20)
.fontWeight(FontWeight.Bold)
Text(this.param.content)
.fontSize(16)
.margin({ top: 10 })
Row() {
Button('取消')
.onClick(() => {
DialogManager.getInstance().hide(DialogType.CUSTOM);
this.param.onCancel?.();
})
Button('确认')
.onClick(() => {
DialogManager.getInstance().hide(DialogType.CUSTOM);
this.param.onConfirm?.();
})
}
.margin({ top: 20 })
}
.width(this.param.flag ? '80%' : '40%') // 横竖屏适配
.padding(20)
.backgroundColor(Color.White)
.borderRadius(12)
}
}
@Builder
export function myDialogBuilder(params: MyDialogParams) {
MyDialog({ param: params })
}
5.3 注册弹窗
// 方式一:在 DialogManager.registerDefaultDialogs() 中添加
private registerDefaultDialogs(): void {
this.registerDialog<PrivacyPolicyParams>(
DialogType.PRIVACY_POLICY,
wrapBuilder(privacyPolicyDialogBuilder)
);
// 添加自定义弹窗
this.registerDialog<MyDialogParams>(
DialogType.CUSTOM,
wrapBuilder(myDialogBuilder)
);
}
// 方式二:动态注册
DialogManager.getInstance().registerDialog<MyDialogParams>(
DialogType.CUSTOM,
wrapBuilder(myDialogBuilder)
);
5.4 使用自定义弹窗
const params = new MyDialogParams();
params.title = "提示";
params.content = "确定要执行此操作吗?";
params.onConfirm = () => {
console.log('用户点击了确认');
};
params.onCancel = () => {
console.log('用户点击了取消');
};
await DialogManager.getInstance().show(DialogType.CUSTOM, params);
六、最佳实践
6.1 在弹窗内部关闭自身
// 推荐:通过 DialogManager 关闭
DialogManager.getInstance().hide(DialogType.PRIVACY_POLICY);
// 不推荐:直接调用 promptAction(会导致状态不同步)
6.2 处理返回键
const options = new DialogOptionsImpl();
options.onWillDismiss = (action: DismissDialogAction) => {
if (action.reason === DismissReason.PRESS_BACK) {
// 阻止返回键关闭
action.dismiss;
// 或执行自定义逻辑
}
};
6.3 弹窗生命周期管理
// 页面销毁时关闭所有弹窗
aboutToDisappear(): void {
DialogManager.getInstance().hideAll();
}
七、注意事项
- 必须初始化:使用前必须调用
DialogManager.getInstance().init() - 异步操作:
show()和hide()都是异步方法,需要使用await - 参数传递:弹窗参数中的
flag会自动设置,无需手动指定 - 弹窗注册:使用前必须先注册弹窗,否则会抛出异常
- ArkTS 兼容:代码已适配 ArkTS 严格模式,避免使用对象展开等不支持的语法
八、版本历史
| 版本 | 日期 | 说明 |
|---|---|---|
| 1.0.0 | 2025-09-03 | 初始版本,支持基础弹窗管理 |
| 2.0.0 | 2025-09-04 | 重构为 BaseDialog + DialogManager 架构 |