一张手绘笔记风的信息图,主题是 HarmonyOS7 浮层入门:PopupStarterGuide。

前言

如果说弹窗更像“暂停当前流程”,那 Popup 更像“贴着某个组件冒出来的一小块信息层”。它不会像对话框那样把页面整体打断,而是围绕触发源做局部信息补充,因此特别适合说明、辅助、悬浮菜单和快速提示。

这个案例是学习 Popup 的第一步。它同时演示了基础浮层和带箭头浮层,帮助你理解 bindPopup() 的核心用法。

一张手绘笔记风流程图,内容来自 HarmonyOS7 PopupStarterGuide 示例。流程

页面效果

页面中有两个按钮:

  • 显示基础 Popup
  • 显示带箭头 Popup

点击按钮后,会在按钮周边弹出一块轻量信息层。关闭时又会通过状态回调把显示状态同步回页面。

完整代码

一张手绘笔记风框架图,解释 HarmonyOS7 PopupStarterGuide 中 Popup

import { DEMO_CARD_COLOR, DEMO_THEME_COLOR } from './types'

@Entry
@Component
struct PopupStarterGuide {
  @State isShow: boolean = true
  @State showPopup: boolean = false
  @State handlePopup: boolean = false

  build() {
    Column() {
      if (this.isShow) {
        Column() {
          Text('Popup 基础演示')
            .fontSize(16)
            .fontWeight(FontWeight.Bold)
            .margin({ bottom: 16 })

          Text('Popup 是一种轻量级浮层,可绑定到任意组件,点击或悬停时显示自定义内容。')
            .fontSize(14)
            .fontColor('#666666')
            .margin({ bottom: 24 })

          Row() {
            Button('显示 Popup')
              .width('45%')
              .height(48)
              .backgroundColor(DEMO_THEME_COLOR)
              .borderRadius(12)
              .fontColor('#FFFFFF')
              .fontSize(15)
              .bindPopup(this.showPopup, {
                builder: this.popupBuilder,
                placement: Placement.Bottom,
                enableArrow: true,
                onStateChange: (e) => {
                  if (!e.isVisible) {
                    this.showPopup = false
                  }
                }
              })
              .onClick(() => {
                this.showPopup = !this.showPopup
              })

            Button('带箭头 Popup')
              .width('45%')
              .height(48)
              .backgroundColor('#4ECDC4')
              .borderRadius(12)
              .fontColor('#FFFFFF')
              .fontSize(15)
              .bindPopup(this.handlePopup, {
                builder: this.arrowPopupBuilder,
                placement: Placement.Top,
                enableArrow: true,
                onStateChange: (e) => {
                  if (!e.isVisible) {
                    this.handlePopup = false
                  }
                }
              })
              .onClick(() => {
                this.handlePopup = !this.handlePopup
              })
          }
          .width('100%')
          .justifyContent(FlexAlign.SpaceBetween)
        }
        .width('100%')
        .padding(24)
        .backgroundColor(DEMO_CARD_COLOR)
        .borderRadius(12)
      }
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F6FA')
    .padding(16)
  }

  @Builder
  popupBuilder() {
    Column() {
      Text('这是一个 Popup')
        .fontSize(14)
        .fontColor('#333333')
        .margin({ bottom: 8 })
      Text('可以展示任意内容')
        .fontSize(12)
        .fontColor('#999999')
    }
    .padding(16)
    .backgroundColor('#FFFFFF')
    .borderRadius(12)
    .shadow({ radius: 12, color: '#00000015' })
  }

  @Builder
  arrowPopupBuilder() {
    Column() {
      Text('带箭头的 Popup')
        .fontSize(14)
        .fontColor('#333333')
        .margin({ bottom: 6 })
      Text('箭头指向触发组件')
        .fontSize(12)
        .fontColor('#999999')
    }
    .padding(16)
    .backgroundColor('#FFFFFF')
    .borderRadius(12)
    .shadow({ radius: 12, color: '#00000015' })
  }
}

关键代码讲解

1. bindPopup() 是 Popup 的绑定入口

和对话框不同,Popup 不是独立弹出来的,而是直接绑定在某个组件上。

.bindPopup(this.showPopup, {
  builder: this.popupBuilder,
  placement: Placement.Bottom,
  enableArrow: true
})

这里有三个重点:

  • 第一个参数是显示状态
  • builder 决定浮层内容
  • placement 决定弹出方向

这意味着 Popup 的位置和内容都天然依附于触发组件。

2. @Builder 负责浮层内容本身

案例中定义了两个 Builder:

  • popupBuilder():基础说明内容
  • arrowPopupBuilder():带箭头说明内容

这是一种很典型的写法。以后你完全可以把 Builder 换成头像卡片、操作菜单、帮助说明甚至小型表单。

3. onStateChange 用来同步关闭状态

很多人第一次写 Popup,会发现点击外部关闭后,状态变量没有跟着变。这个案例专门补上了:

onStateChange: (e) => {
  if (!e.isVisible) {
    this.showPopup = false
  }
}

这一步非常重要。否则页面逻辑以为 Popup 还开着,但界面实际上已经关闭,状态就会不一致。

适合的业务场景

Popup 很适合做这些事情:

  • 悬浮帮助说明
  • 按钮附近的操作菜单
  • 信息补充卡片
  • 轻量级上下文提示

如果内容很多、需要用户中断当前流程,还是应该回到 Dialog,而不是硬把复杂交互塞进 Popup。

总结

这个案例帮你建立了 Popup 的基本认知:它是一个依附于触发组件的轻量浮层,而不是全局弹窗。理解这一点后,你再去做位置控制、自定义内容和交互型浮层时,会顺很多。

Logo

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

更多推荐