HarmonyOS 弹框开发实战【3】

2025-06-25 23:07:25
158次阅读
0个评论

第三篇:弹框管理的最佳实践

做项目时间长了就会发现,弹框多了管理起来真的很麻烦。特别是大一点的项目,各种弹框满天飞,有时候会出现弹框叠弹框的情况,用户体验特别差。所以我后来专门写了个弹框管理器来统一处理这些问题。

弹框管理器的核心思想就是把所有弹框的创建和显示都统一管理起来。我用的是单例模式,保证全局只有一个管理器实例。这样做的好处是可以控制弹框的显示顺序,避免同时出现多个弹框。

队列管理是个重点。实际开发中经常会遇到这种情况:网络请求失败了要弹错误提示,同时用户又点击了删除按钮要弹确认框。如果两个弹框同时出现,界面就乱了。我的做法是给弹框设置优先级,错误提示的优先级高于普通确认框,这样错误提示会先显示,用户处理完了再显示确认框。

弹框的生命周期管理也很重要。每个弹框从创建到销毁都要做好资源管理,特别是自定义弹框,里面可能有定时器、监听器等资源,关闭时一定要记得清理,不然容易内存泄漏。我之前就因为忘记清理定时器导致应用越用越卡。

样式一致性这个问题在大项目中特别明显。不同模块的开发者写的弹框样式不一样,用户用起来会觉得很奇怪。我的做法是定义一套弹框主题,包括颜色、字体、间距等,所有弹框都要遵循这个主题。这样整个应用的弹框风格就统一了。

性能优化方面,我主要关注两点:一是避免频繁创建销毁弹框,二是控制弹框的复杂度。对于一些常用的弹框,我会做成池化管理,预先创建几个实例,用的时候直接取,用完了回收。这样比每次都重新创建要快很多。

// 简化的弹框管理器
class DialogManager {
  private static instance: DialogManager
  private dialogQueue: DialogConfig[] = []
  private currentDialog: CustomDialogController | null = null
  private isProcessing: boolean = false
  private uiContext: UIContext | null = null

  static getInstance(): DialogManager {
    if (!DialogManager.instance) {
      DialogManager.instance = new DialogManager()
    }
    return DialogManager.instance
  }

  // 设置UIContext,在页面中调用
  setUIContext(context: UIContext) {
    this.uiContext = context
  }

  private getUIContext(): UIContext {
    if (!this.uiContext) {
      throw new Error('UIContext未设置,请先调用setUIContext')
    }
    return this.uiContext
  }

  // 显示弹框
  showDialog(config: DialogConfig): string {
    const dialogId = `dialog_${Date.now()}_${Math.random()}`
    config.id = dialogId
    
    // 根据优先级插入队列
    if (config.priority === 'high') {
      this.dialogQueue.unshift(config)
    } else {
      this.dialogQueue.push(config)
    }
    
    // 处理队列
    this.processQueue()
    return dialogId
  }

  private processQueue() {
    // 如果正在显示弹框或队列为空,直接返回
    if (this.isProcessing || this.currentDialog || this.dialogQueue.length === 0) {
      return
    }
    
    this.isProcessing = true
    const config = this.dialogQueue.shift()!
    
    // 创建并显示弹框
    this.createAndShowDialog(config)
  }

  private createAndShowDialog(config: DialogConfig) {
    // 根据配置创建对应的弹框
    if (config.type === 'alert') {
      // 使用UIContext显示系统弹框
      this.getUIContext().showAlertDialog({
        title: config.title,
        message: config.content,
        autoCancel: config.autoCancel !== false,
        alignment: config.alignment || DialogAlignment.Center
      })
    } else {
      // 自定义弹框使用CustomDialogController
      const controller = new CustomDialogController({
        builder: config.builder,
        alignment: config.alignment || DialogAlignment.Center,
        autoCancel: config.autoCancel !== false
      })
      
      this.currentDialog = controller
      controller.open()
    }
    
    // 监听弹框关闭事件
    this.setupDialogCloseHandler(config.id!)
  }

  private setupDialogCloseHandler(dialogId: string) {
    // 实际项目中这里会设置弹框关闭的回调
    // 弹框关闭后继续处理队列
    setTimeout(() => {
      this.currentDialog = null
      this.isProcessing = false
      this.processQueue() // 处理下一个弹框
    }, 100)
  }
}

interface DialogConfig {
  id?: string
  type: 'alert' | 'confirm' | 'input' | 'loading'
  priority?: 'high' | 'normal'
  title?: string
  content?: string
  builder?: CustomBuilder
  alignment?: DialogAlignment
  autoCancel?: boolean
}

可访问性这个话题可能很多人不太关注,但其实挺重要的。特别是做面向大众的应用,要考虑视力障碍用户的使用需求。弹框的文本要有合适的语义标签,按钮要有明确的描述,支持键盘导航等。虽然工作量会增加一些,但能让更多人使用你的应用,还是很有意义的。

测试策略方面,弹框的测试确实比较麻烦,特别是涉及用户交互的部分。我一般会写一些集成测试,模拟用户的点击操作,验证弹框的显示和数据传递是否正确。对于复杂的弹框逻辑,还会写一些端到端测试,确保整个流程没问题。

最后总结几个实用的经验:弹框内容要简洁明了,不要让用户思考太多;重要操作一定要有确认步骤,避免误操作;弹框的样式要与应用整体风格保持一致;性能优化要适度,不要过度工程化;测试要充分,特别是异常情况的处理。

做了这么久开发,我觉得弹框虽然看起来简单,但要做好真的不容易。希望我的这些经验能帮到大家,少踩一些坑。

收藏00

登录 后评论。没有帐号? 注册 一个。