uni.settabbarbadge仅对pages.json中tabbar.list配置的原生tab项生效,需满足启用tabbar、页面在list中、index正确、平台支持(h5不支持);text必须为字符串,超长需截断,清空须用removetabbarbadge;onshow中加settimeout才可靠;自定义导航栏需自行实现角标。

原生导航栏(即 pages.json 中配置的 tabBar)本身不支持直接添加 badge 数字角标——你调用 uni.setTabBarBadge 实际作用的对象,是 tabBar 的「图标项」,不是导航栏标题或自定义导航栏。很多开发者误以为“导航栏”包含顶部标题栏,结果在自定义导航栏里死磕 badge,白忙活。
uni.setTabBarBadge 只对 pages.json 的 tabBar.list 生效
这个 API 的底层逻辑非常明确:它只操作原生 tabBar 组件中已声明的 tab 项。必须同时满足三个条件:
-
pages.json中启用了tabBar,且目标页面在tabBar.list数组里(比如"pagePath": "pages/message/message") -
index参数严格对应该数组下标(从 0 开始),数错一个就静默失败 - 目标平台支持该 API:微信/支付宝/百度等小程序 ✅,App 端 ✅,H5 ❌(H5 必须自己用 CSS 模拟)
常见错误是把消息页设为普通页面(不在 tabBar.list 中),却还传 index: 2——此时根本找不到对应项,API 不报错也不执行。
text 必须是字符串,数字类型会静默失效
这是最隐蔽的坑:uni.setTabBarBadge({ index: 1, text: 9 }) 看似合理,但 iOS 和多数安卓机型直接忽略。系统要求 text 是字符串,否则跳过渲染。
- 正确写法:
text: String(unreadCount)或text: `${unreadCount}` - 超长截断:官方限制最多显示 3 个半角字符,
1000会被清空或显示异常;建议提前处理:text: unreadCount > 99 ? '99+' : String(unreadCount) - 清空角标不能传
text: '',应调用uni.removeTabBarBadge({ index: 1 }),否则 iOS 可能残留旧值
onShow 里加 setTimeout(100) 才稳
在 onLoad 或 created 里调用基本无效——tabBar 组件还没完成初始化。真机上尤其明显:页面刚进,角标一闪而过或根本不出现。
- 必须放在
onShow生命周期中(Vue 3 +keep-alive场景可用onActivated) - 加
setTimeout(() => { uni.setTabBarBadge(...) }, 100)是实战验证过的最小安全延迟 - 如果未读数来自异步接口,别在
then里直接调用,先确保页面已onShow,再触发角标更新
H5 和 App 自定义导航栏要另起炉灶
如果你用的是 "navigationStyle": "custom"(隐藏原生导航栏,手写顶部栏),那 uni.setTabBarBadge 完全不生效——它和自定义导航栏毫无关系。
- H5 端:用
<view class="badge">{{ unreadCount }}</view>+ CSS 定位模拟,注意 z-index 和 transform 兼容性 - App 端:若需在自定义导航栏右上角加 badge,只能靠绝对定位 + 响应式计算位置,无法复用原生角标逻辑
- 不要试图用
plus.runtime.setBadgeNumber去影响导航栏——那是桌面图标角标,和页面内 UI 无关
真正需要角标的地方,永远是用户一眼看到的 tabBar 图标;顶部导航栏加 badge 属于自定义交互,得自己画、自己管、自己同步状态。











