uni-app 凸起 tabbar 必须手写组件,通过 fixed 定位、transform 上移、z-index 提升、负 y 阴影实现视觉凸起,配合安全区适配与 tab 状态同步。

uni-app 无法用原生 tabBar 实现凸起,必须手写组件
uni-app 的原生 tabBar 不支持 midButton(微信小程序也不支持),custom: true 后原生栏直接消失,没有“中间按钮”这个配置项。所以所谓“凸起”,本质是:用 position: fixed 拼一个假底部栏,中间那块单独上浮 + 加阴影 + 避开安全区。
- 所有平台(小程序/H5/App)都得走自定义路线,别指望 pages.json 里加个字段就搞定
- iOS 需要动态读取
env(safe-area-inset-bottom),Android 虚拟导航栏高度不固定,不能写死34rpx - 中间按钮点击区域要足够大(建议 ≥120rpx × 120rpx),否则真机点不中——尤其 iOS 上凸起部分常被误判为“超出可点击范围”
怎么让中间按钮真正“凸起来”:定位 + 层级 + 阴影
凸起不是靠图标大一点,而是视觉层级跃出底部容器。关键在三处:transform: translateY() 上移、z-index 提高、box-shadow 做悬浮感。如果只调大图标或加 padding,结果只是“胖了”,不是“凸了”。
- 外层容器高度设为
140rpx,但中间项自身高度保持100rpx,再用transform: translateY(-30rpx)往上顶 - 中间项的
z-index必须 > 其他 tab 项(比如其他是1,中间设10) - 阴影推荐:
box-shadow: 0 -10rpx 20rpx rgba(0,0,0,.1)—— 注意 y 值为负,才能模拟“从底部浮起”的光效 - 别忘了给中间按钮加
margin-bottom: 30rpx补齐下压空间,否则会挡住下面内容
状态同步和路由跳转容易断连,uni.onTabItemTap 是底线
手写 tabBar 最常崩的就是“点一下没反应”或“刷新页面后高亮错位”。根本原因是:你没接管路由事件,或者用 uni.navigateTo 跳转后没同步 current 状态。
- 必须在
App.vue的onLaunch和onShow里调用uni.onTabItemTap监听,并把当前页路径存到全局vuex或uni.getStorageSync - 每个页面的
onLoad都要读一次当前选中索引,不能只靠 props 传入 —— 页面被uni.reLaunch后 props 会丢失 - 跳转必须用
uni.switchTab({url: '/pages/xxx'}),redirectTo或navigateTo会导致 tabBar 状态不同步 - 中间凸起按钮若需跳转非 tabBar 页面(如发布页),记得先
uni.hideTabBar(),返回时再uni.showTabBar()
双端安全区适配不是加个 env() 就完事
padding-bottom: calc(env(safe-area-inset-bottom) + 10rpx) 这种写法在 H5 和部分 Android 机型上会失效,因为 env() 在非 iOS 环境可能返回 0 或未定义。
- 要用
uni.getSystemInfoSync().safeArea动态获取真实安全区数据,iOS 返回{bottom: 34},Android 多数返回{bottom: 0} - 推荐封装一个计算函数:
getBottomSafeHeight(),优先读 API,fallback 到预设值(如 iOS 34rpx / Android 0rpx / H5 0rpx) - 凸起按钮的上浮量(
transform: translateY)也要随安全区变化微调,否则在 iPhone 15 Pro 上凸起太猛,在小米 Mix Fold 上又贴底











