在鸿蒙(HarmonyOS)开发中,CustomDialog控制器(Controller) 是一个关键设计模式,用于实现对自定义弹窗的 精准控制状态管理。以下是其核心作用、实现原理与完整代码示例:


一、控制器的核心作用

1. 为什么需要控制器?
  • 解耦弹窗逻辑:将弹窗的显示/隐藏、数据绑定、事件处理等逻辑从页面主逻辑中抽离。
  • 状态管理:确保弹窗与父组件的状态同步(如避免弹窗关闭后父组件状态未更新)。
  • 复用性:同一控制器可管理多个弹窗实例或跨页面复用。
  • 复杂交互支持:处理多步骤弹窗、异步操作(如网络请求)的中间状态。
2. 无控制器的问题
  • 直接操作 @State 变量容易导致状态分散。
  • 弹窗事件(如确认/取消)需通过回调层层传递,代码臃肿。
  • 无法统一处理弹窗动画或生命周期。

二、控制器的实现方式

1. 基础版(基于 @State 变量)

适用场景:简单弹窗,仅需控制显示/隐藏。

// 页面组件中定义
@Entry
@Component
struct MyPage {
  @State isDialogVisible: boolean = false;

  build() {
    Column() {
      Button('打开弹窗')
        .onClick(() => { this.isDialogVisible = true; })
    }
    .customDialog(this.isDialogVisible, {
      builder: CustomDialogContent({ 
        onClose: () => { this.isDialogVisible = false; }
      }),
      alignment: DialogAlignment.Center
    })
  }
}

// 弹窗内容组件
@Component
struct CustomDialogContent {
  private onClose: () => void;

  build() {
    Column() {
      Text('这是一个基础弹窗')
      Button('关闭').onClick(() => this.onClose())
    }
  }
}

2. 高级版(封装独立控制器类)

适用场景:复杂弹窗,需要处理数据传递、异步操作、多状态。

// 定义控制器类
class DialogController {
  private isVisible: boolean = false;
  private data: object = {};
  private onConfirm?: (result: any) => void;

  // 打开弹窗并传入数据
  show(options: { data: object; onConfirm: (result: any) => void }) {
    this.isVisible = true;
    this.data = options.data;
    this.onConfirm = options.onConfirm;
  }

  // 关闭弹窗并返回结果
  close(result?: any) {
    this.isVisible = false;
    this.onConfirm?.(result);
  }

  // 绑定到组件
  bindComponent() {
    return {
      isVisible: this.isVisible,
      data: this.data,
      close: this.close.bind(this)
    };
  }
}

// 在页面中使用
@Entry
@Component
struct AdvancedPage {
  private dialogController = new DialogController();

  build() {
    Column() {
      Button('高级弹窗')
        .onClick(() => {
          this.dialogController.show({
            data: { title: '订单确认' },
            onConfirm: (result) => {
              console.log('用户确认:', result);
            }
          });
        })
    }
    .customDialog(this.dialogController.bindComponent().isVisible, {
      builder: AdvancedDialogContent(this.dialogController.bindComponent())
    })
  }
}

// 弹窗内容组件
@Component
struct AdvancedDialogContent {
  private controller: { data: object; close: (result?: any) => void };

  build() {
    Column() {
      Text(this.controller.data.title)
      Button('确认').onClick(() => this.controller.close({ status: 'confirmed' }))
      Button('取消').onClick(() => this.controller.close())
    }
  }
}

三、控制器的关键能力

1. 生命周期管理
class DialogController {
  // 弹窗打开时触发
  onDialogShow() {
    // 执行动画/加载数据
  }

  // 弹窗关闭时触发
  onDialogDismiss() {
    // 释放资源/保存状态
  }
}
2. 数据双向绑定
// 控制器中定义响应式数据
@Observed
class DialogData {
  @Tracked inputValue: string = '';
}

// 在弹窗内容组件中同步
@Component
struct DialogForm {
  @ObjectLink data: DialogData;

  build() {
    TextInput({ text: this.data.inputValue })
      .onChange((value) => { this.data.inputValue = value; })
  }
}
3. 异步操作处理
// 控制器中处理提交
submitForm() {
  showLoading(); // 显示加载状态
  fetch('/api/submit', { data: this.data })
    .then(() => this.close({ success: true }))
    .catch(() => showErrorToast('提交失败'))
    .finally(() => hideLoading());
}

四、最佳实践

1. 多弹窗管理
class MultiDialogManager {
  private controllers: Map<string, DialogController> = new Map();

  register(name: string, controller: DialogController) {
    this.controllers.set(name, controller);
  }

  get(name: string) {
    return this.controllers.get(name);
  }
}

// 在应用初始化时注册
const dialogManager = new MultiDialogManager();
dialogManager.register('login', new DialogController());
dialogManager.register('payment', new DialogController());
2. 动画控制
@Component
struct AnimatedDialog {
  @State private scale: number = 0.5;

  build() {
    Column()
      .scale({ x: this.scale, y: this.scale })
      .onAppear(() => {
        animateTo({ duration: 300 }, () => {
          this.scale = 1;
        });
      })
  }
}
3. 与路由结合
// 页面跳转时自动关闭弹窗
router.pushUrl({ url: 'pages/NextPage' })
  .then(() => this.dialogController.close());

五、总结

通过控制器模式,开发者可以:

  1. 将弹窗的 业务逻辑视图逻辑 解耦
  2. 实现弹窗的 统一状态管理复用
  3. 处理复杂的 异步交互数据流

在以下场景必须使用控制器:

  • 弹窗需要与多个组件交互时
  • 弹窗内部有复杂的状态转换
  • 需要跨页面复用弹窗逻辑
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐