[鸿蒙2025领航者闯关] 自定义Dialog对话框封装与复用
应用中需要频繁使用确认对话框、选择器对话框等,如何封装通用的 Dialog 组件避免重复代码?如何实现优雅的回调处理?: CustomDialog、对话框封装、组件复用、回调处理、UI 组件。
·
问题描述
应用中需要频繁使用确认对话框、选择器对话框等,如何封装通用的 Dialog 组件避免重复代码?如何实现优雅的回调处理?
关键字: CustomDialog、对话框封装、组件复用、回调处理、UI 组件
解决方案
完整代码
/**
* 确认对话框
*/
@CustomDialog
export struct ConfirmDialog {
controller: CustomDialogController;
title: string = '提示';
message: string = '';
confirmText: string = '确定';
cancelText: string = '取消';
onConfirm?: () => void;
onCancel?: () => void;
build() {
Column({ space: 16 }) {
// 标题
Text(this.title)
.fontSize(18)
.fontWeight(FontWeight.Bold)
.width('100%')
// 消息内容
Text(this.message)
.fontSize(14)
.fontColor('#666')
.width('100%')
.margin({ top: 8, bottom: 16 })
// 按钮组
Row({ space: 12 }) {
Button(this.cancelText)
.fontSize(16)
.backgroundColor('#f5f5f5')
.fontColor('#333')
.layoutWeight(1)
.onClick(() => {
this.controller.close();
if (this.onCancel) {
this.onCancel();
}
})
Button(this.confirmText)
.fontSize(16)
.backgroundColor('#ff6b6b')
.fontColor('#fff')
.layoutWeight(1)
.onClick(() => {
this.controller.close();
if (this.onConfirm) {
this.onConfirm();
}
})
}
.width('100%')
}
.padding(20)
.backgroundColor(Color.White)
.borderRadius(12)
}
}
/**
* 单选对话框
*/
@CustomDialog
export struct SelectDialog {
controller: CustomDialogController;
title: string = '请选择';
options: string[] = [];
selectedIndex: number = 0;
onSelect?: (index: number, value: string) => void;
@State currentIndex: number = 0;
aboutToAppear() {
this.currentIndex = this.selectedIndex;
}
build() {
Column({ space: 12 }) {
// 标题
Text(this.title)
.fontSize(18)
.fontWeight(FontWeight.Bold)
.width('100%')
.padding({ bottom: 12 })
// 选项列表
List({ space: 0 }) {
ForEach(this.options, (option: string, index: number) => {
ListItem() {
Row() {
Text(option)
.fontSize(16)
.fontColor(this.currentIndex === index ? '#ff6b6b' : '#333')
.layoutWeight(1)
if (this.currentIndex === index) {
Text('✓')
.fontSize(18)
.fontColor('#ff6b6b')
}
}
.width('100%')
.padding(12)
.backgroundColor(this.currentIndex === index ? '#fff5f5' : Color.White)
.borderRadius(8)
.onClick(() => {
this.currentIndex = index;
})
}
})
}
.height(Math.min(this.options.length * 48, 300))
// 确定按钮
Button('确定')
.width('100%')
.backgroundColor('#ff6b6b')
.fontColor('#fff')
.margin({ top: 12 })
.onClick(() => {
this.controller.close();
if (this.onSelect) {
this.onSelect(this.currentIndex, this.options[this.currentIndex]);
}
})
}
.padding(20)
.backgroundColor(Color.White)
.borderRadius(12)
.width('80%')
}
}
/**
* 输入对话框
*/
@CustomDialog
export struct InputDialog {
controller: CustomDialogController;
title: string = '输入';
placeholder: string = '请输入';
defaultValue: string = '';
inputType: InputType = InputType.Normal;
maxLength: number = 50;
onConfirm?: (value: string) => void;
@State inputValue: string = '';
aboutToAppear() {
this.inputValue = this.defaultValue;
}
build() {
Column({ space: 16 }) {
// 标题
Text(this.title)
.fontSize(18)
.fontWeight(FontWeight.Bold)
.width('100%')
// 输入框
TextInput({ text: this.inputValue, placeholder: this.placeholder })
.type(this.inputType)
.maxLength(this.maxLength)
.onChange((value: string) => {
this.inputValue = value;
})
.width('100%')
.padding(12)
.borderRadius(8)
.backgroundColor('#f5f5f5')
// 按钮组
Row({ space: 12 }) {
Button('取消')
.fontSize(16)
.backgroundColor('#f5f5f5')
.fontColor('#333')
.layoutWeight(1)
.onClick(() => {
this.controller.close();
})
Button('确定')
.fontSize(16)
.backgroundColor('#ff6b6b')
.fontColor('#fff')
.layoutWeight(1)
.onClick(() => {
this.controller.close();
if (this.onConfirm) {
this.onConfirm(this.inputValue);
}
})
}
.width('100%')
}
.padding(20)
.backgroundColor(Color.White)
.borderRadius(12)
}
}
/**
* 加载对话框
*/
@CustomDialog
export struct LoadingDialog {
controller: CustomDialogController;
message: string = '加载中...';
build() {
Column({ space: 16 }) {
LoadingProgress()
.width(50)
.height(50)
.color('#ff6b6b')
Text(this.message)
.fontSize(14)
.fontColor('#666')
}
.padding(30)
.backgroundColor(Color.White)
.borderRadius(12)
}
}
使用示例
@Entry
@Component
struct DemoPage {
private confirmDialogController: CustomDialogController | null = null;
private selectDialogController: CustomDialogController | null = null;
private inputDialogController: CustomDialogController | null = null;
private loadingDialogController: CustomDialogController | null = null;
// 显示确认对话框
showConfirmDialog() {
this.confirmDialogController = new CustomDialogController({
builder: ConfirmDialog({
title: '删除确认',
message: '确定要删除这条记录吗?此操作不可恢复。',
confirmText: '删除',
cancelText: '取消',
onConfirm: () => {
console.log('用户点击了删除');
this.deleteRecord();
},
onCancel: () => {
console.log('用户取消了删除');
}
}),
autoCancel: true,
alignment: DialogAlignment.Center
});
this.confirmDialogController.open();
}
// 显示选择对话框
showSelectDialog() {
this.selectDialogController = new CustomDialogController({
builder: SelectDialog({
title: '选择关系',
options: ['朋友', '同事', '亲戚', '同学', '其他'],
selectedIndex: 0,
onSelect: (index: number, value: string) => {
console.log(`选择了: ${value}`);
}
}),
autoCancel: true,
alignment: DialogAlignment.Center
});
this.selectDialogController.open();
}
// 显示输入对话框
showInputDialog() {
this.inputDialogController = new CustomDialogController({
builder: InputDialog({
title: '添加备注',
placeholder: '请输入备注内容',
defaultValue: '',
maxLength: 100,
onConfirm: (value: string) => {
console.log(`输入内容: ${value}`);
}
}),
autoCancel: true,
alignment: DialogAlignment.Center
});
this.inputDialogController.open();
}
// 显示加载对话框
async showLoadingDialog() {
this.loadingDialogController = new CustomDialogController({
builder: LoadingDialog({
message: '正在保存...'
}),
autoCancel: false,
alignment: DialogAlignment.Center
});
this.loadingDialogController.open();
// 模拟异步操作
await this.saveData();
// 关闭加载对话框
this.loadingDialogController.close();
}
async deleteRecord() {
// 删除逻辑
}
async saveData() {
// 保存逻辑
}
build() {
Column({ space: 16 }) {
Button('确认对话框').onClick(() => this.showConfirmDialog())
Button('选择对话框').onClick(() => this.showSelectDialog())
Button('输入对话框').onClick(() => this.showInputDialog())
Button('加载对话框').onClick(() => this.showLoadingDialog())
}
.padding(20)
}
}
原理解析
1. @CustomDialog 装饰器
@CustomDialog
export struct ConfirmDialog {
controller: CustomDialogController;
}
- 标记为自定义对话框组件
- 必须包含 controller 属性
- 通过 controller 控制显示/隐藏
2. 回调函数传递
onConfirm?: () => void;
- 使用可选属性定义回调
- 调用前检查是否存在
- 支持传递参数
3. @State 状态管理
@State currentIndex: number = 0;
- 对话框内部状态
- 响应用户交互
- 触发 UI 更新
最佳实践
- 统一风格: 所有对话框使用相同的样式和动画
- 回调处理: 使用可选回调,调用前检查
- 自动关闭: 设置 autoCancel: true 支持点击外部关闭
- 内存管理: 对话框关闭后 controller 置 null
- 异步操作: 加载对话框配合 async/await 使用
避坑指南
- 忘记 close: 必须手动调用 controller.close()
- 重复打开: 打开前检查 controller 是否已存在
- 内存泄漏: 组件销毁时关闭所有对话框
- 回调丢失: 箭头函数保持 this 指向
- 样式覆盖: 使用 width/height 限制对话框大小
效果展示
- 确认对话框:标题 + 消息 + 双按钮
- 选择对话框:标题 + 列表 + 确定按钮
- 输入对话框:标题 + 输入框 + 双按钮
- 加载对话框:加载动画 + 提示文字
相关资源
更多推荐


所有评论(0)