鸿蒙 7 弹窗与自定义
做业务开发,弹窗几乎是绕不开的组件。确认提示、表单填写、选择器、消息提醒,全都要用弹窗。很多新手一开始只会用AlertDialog简单提示框,一旦遇到复杂需求,比如弹窗里面放图片、输入框、多行按钮,原生 AlertDialog 就不够用了。
网上不少旧版本鸿蒙的弹窗代码,拿到鸿蒙 7 直接报错。有的人直接用全屏页面模拟弹窗,写出来遮罩层、动画、关闭逻辑一堆 bug,点击遮罩无法关闭,弹窗层级错乱,多次打开还会重复创建实例,内存占用越来越高。
今天就把鸿蒙 7 里两种弹窗方案一次性讲清楚:系统简易弹窗 AlertDialog,还有业务开发最常用的@CustomDialog自定义弹窗。代码全部可直接运行,顺带讲清楚弹窗生命周期、遮罩控制、弹窗传参,以及高频踩坑点。
一、分清两种弹窗,按需选择
- AlertDialog:系统自带简易弹窗。适合纯文字提示、简单确认取消按钮。优点:一行代码快速拉起,不用写额外组件;缺点:布局固定,不能自由放输入框、图片、复杂 UI。
- @CustomDialog:自定义弹窗。完全自由写内部 UI,支持输入框、列表、图片、多按钮。正式项目复杂弹窗首选。
类比理解:AlertDialog 相当于外卖现成快餐,拿来直接吃;@CustomDialog 是你自己买菜做饭,布局、样式、交互全部自定义,自由度更高。
误区提醒:不要用 Page 页面模拟弹窗。自己写的遮罩层很难处理层级、动画、键盘避让,鸿蒙 7 提供的 @CustomDialog 底层已经帮你处理好这些问题,稳定性远高于自己手写。
1. 最简系统弹窗 AlertDialog
简单提示场景,直接调用系统弹窗。
import { AlertDialog } from '@kit.ArkUI';
@Entry
@Component
struct AlertDialogDemoPage {
build() {
Column() {
Button("打开系统确认弹窗")
.onClick(() => {
AlertDialog.show({
title: "操作确认",
message: "确定要提交本次修改吗?",
primaryButton: {
value: "确认",
action: () => {
console.info("用户点击确认")
}
},
secondaryButton: {
value: "取消",
action: () => {
console.info("用户点击取消")
}
}
})
})
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}
关键语句拆解
AlertDialog.show():静态方法,直接唤起系统弹窗,不需要提前创建实例。
- title:弹窗标题;message:弹窗正文文本;
- primaryButton:主按钮,一般是确认;secondaryButton:次要按钮,一般是取消。
执行效果
点击按钮,页面中间弹出系统样式弹窗,有标题、文字、两个按钮,点击按钮自动关闭弹窗。
局限性
弹窗内部布局固定,没法自定义插入 TextInput、图片、多行列 UI。复杂表单弹窗,必须用 @CustomDialog。

二、@CustomDialog 基础自定义弹窗
@CustomDialog 是鸿蒙 7 专门用来定义自定义弹窗的装饰器,把弹窗 UI 单独封装。弹窗的打开关闭依靠DialogController控制器。
完整基础示例:
import { CustomDialog, DialogController } from '@kit.ArkUI';
// 定义自定义弹窗
@CustomDialog
struct SimpleCustomDialog {
// 弹窗控制器,框架自动注入
controller: DialogController;
// 外部传入弹窗标题
@Prop dialogTitle: string;
build() {
Column() {
Text(this.dialogTitle)
.fontSize(22)
.fontWeight(FontWeight.Medium)
.margin({bottom:16})
Text("这是自定义弹窗,布局可以完全自由编写")
.fontSize(16)
.fontColor("#666")
Row() {
Button("关闭弹窗")
.onClick(() => {
// 控制器关闭弹窗
this.controller.close()
})
}
.margin({top:20})
}
.padding(24)
.width("85%")
.borderRadius(16)
.backgroundColor("#ffffff")
}
}
@Entry
@Component
struct CustomDialogPage {
// 创建弹窗控制器
@State dialogCtrl: DialogController = new DialogController();
build() {
Column() {
Button("打开自定义弹窗")
.onClick(() => {
this.dialogCtrl.open()
})
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}
关键说明
@CustomDialog:标记这个结构体是弹窗组件,和 @Component 不一样,弹窗组件必须依赖 DialogController。 controller: DialogController; 固定写法,框架自动注入,弹窗内部调用this.controller.close()关闭弹窗。 this.dialogCtrl.open():页面调用控制器 open,唤起弹窗。
运行效果:点击按钮,弹出圆角白色自定义弹窗,点击弹窗内按钮可以关闭。

三、弹窗传参 + 回调:弹窗内部操作,通知父页面
实际业务弹窗,经常需要弹窗输入内容,点击确认后把输入内容回传给页面。 思路:父页面传回调函数到弹窗,弹窗内用户操作完成,调用回调,同时关闭弹窗。
完整带输入框弹窗示例:
import { CustomDialog, DialogController } from '@kit.ArkUI';
@CustomDialog
struct InputCustomDialog {
controller: DialogController;
@Prop dialogTitle: string;
// 回调,把输入的文本传回父页面
@Param onConfirm: (inputText:string)=>void;
@State inputVal: string = "";
build() {
Column() {
Text(this.dialogTitle)
.fontSize(22)
.margin({bottom:16})
TextInput({text:this.inputVal, placeholder:"请输入内容"})
.onChange((val:string)=>{
this.inputVal = val
})
.border({width:1, color:"#ddd"})
.padding(8)
Row() {
Button("取消")
.onClick(()=>{
this.controller.close()
})
Button("确认")
.onClick(()=>{
// 执行回调,把输入内容传给父页面
this.onConfirm(this.inputVal)
this.controller.close()
})
}
.margin({top:20})
.gap(12)
}
.padding(24)
.width("85%")
.borderRadius(16)
.backgroundColor("#fff")
}
}
@Entry
@Component
struct InputDialogPage {
@State dialogCtrl: DialogController = new DialogController();
@State showResult:string = "等待弹窗输入";
build() {
Column() {
Text(this.showResult).fontSize(20).margin({bottom:20})
Button("打开输入弹窗")
.onClick(() => {
this.dialogCtrl.open({
dialogTitle:"信息填写",
onConfirm: (text:string)=>{
this.showResult = `你输入的内容:${text}`
}
})
})
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.padding(20)
}
}
重点讲解
弹窗打开的时候,open({参数}),可以一次性把 @Prop、@Param 回调传给弹窗。 弹窗内部收集用户输入,点击确认,执行父页面传入的回调函数,完成数据回传,再关闭弹窗。

四、弹窗常用配置:遮罩、点击遮罩关闭、弹窗动画
打开弹窗时,可以额外配置弹窗行为,在 open 的第二个参数传入。
this.dialogCtrl.open({
dialogTitle:"提示"
},{
mask: true, // 是否显示遮罩层
maskClickClose: true, // 点击遮罩区域自动关闭弹窗
alignment: DialogAlignment.Center, // 弹窗居中
autoCancel: true
})
- maskClickClose:日常需求很常用,打开之后点击弹窗外面灰色区域直接关闭弹窗;
- alignment:支持居中、底部弹出 DialogAlignment.Bottom,做底部弹窗。
底部弹窗小提示:如果弹窗从底部弹出,记得给弹窗设置圆角,只设置顶部两个圆角,视觉更符合移动端习惯。

五、弹窗高频踩坑清单
坑 1:多次点击按钮,重复打开弹窗
连续快速点击打开弹窗按钮,会弹出多层弹窗。 解决办法:增加状态标记,弹窗打开时锁定按钮,弹窗关闭之后再解锁。
坑 2:弹窗内 @State 状态不会重置
弹窗关闭再重新打开,里面输入框还保留上次输入内容。 原因:DialogController 实例不会销毁,状态保留。解决:弹窗打开时重置变量,或者在 onWillOpen 生命周期里清空数据。
坑 3:键盘弹出遮挡弹窗输入框
不要自己手动计算位置,@CustomDialog 自带键盘避让逻辑,优先使用官方弹窗,不要手写页面模拟弹窗。
坑 4:混淆 @Component 和 @CustomDialog
把 @Component 结构体当做弹窗传入 DialogController,直接编译报错。弹窗组件必须用 @CustomDialog 装饰。
坑 5:弹窗回调丢失,忘记传参
open 的时候,没有传递 @Param 回调,弹窗点击确认调用 onConfirm 会直接崩溃。
六、弹窗选型速查表
| 弹窗类型 | API | 适用场景 |
|---|---|---|
| 简单提示确认框 | AlertDialog.show | 纯文本、少量按钮,不需要复杂 UI |
| 自由布局弹窗 | @CustomDialog + DialogController | 表单、图片、多组件复杂弹窗 |
| 底部弹窗 | @CustomDialog + alignment:DialogAlignment.Bottom | 底部选择菜单、操作面板 |
结尾总结
鸿蒙 7 弹窗分两大类,简单提示直接用 AlertDialog,复杂 UI 就上 @CustomDialog。
- @CustomDialog 用来定义弹窗,依靠 DialogController 的 open/close 控制弹窗显示隐藏;
- open 方法可以给弹窗传参数、传入回调函数,实现父子弹窗数据通信;
- 支持遮罩、点击遮罩关闭、设置弹窗弹出位置,直接配置即可;
- 注意连续点击重复弹窗、弹窗状态残留两个高频 bug;
- 业务开发不要自己写页面模拟弹窗,官方弹窗底层已经处理好动画、键盘、层级。
实操指南
基于本篇代码,写一个底部弹出的自定义弹窗,弹窗内部放两个选项按钮,点击选项关闭弹窗并且把选中的内容回传给页面。
更多推荐




所有评论(0)