尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

鸿蒙应用开发实战【17】— bindPopup 气泡弹出与筛选面板实现

鸿蒙应用开发实战【17】— bindPopup 气泡弹出与筛选面板实现
📅 发布时间:2026/7/15 16:44:31

鸿蒙应用开发实战【17】— bindPopup 气泡弹出与筛选面板实现

前言

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

号码助手首页有一个「全部/已选N ⌄」筛选按钮,点击后会弹出一个气泡面板,展示分类、卡号、状态三维筛选条件。这个功能使用 ArkUI 的bindPopup实现——它能将一个自定义的@Builder内容以气泡形式浮层显示在触发元素附近,不会遮挡整个屏幕。

本篇涵盖:bindPopup 基本用法、PopupOptions 参数详解、Placement 弹出位置、自定义 @Builder builder 内容、onStateChange 状态回调、Flex + FlexWrap 实现 chip 布局、三维筛选系统完整实现。


一、bindPopup 组件预览

图1:bindPopup 锚点定位原理 + Placement 九宫格方位枚举


二、bindPopup 概述

2.1 bindPopup vs bindSheet 的选择

特性bindPopupbindSheet
显示位置触发元素附近(气泡)屏幕底部
遮挡内容部分遮挡(小区域)遮挡大部分屏幕
适合内容少量选项(筛选、快捷操作)大量内容(列表选择)
关闭方式点击外部自动关闭下滑或点击完成关闭
号码助手使用首页筛选面板AddAppPage 卡号选择

2.2 基本语法

// 绑定在触发元素上Button('筛选').bindPopup(this.showPopup,{builder:this.PopupContent,// @Builder 方法placement:Placement.Bottom,// 弹出位置popupColor:'#FFFFFF',// 气泡背景色onStateChange:(e)=>{if(!e.isVisible){this.showPopup=false}}}).onClick(()=>{this.showPopup=!this.showPopup})

三、bindPopup 参数详解

3.1 完整参数

interfacePopupOptions{builder?:CustomBuilder// 自定义内容(@Builder 方法)placement?:Placement// 弹出方向popupColor?:ResourceColor// 气泡背景色autoCancel?:boolean// 点击外部是否自动关闭(默认 true)offset?:{x:number,y:number}// 弹出偏移onStateChange?:(e:{isVisible:boolean})=>void// 状态变化回调arrowOffset?:number// 箭头偏移showInSubWindow?:boolean// 是否在子窗口显示maskColor?:ResourceColor// 遮罩颜色enableArrow?:boolean// 是否显示箭头(默认 true)}

3.2 Placement 弹出位置

// 可用的 Placement 枚举值Placement.Top// 触发元素上方Placement.Bottom// 触发元素下方(号码助手使用)✅Placement.Left// 触发元素左侧Placement.Right// 触发元素右侧Placement.TopLeft// 上方偏左Placement.TopRight// 上方偏右Placement.BottomLeft// 下方偏左Placement.BottomRight// 下方偏右// ❌ 注意:Placement.BottomEnd 不存在!// 正确使用 Placement.Bottom + 通过 offset 微调位置

四、首页筛选面板完整实现

4.1 触发按钮

// HomePage.ets — 筛选按钮Row({space:3}){Text(this.activeFilterCount()>0?`已选${this.activeFilterCount()}`:'全部').fontSize(12).fontWeight(AppFonts.WEIGHT_SEMIBOLD).fontColor(this.activeFilterCount()>0?'#3E68E0':AppColors.TEXT_2)Text('⌄').fontSize(10).fontColor(this.activeFilterCount()>0?'#3E68E0':AppColors.TEXT_3)}.padding({left:11,right:11,top:6,bottom:6}).backgroundColor(this.activeFilterCount()>0?AppColors.PRIMARY_BG:AppColors.CARD_B).border({width:1,color:this.activeFilterCount()>0?'#4D4F7CFF':AppColors.LINE,radius:14})// ← bindPopup 绑定.bindPopup(this.showFilter,{builder:this.FilterPopoverBuilder,placement:Placement.Bottom,popupColor:'#FFFFFF',onStateChange:(e)=>{if(!e.isVisible){this.showFilter=false}// 点外部关闭时同步状态}}).onClick(()=>{this.showFilter=!this.showFilter})

4.2 @Builder 筛选面板内容

@BuilderprivateFilterPopoverBuilder(){Column(){// ── 分类筛选 ──Column(){Text('分类').fontSize(11).fontColor(AppColors.TEXT_3).fontWeight(AppFonts.WEIGHT_SEMIBOLD).alignSelf(ItemAlign.Start).margin({bottom:8})Flex({wrap:FlexWrap.Wrap}){ForEach(CATEGORIES,(cat:string,idx:number)=>{Text(cat).fontSize(12).fontWeight(AppFonts.WEIGHT_MEDIUM).fontColor(this.filterCatIdx===idx?'#FFFFFF':AppColors.TEXT_2).padding({left:12,right:12,top:6,bottom:6}).backgroundColor(this.filterCatIdx===idx?AppColors.PRIMARY:AppColors.CARD_B).border({width:1,color:this.filterCatIdx===idx?'#00000000':AppColors.LINE,radius:14}).margin({right:6,bottom:6}).onClick(()=>{this.filterCatIdx=idx})},(cat:string)=>cat)}}.margin({bottom:14}).alignItems(HorizontalAlign.Start)// ── 卡号筛选 ──Column(){Text('卡号').fontSize(11).fontColor(AppColors.TEXT_3).fontWeight(AppFonts.WEIGHT_SEMIBOLD).alignSelf(ItemAlign.Start).margin({bottom:8})Flex({wrap:FlexWrap.Wrap}){// 「全部」选项Text('全部').fontSize(12).fontWeight(AppFonts.WEIGHT_MEDIUM).fontColor(this.filterCardIdx===0?'#FFFFFF':AppColors.TEXT_2).padding({left:12,right:12,top:6,bottom:6}).backgroundColor(this.filterCardIdx===0?AppColors.PRIMARY:AppColors.CARD_B).border({width:1,color:this.filterCardIdx===0?'#00000000':AppColors.LINE,radius:14}).margin({right:6,bottom:6}).onClick(()=>{this.filterCardIdx=0})// 各卡号选项ForEach(this.cards,(card:CardEntity,idx:number)=>{Text(card.label).fontSize(12).fontWeight(AppFonts.WEIGHT_MEDIUM).fontColor(this.filterCardIdx===idx+1?'#FFFFFF':AppColors.TEXT_2).padding({left:12,right:12,top:6,bottom:6}).backgroundColor(this.filterCardIdx===idx+1?AppColors.PRIMARY:AppColors.CARD_B).border({width:1,color:this.filterCardIdx===idx+1?'#00000000':AppColors.LINE,radius:14}).margin({right:6,bottom:6}).onClick(()=>{this.filterCardIdx=idx+1})},(card:CardEntity)=>`fc_${card.id??0}`)}}.margin({bottom:14}).alignItems(HorizontalAlign.Start)// ── 状态筛选 ──Column(){Text('状态').fontSize(11).fontColor(AppColors.TEXT_3).fontWeight(AppFonts.WEIGHT_SEMIBOLD).alignSelf(ItemAlign.Start).margin({bottom:8})Flex({wrap:FlexWrap.Wrap}){ForEach(STATUS_FILTERS,(s:string,idx:number)=>{Text(s).fontSize(12).fontWeight(AppFonts.WEIGHT_MEDIUM).fontColor(this.filterStatIdx===idx?'#FFFFFF':AppColors.TEXT_2).padding({left:12,right:12,top:6,bottom:6}).backgroundColor(this.filterStatIdx===idx?AppColors.PRIMARY:AppColors.CARD_B).border({width:1,color:this.filterStatIdx===idx?'#00000000':AppColors.LINE,radius:14}).margin({right:6,bottom:6}).onClick(()=>{this.filterStatIdx=idx})},(s:string)=>s)}}.margin({bottom:12}).alignItems(HorizontalAlign.Start)// ── 底部按钮 ──Row({space:8}){Button('重置',{type:ButtonType.Normal}).layoutWeight(1).height(36).fontSize(12).fontColor(AppColors.TEXT).backgroundColor(AppColors.CARD_B).border({width:1,color:AppColors.LINE,radius:10}).onClick(()=>this.resetFilters())Button('完成',{type:ButtonType.Normal}).layoutWeight(1).height(36).fontSize(12).fontColor('#FFFFFF').borderRadius(10).linearGradient({angle:135,colors:[[AppColors.PRIMARY,0],[AppColors.PRIMARY_2,1]]}).backgroundColor(Color.Transparent).onClick(()=>{this.showFilter=false})}}.width(220).padding(14)}

五、Flex + FlexWrap 实现 Chip 布局

5.1 FlexWrap 自动换行

// Chip 标签自动换行布局(筛选选项数量不固定时很有用)Flex({wrap:FlexWrap.Wrap}){Text('分类1').margin({right:6,bottom:6})Text('分类2').margin({right:6,bottom:6})Text('分类3').margin({right:6,bottom:6})// 超过一行时自动换行}// 关键参数:// FlexWrap.Wrap:允许换行(默认 NoWrap 不换行)// margin.right:chip 之间的水平间距// margin.bottom:行与行之间的垂直间距

5.2 与 Row 的区别

// Row:固定单行,不自动换行(内容超出时裁剪)Row({space:6}){Text('分类1')Text('分类2')Text('分类3')}// Flex + wrap:多行自动换行(适合数量不固定的标签)Flex({wrap:FlexWrap.Wrap}){Text('分类1').margin(...)Text('分类2').margin(...)Text('分类3').margin(...)}

六、筛选状态管理

6.1 筛选条件计数

privateactiveFilterCount():number{letn=0if(this.filterCatIdx!==0)n++// 非「全部」时 +1if(this.filterCardIdx!==0)n++if(this.filterStatIdx!==0)n++returnn}

6.2 筛选重置

privateresetFilters():void{this.filterCatIdx=0this.filterCardIdx=0this.filterStatIdx=0this.showFilter=false// 重置后关闭面板}

6.3 三维过滤逻辑

privategetFilteredRows():AppRow[]{returnthis.rows.filter((r:AppRow)=>{constcatOk=this.filterCatIdx===0||r.binding.category===CATEGORIES[this.filterCatIdx]constcardOk=this.filterCardIdx===0||r.cardLabel===this.cards[this.filterCardIdx-1]?.labelconststatOk=this.filterStatIdx===0||r.binding.status===STATUS_FILTERS[this.filterStatIdx]returncatOk&&cardOk&&statOk})}

七、本篇小结

知识点核心要点
bindPopup气泡弹出,适合小型筛选面板
Placement.Bottom在触发元素下方弹出
onStateChange点击外部关闭时同步 @State
Flex + FlexWrap.Wrap标签自动换行(chip 布局)
筛选三维度分类/卡号/状态独立过滤,AND 关系

参考资料

  • 鸿蒙应用开发实战【05】— 首页开发与状态管理
  • 鸿蒙应用开发实战【16】— bindSheet 底部弹出面板
  • bindPopup API 参考
  • Placement 枚举
  • Flex 容器
  • FlexWrap 说明
  • @Builder 装饰器
  • Button 组件

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


相关资源:

  • 开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
  • bindPopup 文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-universal-attributes-popup
  • Flex 容器文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-flex

相关新闻

  • OpenMTP终极指南:如何在macOS上实现快速免费的Android文件传输
  • 重测序基因组:Pi核酸多样性在群体遗传选择分析中的应用
  • 2026年低延迟Agent数据库哪家专业:实时查询引擎、数据新鲜度与AI场景适配深度解析 - 科技焦点

最新新闻

  • Jido区块链集成:智能合约与去中心化代理的终极指南
  • KUKA机器人奇异点:从原理到现场调试的实战解析
  • 猫抓浏览器扩展:网页媒体资源嗅探与智能下载解决方案
  • 从零开始:使用openEuler OpenStack SIG工具创建RPM软件仓的完整指南
  • TensorFlow 2深度实践:从tf.function到SavedModel的工业级训练闭环
  • 警惕AI领域虚构技术名词与过度优化陷阱

日新闻

  • 告别启动盘残留:用Diskpart彻底清除U盘EFI分区与恢复完整空间
  • 2026 年宜春诚信的塑料缠绕膜厂家哪个好,缠绕膜背后的秘密:你不知道的成本陷阱 - 领域鉴赏官
  • Arch ECS 入门指南:10分钟掌握C#高性能数据驱动架构

周新闻

  • IX9104 PCIe5.0 高速交换芯片@ACP#完整规格 + 应用场景总结
  • Unity游戏集成Coze智能体:实现NPC智能对话与知识库联动
  • SAP EPIC 建行回单查询:从标准类CL_EPIC_EXAMPLE_CN_CCB_GHTD到Z类的5处关键修改

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号