HarmonyOS7 消息徽标展示页实战:Badge 不只是会用,还要用得顺手
文章目录Badge 不是贴上去就完事清除徽标要清完整状态三种徽标场景怎么选页面结构怎么看完整代码写在最后Badge 最常见的误用是把它当成一个红点装饰。实际做消息页、应用入口、Tab 栏时它表达的是“还有东西没处理”。这个状态如果和真实数据脱节用户点进去发现什么都没有体验会很糟。这篇用 HarmonyOS7 的 Badge 做了三个场景应用图标未读数、徽标位置对比、Tab 栏消息提醒。它不复杂但很适合拿来练状态同步。Badge 不是贴上去就完事页面里定义了AppInfo和TabItem。前者记录应用图标、背景色、未读数、更新状态和圆点状态后者负责 Tab 栏里的标题、图标和徽标数字。这种数据结构比直接在 UI 里写死数字好很多。未读数来自接口也好来自本地缓存也好最后都能落到同一个字段上Badge 只负责展示。清除徽标要清完整状态clearBadge()是这篇的关键。点击某个应用后它会把对应应用的msgCount、hasUpdate、hasDot一起清掉而不是只把数字改成 0。clearBadge(appId:number){this.appsthis.apps.map((app:AppInfo){if(app.idappId){return{id:app.id,name:app.name,icon:app.icon,bgColor:app.bgColor,msgCount:0,hasUpdate:false,hasDot:false}}returnapp})}这点很贴近真实业务。一个入口可能同时有未读消息、版本更新、小红点提醒如果只清其中一个页面就会出现“数字没了但红点还在”的尴尬状态。三种徽标场景怎么选数字徽标适合明确数量比如未读消息、待处理订单圆点徽标适合弱提醒比如有新内容但数量不重要Tab 徽标适合告诉用户某个栏目里有待处理内容。别所有地方都用数字。超过一定数量后用户其实不关心精确值显示99或一个红点往往更清爽。页面结构怎么看BadgeMessagePage主要看两块状态apps控制应用图标区tabs和selectedTab控制底部 Tab。读代码时可以先看数据数组再看 Badge 包裹了哪个组件最后看点击事件如何更新状态。如果你要把这个案例放进项目我建议把清除逻辑接到真实阅读状态上。Badge 的展示可以很轻但背后的状态一定要准。完整代码下面是完整代码。入口组件名是BadgeMessagePage可以直接作为消息入口或 Tab 徽标的参考实现。// Badge 徽标组件全解析interfaceAppInfo{id:numbername:stringicon:stringbgColor:stringmsgCount:numberhasUpdate:booleanhasDot:boolean}interfaceTabItem{label:stringicon:stringbadgeCount:number}EntryComponentstruct 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:number0StatedotBadgeVisible:booleantrueclearBadge(appId:number){this.appsthis.apps.map((app:AppInfo){if(app.idappId){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.msgCount0){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.badgeCount0){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.selectedTabindex?#2563EB:#9CA3AF)}.layoutWeight(1).alignItems(HorizontalAlign.Center).onClick((){this.selectedTabindex})},(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的实践模板。先跑通页面再逐步替换数据和样式效率会高不少。