做微信小程序的朋友大多遇到过这种尴尬:产品经理拿着设计稿说,这个 tabbar 要中间凸起一个按钮,图标要能带角标,选中态要有个小动画。而小程序原生 tabBar 只支持静态配置,改个图标都得重新编译,更别说凸起和动画了。这时候就得上自定义 tabbar。
自定义 tabbar 的核心思路其实不复杂:把原生 tabbar 隐藏掉,自己写一个 fixed 定位的组件,用 wx.switchTab 做页面切换。但坑也不少,比如切换时的闪烁、选中态不同步、页面栈判断错误等。下面把我踩过的坑和最终方案整理出来。
一、开启自定义 tabbar
在 app.json 里给 tabBar 加一个 custom: true,同时保留 list 配置(list 里的 pagePath 必须和真实页面一致,否则 switchTab 会失败):
{
"tabBar": {
"custom": true,
"list": [
{ "pagePath": "pages/index/index", "text": "首页" },
{ "pagePath": "pages/category/category", "text": "分类" },
{ "pagePath": "pages/cart/cart", "text": "购物车" },
{ "pagePath": "pages/mine/mine", "text": "我的" }
]
}
}
然后在项目根目录新建 custom-tab-bar 文件夹,注意这个名字是固定的,不能改。里面放 index.js / index.json / index.wxml / index.wxss 四个文件,index.json 里要声明 "component": true。
二、组件逻辑实现
组件里最关键的是 selected 状态和切换方法。这里有个细节:每个 tab 页面都要在 onShow 里调用 this.getTabBar().setData({ selected: 0 }) 来同步选中态,否则从其他页面返回时高亮会错乱。
// custom-tab-bar/index.js
Component({
data: {
selected: 0,
list: [
{ pagePath: '/pages/index/index', text: '首页', icon: 'home' },
{ pagePath: '/pages/category/category', text: '分类', icon: 'grid' },
{ pagePath: '/pages/cart/cart', text: '购物车', icon: 'cart' },
{ pagePath: '/pages/mine/mine', text: '我的', icon: 'user' }
]
},
methods: {
switchTab(e) {
const { index, path } = e.currentTarget.dataset;
if (this.data.selected === index) return;
wx.switchTab({
url: path,
success: () => {
this.setData({ selected: index });
}
});
}
}
});
对应的 wxml 用 flex 布局,中间凸起按钮可以单独用绝对定位抬高:
<view class="tab-bar">
<view
wx:for="{{list}}"
wx:key="pagePath"
class="tab-item {{selected === index ? 'active' : ''}}"
data-index="{{index}}"
data-path="{{item.pagePath}}"
bindtap="switchTab"
>
<view class="icon icon-{{item.icon}}"></view>
<text>{{item.text}}</text>
</view>
</view>
三、页面同步选中态
每个 tab 页面都要加这段,建议封装成 mixin 或者直接复制,四个页面也就几行:
onShow() {
if (typeof this.getTabBar === 'function' && this.getTabBar()) {
this.getTabBar().setData({ selected: 0 }); // 按页面改索引
}
}
四、几个容易踩的坑
- 闪烁问题:自定义 tabbar 首次加载会有短暂空白,可以在
app.wxss里给 tabbar 预留高度,或者用wx.hideTabBar()配合,但更推荐直接在组件里加骨架样式。 - 页面栈判断:不要用
getCurrentPages()去反推索引,容易在多级跳转后出错,老老实实每个页面 setData 最稳。 - 角标和红点:购物车数量这类动态数据,建议放在全局 store(如 mobx-miniprogram 或简单的 globalData)里,tabbar 组件监听变化,避免每个页面重复请求。
- 安全区适配:iPhone 底部有 home indicator,tabbar 高度要用
env(safe-area-inset-bottom)补 padding,不然会被遮挡。
五、小结
自定义 tabbar 本身代码量不大,难点在于状态同步和细节适配。我的建议是:如果只是改个图标颜色,原生配置够用就别折腾;一旦涉及凸起按钮、动态角标、切换动画,再上自定义方案。另外记得在真机上多测几种机型,尤其是刘海屏和折叠屏,安全区适配做不好,体验会打折扣。
这套方案我在几个电商类小程序里都跑过,稳定性和性能都没问题。如果你也在做类似需求,可以直接拿去改,省下的时间够喝杯咖啡了。
评论 (0)
还没有评论,快来抢沙发吧~