前言

在 HarmonyOS NEXT 开发过程中,弹框(Dialog) 几乎是每个应用都会使用到的组件。

例如:

  • 登录确认
  • 删除确认
  • 支付密码
  • 分享面板
  • Loading
  • Toast
  • BottomSheet
  • 自定义输入框
  • 图片预览
  • 权限申请

很多刚开始学习 HarmonyOS 的开发者都会有这样的疑问:

HarmonyOS 里面为什么有这么多 Dialog?

官方文档中常见的就有:

  • OpenCustomDialog
  • CustomDialog
  • DialogController
  • PromptAction
  • AlertDialog
  • ActionSheet
  • DialogHub(项目封装)
  • OverlayManager(API13+)

尤其很多项目里面都会封装一个 DialogHub

于是很多人会问:

DialogHub 是官方的吗?

不是。

它只是很多大型项目都会封装出来的一个统一管理 Dialog 的方案

本文将彻底讲清楚:

  • OpenCustomDialog 到底是什么?
  • CustomDialog 和 OpenCustomDialog 的关系
  • DialogController 的作用
  • DialogHub 为什么会出现
  • 三者适合什么场景
  • 企业项目一般如何封装
  • 如何避免 Dialog 泄漏
  • 如何实现全局弹框
  • 如何实现 Promise 风格 Dialog
  • 如何实现 Dialog 队列
  • 如何实现 Dialog 防重复

本文预计 2 万字左右,建议收藏。


一、HarmonyOS Dialog 发展过程

ArkUI 的 Dialog 大致经历几个阶段。


AlertDialog
        │
        ▼
CustomDialog
        │
        ▼
DialogController
        │
        ▼
OpenCustomDialog
        │
        ▼
OverlayManager(API13)

其中企业开发里面又衍生出了:


DialogHub

注意:

DialogHub 并不是官方组件,而是开发者封装出来的一套管理方案。


二、什么是 OpenCustomDialog

OpenCustomDialog 是 HarmonyOS 提供的:

任意时刻打开一个自定义 Dialog 的能力。

以前使用 Dialog,一般需要:


Button
 ↓
Controller.open()

必须有 Controller。

现在可以:


Button
 ↓
openCustomDialog()

直接打开。

例如:


Button("打开Dialog")
.onClick(()=>{
    openCustomDialog({
        builder: () => {
            MyDialog()
        }
    })
})

是不是简单很多?


它最大的特点

无需 Controller。

无需提前创建对象。

直接打开即可。

所以它非常适合:

  • 临时 Dialog
  • Toast
  • Loading
  • 分享面板
  • 输入框

三、OpenCustomDialog 原理

内部其实就是:


UIContext
        │
        ▼
Overlay
        │
        ▼
Dialog

流程如下:


点击按钮
      │
      ▼
openCustomDialog()
      │
      ▼
创建Overlay节点
      │
      ▼
插入Window
      │
      ▼
显示Dialog

因此它其实也是 Overlay 的一种。


四、什么是 CustomDialog

CustomDialog 更早。

它本质就是:


一个可以继承的 Dialog 类

例如:


@CustomDialog
struct DeleteDialog{

    controller?: CustomDialogController

    build(){
        Column(){

            Text("确定删除吗")

            Button("确定")
        }
    }
}

然后:


let controller=new CustomDialogController({
    builder:DeleteDialog()
})

controller.open()

是不是发现:

需要 Controller。


五、为什么需要 Controller

Controller 管理的是:


Dialog 生命周期

包括:


open()

close()

update()

cancel()

例如:


Dialog
    │
    ▼
Controller
    │
    ▼
业务代码

因此 Controller 非常适合:

  • 长生命周期
  • 多次打开
  • 多次关闭

例如:

支付密码。


六、OpenCustomDialog 与 CustomDialog 的区别

对比项 OpenCustomDialog CustomDialog
Controller 不需要 需要
生命周期 临时 长生命周期
使用难度 简单 略复杂
推荐程度 ⭐⭐⭐⭐⭐ ⭐⭐⭐
企业使用 非常多 较多
API 风格 函数
可复用 一般 很强
维护成本

一句话总结:

OpenCustomDialog 更适合快速弹框;CustomDialog 更适合需要完整生命周期管理和复用的复杂弹框。


七、什么是 DialogHub

重点来了。

很多人第一次看到:


DialogHub.show()

还以为官方 API。

其实:

不是。

它只是:


项目封装

例如:


DialogHub

├── showLoading()

├── hideLoading()

├── showDialog()

├── showConfirm()

├── showSuccess()

├── showError()

├── showInput()

└── showBottomDialog()

是不是很像:

Android:


DialogManager

或者:

iOS:


HUDManager

八、为什么需要 DialogHub

大型项目里面:

假设有:


100

页面

如果每个页面:


new Controller

管理起来会非常混乱。

例如:


PageA

PageB

PageC

PageD

PageE

每个页面:


Loading

Confirm

Input

Toast

Error

Success

可能:


600+

Dialog

维护非常困难。

于是:

统一管理。


DialogHub
      │
      ▼
所有Dialog

九、DialogHub 的核心思想

统一入口。

例如:


DialogHub.showConfirm({
    title:"删除",
    message:"确定删除吗?"
})

而不是:


new Controller()

controller.open()

业务层根本不用关心 Controller。


十、DialogHub 内部实现思路

一般都会维护:


Map

例如:


Map<String,DialogController>

打开:


不存在

↓

创建

↓

缓存

关闭:


获取Controller

↓

close()

↓

删除

这样整个项目:

只有:


一个

DialogHub

十一、三者关系图


                 Dialog

                    │

      ┌─────────────┴──────────────┐

      ▼                            ▼

CustomDialog              OpenCustomDialog

      │

      ▼

DialogController

      │

      ▼

DialogHub(项目封装)

需要注意的是,DialogHub 并不是官方 API,而是建立在官方 Dialog 能力之上的统一管理层。


十二、三者优缺点总结

方案 优点 缺点 推荐场景
OpenCustomDialog 简洁、无需 Controller、开发效率高 生命周期控制较弱 临时提示、确认框、Loading
CustomDialog 生命周期完整、复用性强 代码量较多 复杂业务弹框
DialogHub 统一管理、便于维护、支持扩展 需要自行设计与维护 中大型项目、团队协作

十三、企业级最佳实践

在实际项目中,可以按照以下原则选择:

  • 简单页面弹框:优先使用 OpenCustomDialog
  • 复杂、可复用的业务弹框:使用 CustomDialog + DialogController
  • 中大型项目:封装 DialogHub,统一管理 Loading、确认框、输入框、全局提示等能力。
  • 需要跨页面、全局展示的浮层:根据 API 版本,优先考虑 OverlayManager 等更现代的浮层管理能力。

一个典型的企业架构如下:


业务页面
    │
    ▼
DialogHub
    │
    ├── OpenCustomDialog(简单弹框)
    ├── CustomDialog(复杂弹框)
    └── OverlayManager(全局浮层,API13+)

十四、常见问题(FAQ)

Q1:OpenCustomDialog 会取代 CustomDialog 吗?

不会。

两者定位不同。前者强调快速打开,后者强调生命周期管理与复用

Q2:DialogHub 是官方提供的吗?

不是。它是很多团队根据项目需求封装的统一 Dialog 管理器,没有官方统一实现。

Q3:什么时候一定要使用 DialogController?

当弹框需要被多次打开、关闭、更新,或者需要在不同逻辑中精确控制生命周期时,DialogController 会更加合适。

Q4:DialogHub 一定要用吗?

小型项目没有必要。随着页面和弹框数量增加,统一管理能够降低维护成本,因此中大型项目更值得采用。


总结

OpenCustomDialogCustomDialogDialogHub 并不是相互替代的关系,而是分别解决不同层级的问题:

  • OpenCustomDialog:官方提供的轻量级弹框能力,适合快速展示临时 Dialog。
  • CustomDialog:官方提供的可复用自定义弹框机制,配合 DialogController 实现完整生命周期管理。
  • DialogHub:项目层面的封装方案,将各种官方 Dialog 能力统一管理,便于大型项目维护和扩展。

如果按企业开发经验给出建议,可以遵循下面这套原则:

项目规模 推荐方案
学习 Demo OpenCustomDialog
中小型项目 OpenCustomDialog + 少量 CustomDialog
中大型项目 DialogHub + OpenCustomDialog + CustomDialog
企业级应用 DialogHub + OverlayManager(新版 API)+ 自定义弹框组件体系

掌握这三者的定位和协作方式,可以帮助你设计出更清晰、更易维护的鸿蒙弹框架构,也能避免后期因为弹框管理混乱而带来的维护成本。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐