OpenHarmony CustomDialog 自定义弹窗实战开发

发布时间:2026/7/25 2:54:55
OpenHarmony CustomDialog 自定义弹窗实战开发 一、前言前文使用的AlertDialog样式固定仅能配置标题、文本、按钮无法满足头像选择、表单弹窗、确认弹窗、底部弹窗等个性化界面需求。OpenHarmony 提供CustomDialog自定义弹窗组件基于 ArkUI 自由布局支持自定义样式、交互、尺寸、动画是项目中高频使用的进阶组件。本文讲解自定义弹窗定义、调用传参、弹窗样式、关闭逻辑、嵌套交互搭配多个可直接运行的案例并结合全局状态完成综合实战。二、核心基础说明定义规则使用CustomDialog装饰器声明自定义弹窗区别于普通页面组件Component。弹窗参数通过DialogParam接收外部传入参数、回调函数实现父子通信。关闭弹窗组件内置controller.close()方法主动关闭弹窗。弹窗控制器CustomDialogController用于创建、唤起、控制弹窗。三、基础用法简单提示弹窗3.1 基础自定义弹窗纯提示 双按钮ets// 1. 定义自定义弹窗 CustomDialog struct SimpleDialog { // 弹窗控制器内置方法close() controller: CustomDialogController // 接收外部回调 DialogParam confirmCallback: () void DialogParam cancelCallback: () void build() { Column({ space: 20 }) { // 弹窗标题 Text(操作提示) .fontSize(20) .fontWeight(FontWeight.Bold) // 内容 Text(确定执行当前操作吗).fontSize(16) // 按钮区域 Row({ space: 30 }) { Button(取消) .width(100) .backgroundColor(#999) .onClick(() { this.controller.close() // 关闭弹窗 this.cancelCallback() // 执行取消回调 }) Button(确定) .width(100) .backgroundColor(#007DFF) .onClick(() { this.controller.close() this.confirmCallback() // 执行确定回调 }) } } .width(300) .padding(20) .backgroundColor(Color.White) .borderRadius(12) } } // 2. 页面入口调用弹窗 Entry Component struct DialogIndex { // 创建弹窗控制器 dialogController: CustomDialogController new CustomDialogController({ builder: SimpleDialog({ confirmCallback: () { console.log(点击了确定按钮) }, cancelCallback: () { console.log(点击了取消按钮) } }), // 弹窗配置点击遮罩是否关闭弹窗 autoCancel: true }) build() { Column() { Button(打开自定义提示弹窗) .width(220) .onClick(() { this.dialogController.open() // 唤起弹窗 }) } .width(100%) .height(100%) .justifyContent(FlexAlign.Center) } }3.2 配置项说明在CustomDialogController中可配置常用属性autoCancel布尔值点击弹窗外部遮罩层是否关闭弹窗默认truealignment弹窗对齐方式居中、底部、顶部、左侧、右侧offset弹窗偏移距离maskColor遮罩层颜色四、进阶案例 1带输入框的表单弹窗适用于弹窗内输入内容、评论、备注、修改昵称等场景实现弹窗内数据收集。etsCustomDialog struct InputDialog { controller: CustomDialogController // 回传给父页面的输入内容 DialogParam submit: (content: string) void State inputText: string build() { Column({ space: 18 }) { Text(请输入备注信息).fontSize(18).fontWeight(FontWeight.Bold) // 弹窗内输入框 TextInput({ placeholder: 在此输入内容, text: this.inputText }) .width(100%) .height(45) .onChange(val this.inputText val) Row({ space: 20 }) { Button(关闭) .layoutWeight(1) .backgroundColor(#EEEEEE) .fontColor(#333) .onClick(() this.controller.close()) Button(提交) .layoutWeight(1) .backgroundColor(#007DFF) .onClick(() { this.submit(this.inputText) this.controller.close() }) } } .width(320) .padding(20) .backgroundColor(Color.White) .borderRadius(10) } } Entry Component struct InputDialogPage { State result: string inputDialog: CustomDialogController new CustomDialogController({ builder: InputDialog({ submit: (val: string) { this.result 弹窗输入内容 val } }), autoCancel: false // 禁止点击遮罩关闭 }) build() { Column({ space: 20 }) { Button(打开输入弹窗) .width(220) .onClick(() this.inputDialog.open()) Text(this.result).fontSize(18) } .width(100%) .height(100%) .justifyContent(FlexAlign.Center) .padding(20) } }五、进阶案例 2底部弹窗底部弹出菜单通过alignment实现从页面底部弹出的菜单弹窗常用于分享、操作菜单。etsCustomDialog struct BottomMenuDialog { controller: CustomDialogController DialogParam menuClick: (index: number) void build() { Column() { List({ space: 1 }) { ListItem() { Text(分享好友) .width(100%) .height(50) .textAlign(TextAlign.Center) .fontSize(17) .onClick(() { this.menuClick(1) this.controller.close() }) } ListItem() { Text(收藏内容) .width(100%) .height(50) .textAlign(TextAlign.Center) .fontSize(17) .onClick(() { this.menuClick(2) this.controller.close() }) } ListItem() { Text(举报) .width(100%) .height(50) .textAlign(TextAlign.Center) .fontSize(17) .onClick(() { this.menuClick(3) this.controller.close() }) } } .width(100%) // 取消按钮 Button(取消) .width(100%) .height(50) .margin({ top: 10 }) .backgroundColor(Color.White) .onClick(() this.controller.close()) } .width(100%) .backgroundColor(#F5F5F5) } } Entry Component struct BottomDialogPage { State tip: string bottomDialog: CustomDialogController new CustomDialogController({ builder: BottomMenuDialog({ menuClick: (idx: number) { switch (idx) { case 1: this.tip 已选择分享好友 break case 2: this.tip 已选择收藏内容 break case 3: this.tip 已选择举报 break } } }), alignment: DialogAlignment.Bottom, // 弹窗底部对齐 autoCancel: true }) build() { Column({ space: 20 }) { Button(打开底部菜单弹窗) .width(220) .onClick(() this.bottomDialog.open()) Text(this.tip).fontSize(18) } .width(100%) .height(100%) .justifyContent(FlexAlign.Center) } }六、综合实战弹窗修改全局用户名联动 AppStorage结合之前的全局状态AppStorage实现弹窗修改用户名 → 全局数据同步刷新完整业务。ets// 自定义修改昵称弹窗 CustomDialog struct EditNameDialog { controller: CustomDialogController // 接收父页面传入的原始名称 DialogParam oldName: string DialogParam saveAction: (newName: string) void State tempName: string aboutToAppear() { // 弹窗打开时赋值初始值 this.tempName this.oldName } build() { Column({ space: 15 }) { Text(修改用户名).fontSize(20).fontWeight(FontWeight.Bold) TextInput({ text: this.tempName }) .width(100%) .height(45) .onChange(val this.tempName val) Row({ space: 20 }) { Button(取消) .layoutWeight(1) .onClick(() this.controller.close()) Button(保存) .layoutWeight(1) .backgroundColor(#007DFF) .onClick(() { this.saveAction(this.tempName) this.controller.close() }) } } .width(300) .padding(20) .backgroundColor(Color.White) .borderRadius(12) } } Entry Component struct UserInfoPage { // 双向绑定全局用户名 StorageLink(userName) userName: string editDialog: CustomDialogController new CustomDialogController({ builder: EditNameDialog({ oldName: this.userName, saveAction: (newName: string) { // 修改全局数据所有绑定页面自动刷新 this.userName newName } }) }) build() { Column({ space: 25 }) { Text(当前用户名 this.userName).fontSize(20) Button(点击修改用户名) .width(220) .onClick(() this.editDialog.open()) } .width(100%) .height(100%) .justifyContent(FlexAlign.Center) .padding(20) } }七、开发要点、踩坑与最佳实践7.1 核心使用规则装饰器区分CustomDialog仅用于定义弹窗不能作为独立页面Component普通组件 / 页面弹窗内部必须依赖controller.close()关闭无法直接路由关闭。外部传参、回调统一使用DialogParam不建议直接使用Prop。7.2 常用配置技巧居中弹窗默认无需设置alignment底部弹窗alignment: DialogAlignment.Bottom禁止点击遮罩关闭autoCancel: false表单、重要确认弹窗推荐开启自定义遮罩maskColor: rgba(0,0,0,0.6)7.3 常见问题解决弹窗多次创建报错控制器建议定义在组件顶层不要在onClick内部重复new。弹窗输入框数据不回显在弹窗aboutToAppear生命周期中接收初始值不要直接赋值。弹窗尺寸适配固定宽高适配小弹窗百分比宽高适配底部全屏菜单。7.4 项目规范按业务拆分弹窗提示弹窗、表单弹窗、菜单弹窗单独文件管理。重要操作弹窗退出账号、删除数据设置autoCancel: false防止误触。弹窗样式统一圆角、内边距、配色保持项目 UI 风格一致。