uni-app x uni-tabBar UTS 插件深度解析:动态设置 TabBar 样式、徽标与中间按钮的完整实战指南
【免费下载链接】uni-appA cross-platform framework using Vue.js项目地址: https://gitcode.com/gh_mirrors/un/uni-app
uni-tabBar 是 uni-app / uni-app x 仓库中一个基于 UTS 技术实现的 uni_modules 插件,核心能力是"实现设置 TabBar 样式功能",把uni.setTabBarBadge、uni.setTabBarItem、uni.setTabBarStyle等 9 个 TabBar 动态操作 API 的跨端实现沉淀为可复用插件。本文以仓库中的插件文档 src/uni_modules/uni-tabBar/readme.md 为骨架,结合其源码实现与官方示例组件,完整讲解 UTS 语言与 UTS 插件机制、全部 API 的参数语义与平台支持矩阵、Android/HarmonyOS 双端底层调用链,以及可直接复制的实战代码。读完你既能熟练使用这套 API 完成 TabBar 的运行时定制(角标、红点、显隐、换肤、中间凸起按钮),也能理解一个标准 UTS 插件从类型声明到分平台实现的完整工程结构。
一、插件定位:一个"封装 TabBar 动态 API"的 UTS 插件
在 uni-app x 中,TabBar 的静态配置(页面路径、图标、颜色等)通过 pages.json 中的tabBar字段声明,而运行时的动态调整(添加数字角标、显示红点、切换样式、隐藏某个 tab)则由uni.xxx系列 API 完成。uni-tabBar 插件正是这些动态 API 的统一载体。
从插件元信息 package.json 可以看到:
- 插件 ID 为
uni-tabBar,type为uts,即一个纯 UTS 插件; engines.HBuilderX要求^3.6.8,说明该插件适用于 HBuilderX 3.6.8 及以上版本;- 在
uni_modules.uni-ext-api.uni段中声明了 9 个扩展 API:showTabBarRedDot、hideTabBarRedDot、setTabBarBadge、removeTabBarBadge、setTabBarItem、setTabBarStyle、showTabBar、hideTabBar、onTabBarMidButtonTap; platforms段声明了插件在 Vue2/Vue3、App(Android/iOS)、H5、各主流小程序(微信、阿里、百度、字节跳动、QQ、钉钉、快手、飞书、京东)以及快应用等客户端环境中的可用性。
也就是说,插件安装后这些 API 会以uni.setTabBarBadge()的形式直接注入全局uni对象,开发者无需关心底层是 Kotlin、Swift 还是 ArkTS。
二、UTS 语言与 UTS 插件机制(插件的技术底座)
uni-tabBar 之所以能一套代码覆盖多端,依赖于其背后的 UTS 语言与 UTS 插件规范。以下内容摘自插件文档并结合作者视角展开。
2.1 UTS:可编译为多端原生语言的强类型语言
UTS(uni type script)是一门跨平台、高性能、强类型的现代编程语言,它最大的特点是按目标平台编译为对应的原生语言:
| 目标平台 | 编译产物语言 | | -- | -- | | Android | Kotlin | | iOS | Swift | | HarmonyOS(鸿蒙) | ArkTS | | Web / 小程序 | JavaScript |
UTS 采用了与 TypeScript 基本一致的语法规范,并支持绝大部分 ES6 API。但为了跨端统一,UTS 做出了一些约束,并针对特定平台进行了增补:过去在 JS 引擎下运行的语法,大部分在 UTS 处理后可以平滑迁移到 Kotlin 和 Swift 中;但仍有部分语法无法抹平差异,此时需要借助条件编译——和 uni-app 的条件编译类似,UTS 同样支持条件编译,写在条件编译分支里的代码可以调用平台特有的扩展语法。仓库内 UTS 相关的完整介绍可参考 docs/uts/README.md,UTS 与 TS 的具体差异见 docs/uts/uts_diff_ts.md。
2.2 UTS 插件:用 UTS 封装原生 API 的标准形态
UTS 插件是一种特定的 uni_modules 插件,其核心目的是允许 uni-app / uni-app x 开发者使用 UTS 语法调用扩展 API(封装原生系统的 API 或三方 SDK)。
UTS 插件的实现代码主要位于utssdk目录下,并按平台分离组织,插件文档给出了如下目录约定:
| 目录/文件 | 目标平台 | 实现语言 | 作用描述 | | -- | -- | -- | -- | |utssdk/app-android| Android | UTS, Kotlin, Java | 存放 UTS 插件在 Android 平台上的具体实现源码 | |utssdk/app-ios| iOS | UTS, Swift | 存放 UTS 插件在 iOS 平台上的具体实现源码 | |utssdk/app-harmony| HarmonyOS(鸿蒙) | UTS, ArkTS | 存放 UTS 插件在 HarmonyOS 平台上的具体实现源码 | |utssdk/*.uts| 多平台共用 | UTS | 存放使用 UTS 语言编写的、可供所有平台共用的实现源码 |
uni-tabBar 插件严格遵循了这一结构。查看仓库中的 src/uni_modules/uni-tabBar/utssdk 目录:
utssdk/ ├── app-android/ │ └── index.uts # Android 平台实现 ├── app-harmony/ │ └── index.uts # HarmonyOS 平台实现 ├── interface.uts # 多平台共用:全部 API 的类型声明(跨端共用) ├── protocol.uts # 多平台共用:API 名称常量与参数协议校验表 └── unierror.uts # 多平台共用:统一错误类其中app-android/index.uts与app-harmony/index.uts是平台专属实现,其余三个文件为跨平台共享逻辑。UTS 插件的整体开发规范可参考 docs/plugin/uts-plugin.md,如需在插件中混编原生语言,见 docs/plugin/uts-plugin-hybrid.md;各平台的注意事项分别见 docs/plugin/uts-for-android.md、docs/plugin/uts-for-ios.md 与 docs/plugin/uts-for-harmony.md。
三、九个 API 的完整参数语义与类型定义
插件对外暴露的能力全部收敛在跨平台类型声明文件 interface.uts 中,该文件同时定义了参数类型、回调类型、错误码与Uni接口扩展声明。下面按功能分组逐一拆解。
3.1 角标(Badge):setTabBarBadge / removeTabBarBadge
setTabBarBadge用于为 TabBar 某一项的右上角添加文本角标,其参数类型SetTabBarBadgeOptions定义如下(见 interface.uts):
| 字段 | 类型 | 必填 | 说明 | | -- | -- | -- | -- | |index| number | 是 | tabBar 的哪一项,从左边算起,索引从 0 开始 | |text| string | 是 | 显示的文本,不超过 3 个半角字符 | |success| (result) => void | 否 | 接口调用成功的回调 | |fail| (result) => void | 否 | 接口调用失败的回调 | |complete| (result) => void | 否 | 接口调用结束的回调(成功、失败都会执行) |
removeTabBarBadge用于移除角标,参数RemoveTabBarBadgeOptions只需必填的index(语义同上)。两个 API 均返回Promise<...> | null,因此既可写回调也可await。
在 protocol.uts 中,两者的参数协议同样约束为:index(number、必填)、text(string、必填)。也就是说运行时若缺少index或text,会在参数校验阶段直接失败,而不会进入原生调用。
3.2 红点:showTabBarRedDot / hideTabBarRedDot
showTabBarRedDot用于在 TabBar 某一项的右上角显示红点,hideTabBarRedDot用于隐藏。两者的ShowTabBarRedDotOptions/HideTabBarRedDotOptions均只有必填的index,配合success/fail/complete回调。协议文件对两者都声明了index(number、必填),与角标 API 保持一致。
3.3 单项内容:setTabBarItem
setTabBarItem用于动态设置 TabBar 某一项的内容,是日常定制最常用的 API 之一,参数类型SetTabBarItemOptions包含:
| 字段 | 类型 | 必填 | 说明 | | -- | -- | -- | -- | |index| number | 是 | tabBar 的哪一项,从左边算起,索引从 0 开始 | |text| string | 否 | tab 上按钮文字 | |iconPath| string | 否 | 图片路径 | |selectedIconPath| string | 否 | 选中时的图片路径 | |pagePath| string | 否 | 页面绝对路径 | |iconfont| SetTabBarItemIconFontOptions | 否 | 字体图标,优先级高于iconPath| |visible| boolean | 否 | tab 是否显示 | |success/fail/complete| 回调 | 否 | 标准回调三件套 |
其中SetTabBarItemIconFontOptions结构为:text(字库 Unicode 码)、selectedText(选中后字库 Unicode 码)、fontSize(字体图标字号,单位 px)、color(字体图标颜色)、selectedColor(字体图标选中颜色)。
值得注意的细节:
pagePath字段带有@uniPlatform标注,在 App(Android/iOS/HarmonyOS)各端标注为uniVer: "x",而 Web 端为"√",说明该字段的能力覆盖存在平台差异,跨端使用时需要留意(具体以目标端实际支持为准);iconfont的优先级高于iconPath,即同时传入时以字体图标为准。
3.4 整体样式:setTabBarStyle
setTabBarStyle用于动态设置 TabBar 的整体样式,参数SetTabBarStyleOptions字段如下:
| 字段 | 类型 | 必填 | 说明 | | -- | -- | -- | -- | |color| string | string.ColorString | 否 | tab 上文字默认颜色 | |selectedColor| string | string.ColorString | 否 | tab 上文字选中时的颜色 | |backgroundColor| string | string.ColorString | 否 | tab 的背景色 | |backgroundImage| string | 否 | 图片背景 | |backgroundRepeat| 'repeat' | 'repeat-x' | 'repeat-y' | 'no-repeat' | 否 | 背景图平铺方式:分别为垂直+水平平铺、水平平铺(垂直拉伸)、垂直平铺(水平拉伸)、双向拉伸 | |borderColor| string | string.ColorString | 否 | tabbar 上边框颜色(优先级高于 borderStyle) | |borderStyle| 'black' | 'white' | 否 | tabbar 上边框颜色(黑/白二选一) | |midButton| MidButtonOptions | 否 | tabbar 中间按钮,仅在 list 项为偶数时有效(内部能力) | |success/fail/complete| 回调 | 否 | 标准回调三件套 |
其中MidButtonOptions用于实现类似"中间凸起"的发布按钮效果,参数为:width(中间按钮宽度,默认 80px,tabBar 其它项为减去此宽度后平分)、height(中间按钮高度,默认 50px,可大于 tabBar 高度实现中间凸起效果)、text(中间按钮文字)、iconPath(中间按钮图片路径)、iconWidth(图片宽度,高度等比例缩放,默认 24px)、backgroundImage(中间按钮背景图片路径)、iconfont(字体图标,优先级高于iconPath)。
borderColor与borderStyle的关系在源码中有明确体现:Android 实现中会先判断borderColor是否为字符串,若是则直接以borderColor覆盖borderStyle(详见下文第四节),这与类型注释"优先级高于 borderStyle"完全一致。
3.5 显隐控制:showTabBar / hideTabBar
showTabBar与hideTabBar用于控制整个 TabBar 的显示与隐藏,参数ShowTabBarOptions/HideTabBarOptions仅有一个可选字段animation(是否需要动画效果),加上标准回调。两者的参数类型声明允许传入null(options?: ShowTabBarOptions | null),即可以直接uni.hideTabBar()无参调用。
3.6 中间按钮事件:onTabBarMidButtonTap
onTabBarMidButtonTap(callback)用于监听中间按钮的点击事件,回调OnTabBarMidButtonTapCallback无参数。从 interface.uts 的@uniPlatform标注看,该 API 在 App(Android/iOS)的 uni-app 体系中为"√",而在 uni-app x 各端多为 "x",Web 端 uniVer 为 "√",即该能力更多面向传统 uni-app 运行时(具体以目标平台实际支持为准)。
3.7 统一错误码与错误对象
插件定义了两个错误码(见 interface.uts 与 unierror.uts):
| errCode | 含义 | | -- | -- | | 100 | TabBar 不存在(tabBar is not exist) | | 200 | 参数错误 |
所有 API 的失败对象SetTabBarFail都继承自IUniError并携带errCode;实现类SetTabBarFailImpl构造函数签名(errMsg: string, errCode: SetTabBarErrorCode = 100),即默认错误码为 100。开发者在fail回调中可通过errCode精确区分失败原因。
四、源码级实现剖析:一条 API 从调用到原生执行的完整链路
uni-tabBar 的共享逻辑与平台实现分离,下面分别剖析 Android 与 HarmonyOS 的实现,帮助你理解 UTS 插件的内部运作。
4.1 Android 平台:defineAsyncApi + getTabBar
Android 实现位于 app-android/index.uts,其模式可归纳为三步:
- 定义异步 API:通过
defineAsyncApi<Options, Success>(apiName, handler)声明,例如setTabBarBadge的定义为defineAsyncApi<SetTabBarBadgeOptions, SetTabBarBadgeSuccess>('setTabBarBadge', ...); - 获取 TabBar 实例:从
@dcloudio/uni-runtime导入getTabBar(),若返回null则res.reject(new SetTabBarFailImpl('tabBar is not exist'))并以错误码 100 结束; - 组装参数并调用原生方法:将 UTS 对象参数转换为
Map<string, any>后调用tabBar.setTabBarBadge(map),成功则res.resolve(null)。
以setTabBarItem为例,参数组装会把text、iconPath、selectedIconPath、pagePath、visible放入 Map,并在iconfont非空时追加一个嵌套的iconfontMap(含text/selectedText/fontSize/color/selectedColor)。setTabBarStyle的实现则展示了两个值得关注的细节:
- 通过
isString(options.borderColor)判断:优先使用borderColor作为上边框颜色;否则使用getTabBarBorderStyle(options.borderStyle)将'black' | 'white'转换为平台所需格式; midButton非空时,将width/height/iconPath/text/iconWidth/backgroundImage及嵌套iconfont组装为midButtonMap。
onTabBarMidButtonTap在 Android 侧通过defineOnApi('onTabBarMidButtonTap', ...)注册为事件监听 API(当前实现为 noop 占位,事件响应由原生侧完成)。
4.2 HarmonyOS 平台:协议校验 + 参数直传
HarmonyOS 实现位于 app-harmony/index.uts,与 Android 的主要差异在于:
- API 名称使用常量:如
API_SET_TAB_BAR_BADGE、API_SHOW_TAB_BAR_RED_DOT等,这些常量统一定义在 protocol.uts 中(如export const API_SET_TAB_BAR_BADGE = 'setTabBarBadge'),避免字符串散落各处; - 携带参数协议:
defineAsyncApi的第三个参数传入协议表(如SetTabBarBadgeApiProtocol),由框架在进入实现前完成参数类型与必填校验,校验失败即exec.reject,无需在每个方法内重复判断; - 参数直传对象:与 Android 的 Map 组装不同,Harmony 端将 UTS 对象直接传给原生
ITabBar接口(hideTabBar/showTabBar无参调用); - 文件同时以
export { ... }方式导出了全部 Options/Success 类型,供其他模块引用。
协议表SetTabBarStyleApiProtocol声明了color/selectedColor/backgroundColor/backgroundImage/backgroundRepeat/borderStyle/borderColor七个可选 string 参数;SetTabBarItemApiProtocol声明index必填、其余(text/iconPath/selectedIconPath/pagePath/visible/iconfont)可选。
4.3 双端一致性小结
| 环节 | Android(app-android/index.uts) | HarmonyOS(app-harmony/index.uts) | | -- | -- | -- | | API 定义 |defineAsyncApi('xxx', handler)|defineAsyncApi(API_XXX, handler, Protocol)| | TabBar 获取 |getTabBar()(来自 @dcloudio/uni-runtime) |getTabBar(),并断言为ITabBar| | 空实例处理 |reject(new SetTabBarFailImpl('tabBar is not exist'))|reject('tabBar is not exist')| | 参数传递 | 组装Map<string, any>| 直接传递 UTS 对象 | | 参数校验 | 由业务/原生侧处理 | 框架层协议表校验 |
从源码结构看,插件把"跨端共用的类型与协议"与"平台专属的调用细节"严格隔离,这正是标准 UTS 插件的推荐组织方式。
五、官方示例:api-set-tabbar 组件实战演示
仓库在 src/components/api-set-tabbar/api-set-tabbar.vue 中提供了覆盖全部 API 的官方演示组件(页面标题tababr,脚本语言为lang="uts"),是学习这套 API 的最佳范本。
5.1 角标与红点的互斥切换
演示组件用两个状态hasSetTabBarBadge与hasShownTabBarRedDot控制,并保证两者互斥:设置角标前先隐藏红点,显示红点前先移除角标,避免角标与红点叠加:
const setTabBarBadge = () => { if (hasShownTabBarRedDot.value) { uni.hideTabBarRedDot({ index: 1 }) hasShownTabBarRedDot.value = !hasShownTabBarRedDot.value } if (!hasSetTabBarBadge.value) { uni.setTabBarBadge({ index: 1, text: '1' }) } else { uni.removeTabBarBadge({ index: 1 }) } hasSetTabBarBadge.value = !hasSetTabBarBadge.value } const showTabBarRedDot = () => { if (hasSetTabBarBadge.value) { uni.removeTabBarBadge({ index: 1 }) hasSetTabBarBadge.value = !hasSetTabBarBadge.value } if (!hasShownTabBarRedDot.value) { uni.showTabBarRedDot({ index: 1 }) } else { uni.hideTabBarRedDot({ index: 1 }) } hasShownTabBarRedDot.value = !hasShownTabBarRedDot.value }5.2 样式与单项的动态定制
customStyle在默认配色与自定义配色间切换,完整展示了setTabBarStyle的color、selectedColor、backgroundColor、borderStyle用法,并注释提示可追加borderColor(优先级更高):
uni.setTabBarStyle({ color: '#FFF', selectedColor: '#007AFF', backgroundColor: '#000000', borderStyle: 'black', })customItem/setTabBarTitle/hideTabBarItem则演示了setTabBarItem的三类玩法:更换文字(text: 'API')、设置超长标题(同时清空iconPath/selectedIconPath)、通过visible: false隐藏某项。其中图标使用仓库静态资源 src/static/api.png 与 src/static/apiHL.png:
let tabBarOptions = { index: 1, text: '接口', iconPath: '/static/api.png', selectedIconPath: '/static/apiHL.png' } as SetTabBarItemOptions uni.setTabBarItem(tabBarOptions)5.3 显隐控制与条件编译
hideTabBar通过uni.hideTabBar()/uni.showTabBar()切换整条 TabBar。值得注意的是示例对setTabBarItem相关能力使用了条件编译:在APP-HARMONY平台通过uni.showToast({ title: "暂不支持" })提示,其余平台走完整逻辑(#ifdef APP-HARMONY/#ifndef APP-HARMONY)。这印证了 UTS 条件编译在实际项目中的典型用法——对平台差异能力做降级处理。
5.4 组件卸载时的状态恢复
示例在onUnmounted中根据各状态标记逐个还原 TabBar:移除角标、隐藏红点、恢复样式、恢复 item 文本与图标、恢复visible,最后uni.showTabBar()。这一写法是页面级 TabBar 定制必须养成的习惯——避免组件销毁后 TabBar 残留被修改的状态。
六、API 平台支持矩阵与使用注意事项
结合 interface.uts 中各 API 的@uniPlatform标注,可将主要 API 的支持情况归纳如下(√ 表示支持,x 表示不支持,数字表示引入该能力的 uni-app x 版本;此为仓库源码标注,实际以目标端版本为准):
| API | App-Android (unixVer) | App-iOS (unixVer) | App-Harmony (unixVer) | 微信小程序 (unixVer) | Web (unixVer) | | -- | -- | -- | -- | -- | -- | | setTabBarBadge / removeTabBarBadge | 3.91 | 4.11 | 4.61 | 4.41 | 4.0 | | setTabBarItem | 3.91 | 4.11 | 4.61 | 4.41 | 4.0 | | setTabBarStyle | 3.91 | 4.11 | x(uniVer 4.23) | 4.41 | 4.0 | | showTabBar / hideTabBar | 3.91 | 4.11 | 4.61 | 4.41 | 4.0 | | showTabBarRedDot / hideTabBarRedDot | 3.91 | 4.11 | 4.61 | 4.41 | 4.0 | | onTabBarMidButtonTap | unixVer x(uniVer √) | unixVer x(uniVer √) | x | x | 4.0 |
使用时的关键注意事项:
index是硬性必填参数,从 0 开始计数,越界或缺失会在协议校验/原生调用阶段报错;- 角标
text不超过 3 个半角字符,且角标与红点语义互斥,切换前需先移除另一者(官方示例即按此处理); borderColor优先级高于borderStyle,且borderStyle仅接受'black' | 'white';iconfont优先级高于iconPath;midButton(中间按钮)仅在 tabBar list 项为偶数时有效,并可通过height大于 TabBar 高度实现中间凸起;- 需要监听中间按钮点击时使用
uni.onTabBarMidButtonTap(callback),对应 API 文档见 docs/api/on-tab-bar-mid-button-tap.md; - 完整 API 规范与逐参数说明可查阅仓库文档 docs/api/set-tab-bar.md。
七、如何安装与使用
uni-tabBar 作为 uni_modules 插件,使用方式与所有 uni_modules 一致:
- 获取插件:在 HBuilderX 的插件市场或 uni_modules 目录中导入
uni-tabBar(当前仓库内的实现位于 src/uni_modules/uni-tabBar,可直接作为参考实现比对),HBuilderX 版本需不低于^3.6.8; - 确认页面配置:确保当前页面属于
pages.json中tabBar.list配置的 tab 页面,因为所有 API 都依赖getTabBar()获取到已创建的 TabBar 实例,否则会以错误码 100(tabBar is not exist)失败; - 直接调用:插件安装后 API 自动挂载到全局
uni,在<script lang="uts" setup>中直接书写uni.setTabBarBadge({ index, text })等调用即可,返回值为 Promise 或使用 success/fail/complete 回调; - 恢复现场:参考官方示例,在页面
onUnmounted中按状态标记恢复 TabBar,防止修改泄漏到其他页面。
八、结语:从 uni-tabBar 看 UTS 插件工程的范式
uni-tabBar 是一个体量不大却极具教学价值的 UTS 插件:它用共享的interface.uts统一定义 API 类型与平台标注,用protocol.uts集中管理 API 常量与参数协议,用unierror.uts统一错误语义,再用app-android/app-harmony分别对接两端原生运行时。这种"共享类型 + 平台实现"的分层模式,正是 uni-app x 生态中所有扩展 API 插件的标准范式。理解它,你不仅掌握了 TabBar 动态定制的全部 API,也获得了一套可复刻的 UTS 插件工程模板。
进一步的深入学习可参考仓库内以下资料:docs/plugin/uts-plugin.md(UTS 插件开发)、docs/uts/README.md(UTS 语言)、docs/uts/uts_diff_ts.md(与 TS 的差异)、docs/api/set-tab-bar.md(API 规范),以及官方示例 src/components/api-set-tabbar/api-set-tabbar.vue。
【免费下载链接】uni-appA cross-platform framework using Vue.js项目地址: https://gitcode.com/gh_mirrors/un/uni-app
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考