当前位置: 首页 > news >正文

HarmonyOS7 消息徽标展示页实战:Badge 不只是会用,还要用得顺手

文章目录

      • Badge 不是贴上去就完事
      • 清除徽标要清完整状态
      • 三种徽标场景怎么选
      • 页面结构怎么看
      • 完整代码
      • 写在最后

Badge 最常见的误用,是把它当成一个红点装饰。实际做消息页、应用入口、Tab 栏时,它表达的是“还有东西没处理”。这个状态如果和真实数据脱节,用户点进去发现什么都没有,体验会很糟。

这篇用 HarmonyOS7 的 Badge 做了三个场景:应用图标未读数、徽标位置对比、Tab 栏消息提醒。它不复杂,但很适合拿来练状态同步。

Badge 不是贴上去就完事

页面里定义了AppInfoTabItem。前者记录应用图标、背景色、未读数、更新状态和圆点状态;后者负责 Tab 栏里的标题、图标和徽标数字。

这种数据结构比直接在 UI 里写死数字好很多。未读数来自接口也好,来自本地缓存也好,最后都能落到同一个字段上,Badge 只负责展示。

清除徽标要清完整状态

clearBadge()是这篇的关键。点击某个应用后,它会把对应应用的msgCounthasUpdatehasDot一起清掉,而不是只把数字改成 0。

clearBadge(appId:number){this.apps=this.apps.map((app:AppInfo)=>{if(app.id===appId){return{id:app.id,name:app.name,icon:app.icon,bgColor:app.bgColor,msgCount:0,hasUpdate:false,hasDot:false}}returnapp})}

这点很贴近真实业务。一个入口可能同时有未读消息、版本更新、小红点提醒,如果只清其中一个,页面就会出现“数字没了但红点还在”的尴尬状态。

三种徽标场景怎么选

数字徽标适合明确数量,比如未读消息、待处理订单;圆点徽标适合弱提醒,比如有新内容但数量不重要;Tab 徽标适合告诉用户某个栏目里有待处理内容。

别所有地方都用数字。超过一定数量后,用户其实不关心精确值,显示99+或一个红点往往更清爽。

页面结构怎么看

BadgeMessagePage主要看两块状态:apps控制应用图标区,tabsselectedTab控制底部 Tab。读代码时可以先看数据数组,再看 Badge 包裹了哪个组件,最后看点击事件如何更新状态。

如果你要把这个案例放进项目,我建议把清除逻辑接到真实阅读状态上。Badge 的展示可以很轻,但背后的状态一定要准。

完整代码

下面是完整代码。入口组件名是BadgeMessagePage,可以直接作为消息入口或 Tab 徽标的参考实现。

// Badge 徽标组件全解析interfaceAppInfo{id:numbername:stringicon:stringbgColor:stringmsgCount:numberhasUpdate:booleanhasDot:boolean}interfaceTabItem{label:stringicon:stringbadgeCount:number}@Entry@Componentstruct BadgeMessagePage{@Stateapps:AppInfo[]=[{id:1,name:'消息',icon:'💬',bgColor:'#2563EB',msgCount:99,hasUpdate:false,hasDot:false},{id:2,name:'邮件',icon:'📧',bgColor:'#DC2626',msgCount:3,hasUpdate:false,hasDot:false},{id:3,name:'通知',icon:'🔔',bgColor:'#D97706',msgCount:0,hasUpdate:false,hasDot:true},{id:4,name:'商城',icon:'🛒',bgColor:'#059669',msgCount:0,hasUpdate:true,hasDot:false},{id:5,name:'日历',icon:'📅',bgColor:'#7C3AED',msgCount:12,hasUpdate:false,hasDot:false},{id:6,name:'设置',icon:'⚙️',bgColor:'#374151',msgCount:0,hasUpdate:true,hasDot:false},]@Statetabs:TabItem[]=[{label:'首页',icon:'🏠',badgeCount:0},{label:'消息',icon:'💬',badgeCount:5},{label:'发现',icon:'🔍',badgeCount:0},{label:'我的',icon:'👤',badgeCount:1},]@StateselectedTab:number=0@StatedotBadgeVisible:boolean=trueclearBadge(appId:number){this.apps=this.apps.map((app:AppInfo)=>{if(app.id===appId){return{id:app.id,name:app.name,icon:app.icon,bgColor:app.bgColor,msgCount:0,hasUpdate:false,hasDot:false}}returnapp})}build(){Column({space:0}){// 标题Text('Badge 徽标组件').fontSize(20).fontWeight(FontWeight.Bold).fontColor('#111827').width('100%').padding({left:20,right:20,top:20,bottom:4})Text('数字徽标、圆点徽标、位置控制').fontSize(13).fontColor('#6B7280').width('100%').padding({left:20,right:20,bottom:16})// 一、应用图标徽标Column({space:12}){Text('一、应用图标徽标(点击清除)').fontSize(14).fontWeight(FontWeight.Bold).fontColor('#374151').width('100%')Flex({wrap:FlexWrap.Wrap,justifyContent:FlexAlign.Start}){ForEach(this.apps,(app:AppInfo)=>{Column({space:6}){if(app.msgCount>0){Badge({count:app.msgCount,maxCount:99,position:BadgePosition.RightTop,style:{badgeSize:18,badgeColor:'#EF4444',fontSize:10}}){Text(app.icon).fontSize(28).width(56).height(56).textAlign(TextAlign.Center).backgroundColor(app.bgColor).borderRadius(14)}.onClick(()=>this.clearBadge(app.id))}elseif(app.hasDot){Badge({value:'',position:BadgePosition.RightTop,style:{badgeSize:10,badgeColor:'#EF4444'}}){Text(app.icon).fontSize(28).width(56).height(56).textAlign(TextAlign.Center).backgroundColor(app.bgColor).borderRadius(14)}.onClick(()=>this.clearBadge(app.id))}elseif(app.hasUpdate){Badge({value:'NEW',position:BadgePosition.RightTop,style:{badgeSize:16,badgeColor:'#F97316',fontSize:9,fontWeight:FontWeight.Bold}}){Text(app.icon).fontSize(28).width(56).height(56).textAlign(TextAlign.Center).backgroundColor(app.bgColor).borderRadius(14)}.onClick(()=>this.clearBadge(app.id))}else{Text(app.icon).fontSize(28).width(56).height(56).textAlign(TextAlign.Center).backgroundColor(app.bgColor).borderRadius(14).onClick(()=>this.clearBadge(app.id))}Text(app.name).fontSize(11).fontColor('#374151')}.alignItems(HorizontalAlign.Center).margin({right:16,bottom:8})},(app:AppInfo)=>app.id.toString())}.width('100%').padding({top:12,bottom:12,left:12,right:12}).backgroundColor('#F9FAFB').borderRadius(12)}.width('100%').padding({left:20,right:20}).alignItems(HorizontalAlign.Start).margin({bottom:16})// 二、徽标位置对比Column({space:12}){Text('二、徽标位置对比').fontSize(14).fontWeight(FontWeight.Bold).fontColor('#374151').width('100%')Row({space:20}){Column({space:8}){Badge({count:5,position:BadgePosition.RightTop,style:{badgeSize:18,badgeColor:'#EF4444'}}){Text('📦').fontSize(28).width(52).height(52).textAlign(TextAlign.Center).backgroundColor('#EFF6FF').borderRadius(12)}Text('右上角').fontSize(12).fontColor('#6B7280')}Column({space:8}){Badge({count:5,position:BadgePosition.Left,style:{badgeSize:18,badgeColor:'#059669'}}){Text('📦').fontSize(28).width(52).height(52).textAlign(TextAlign.Center).backgroundColor('#ECFDF5').borderRadius(12)}Text('左侧').fontSize(12).fontColor('#6B7280')}Column({space:8}){Badge({count:5,position:BadgePosition.Right,style:{badgeSize:18,badgeColor:'#7C3AED'}}){Text('📦').fontSize(28).width(52).height(52).textAlign(TextAlign.Center).backgroundColor('#F5F3FF').borderRadius(12)}Text('右侧').fontSize(12).fontColor('#6B7280')}}.width('100%').justifyContent(FlexAlign.SpaceAround).padding(12).backgroundColor('#F9FAFB').borderRadius(12)}.width('100%').padding({left:20,right:20}).alignItems(HorizontalAlign.Start).margin({bottom:16})// 三、Tab 栏徽标Column({space:12}){Text('三、Tab 栏消息徽标').fontSize(14).fontWeight(FontWeight.Bold).fontColor('#374151').width('100%')Row(){ForEach(this.tabs,(tab:TabItem,index:number)=>{Column({space:4}){if(tab.badgeCount>0){Badge({count:tab.badgeCount,position:BadgePosition.RightTop,style:{badgeSize:16,badgeColor:'#EF4444',fontSize:10}}){Text(tab.icon).fontSize(24).width(36).height(36).textAlign(TextAlign.Center)}}else{Text(tab.icon).fontSize(24).width(36).height(36).textAlign(TextAlign.Center)}Text(tab.label).fontSize(11).fontColor(this.selectedTab===index?'#2563EB':'#9CA3AF')}.layoutWeight(1).alignItems(HorizontalAlign.Center).onClick(()=>{this.selectedTab=index})},(tab:TabItem)=>tab.label)}.width('100%').padding({top:8,bottom:8}).backgroundColor(Color.White).borderRadius(12).shadow({radius:8,color:'rgba(0,0,0,0.08)',offsetY:-2})}.width('100%').padding({left:20,right:20}).alignItems(HorizontalAlign.Start)Blank()}.width('100%').height('100%').backgroundColor('#FFFFFF')}}

写在最后

如果你正在整理 HarmonyOS7 组件案例,可以把这篇当成Badge的实践模板。先跑通页面,再逐步替换数据和样式,效率会高不少。

http://www.jsqmd.com/news/1220556/

相关文章:

  • Invoicely:简单高效的开源发票生成器,让专业发票制作仅需几分钟
  • Python循环控制:while/continue/break原理与应用
  • 2026最新!百达翡丽全国官方售后网点核验报告出炉,超60家正规服务门店详细地址公布 - 百达翡丽中国服务中心
  • 3分钟掌握payload-dumper-go:高效的Android OTA解包利器
  • 西安黄金上门回收实地避坑测评!6 家临街实体门店大盘计价无任何隐形扣费 - 不晚生活号
  • Rapid SCADA项目快速上手:10分钟完成第一个工业监控项目
  • 2026吉他选购避坑指南!吃透3大核心,7款高性价比机型实测推荐
  • 苹果手机去水印App哪个好用?免费好用的iPhone去水印工具横评 - 科技热点发布
  • 2026 上海汽车隔音口碑标杆:魔都之声汽车音响 以专业工艺铸就长效静谧驾乘体验 - 汽车音响改装
  • Selene PageObject 模式实战:构建可维护的 Python Web 测试框架的完整指南
  • 抖音内容追踪助手:解放你的碎片化时间,不错过每一个重要更新
  • Diplomat:革命性Rust FFI工具,轻松生成多语言绑定的完整指南
  • 出差途中表坏了,最怕的不是修不好,是修完找不到人 - 亨得利官方维修中心
  • Python agent-admin 包详解:功能、安装、案例与常见错误
  • RawPDB性能测试:1GiB PDB文件解析仅需233ms的底层优化揭秘
  • 构建企业级数据中台:DataSphere Studio的架构创新与实践指南
  • 【LE Audio】CSIS精讲[3]:协调集广播识别的双核心——RSI与服务数据设计
  • 2026年天津全城及周边县城欧米茄手表回收京津冀十年老店可上门可现场打款 联系方式:133 9303 2100 - 优企甄选
  • 实测:如何去除抖音上的抖音号水印?合法方法与工具风险大盘点 - 科技热点发布
  • SecretAgent核心功能解析:从反屏蔽到DOM追踪的全方位能力
  • 移动端白屏、折叠屏错位、Webview抖动——Cursor响应式故障诊断矩阵(附12个生产环境真实日志片段)
  • 瑞德克斯平台:风控思路的标准分析
  • 智谱清言Prompt工程黄金公式(已验证217个真实业务场景):3步写出高召回+低幻觉指令,今天不学明天就掉队
  • U盘加密工具,你的U盘你做主
  • AI 辅助 DApp 负载测试设计:用户行为建模、流量回放与链上压力场景生成
  • TMS320F28003x DMA模块深度解析:从寄存器映射到乒乓缓冲实战
  • 权威核验!广州劳力士官方直营售后网点大全,官方门店地址+官方服务电话,2026年7月最新公示 - 劳力士中国维修中心
  • 杭州卖金避坑指南!这6家宝藏黄金回收店覆盖全城,价格透明不踩雷 - 新芸鼎珠宝首饰
  • 如何打破Windows版本限制:Policy Plus让你的家庭版也能享受专业级组策略管理
  • 如何快速掌握Python RCWA:开源光学仿真工具完整指南