背景:为什么需要自定义 tabBar?
微信小程序原生 tabBar 虽然简单易用,但存在明显限制:
- ❌ 不支持中间'+'号等凸起按钮
- ❌ 图标和文字样式无法高度自定义(如选中态动画)
- ❌ 无法动态隐藏/显示 tabBar
- ❌ 不能嵌入徽标(Badge)、红点等业务元素
解决方案:使用自定义 tabBar!
本文将带你从零实现一个支持中间凸起按钮、带动画、可扩展的自定义 tabBar,并封装为通用组件。
介绍微信小程序自定义 tabBar 的实现方法。原生 tabBar 不支持凸起按钮、动态样式及徽标,通过关闭原生配置并手动引入组件可解决。步骤包括创建组件(配置 json、定义数据模板样式)、在页面中引入并使用。中间按钮使用 navigateTo 跳转非 tab 页,普通 tab 使用 switchTab。需处理底部安全区域遮挡问题,支持徽标更新及动画优化。
微信小程序原生 tabBar 虽然简单易用,但存在明显限制:
解决方案:使用自定义 tabBar!
本文将带你从零实现一个支持中间凸起按钮、带动画、可扩展的自定义 tabBar,并封装为通用组件。
✅ 底部 5 个 tab(中间为'+'发布按钮)
✅ 点击 tab 平滑切换页面
✅ 中间按钮跳转独立功能页(如发布内容)
✅ 支持徽标、选中高亮、图标切换
由于小程序页面是全屏渲染,我们无法像 H5 那样用 fixed 布局直接覆盖原生 tabBar。
正确做法:
⚠️ 注意:自定义 tabBar 不是全局组件,需在每个 tab 页面中手动引入!
components/
└── custom-tab-bar/
├── custom-tab-bar.js
├── custom-tab-bar.json
├── custom-tab-bar.wxml
└── custom-tab-bar.wxss
{
"component": true,
"usingComponents": {}
}
Component({
properties: {
current: {
type: Number,
value: 0
}
},
data: {
// tab 配置(可抽离为常量)
tabs: [
{
pagePath: "/pages/home/index",
text: "首页",
icon: "home",
selectedIcon: "home-fill"
},
{
pagePath: "/pages/category/index",
text: "分类",
icon: "category",
selectedIcon: "category-fill"
},
{
pagePath: "/pages/publish/index",
text: "",
icon: "add",
isCenter: true
},
{
pagePath: "/pages/cart/index",
text: "购物车",
icon: "cart",
selectedIcon: "cart-fill"
},
{
pagePath: "/pages/my/index",
text: "我的",
icon: "my",
selectedIcon: "my-fill"
}
]
},
methods: {
switchTab(e) {
const { index } = e.currentTarget.dataset;
const item = this.data.tabs[index];
if (item.isCenter) {
wx.navigateTo({ url: '/pages/publish/index' });
return;
}
wx.switchTab({ url: item.pagePath });
this.triggerEvent('change', { index });
}
}
});
💡 提示:图标建议使用字体图标(如 IconFont)或本地 PNG
<!-- components/custom-tab-bar/custom-tab-bar.wxml -->
<view class="tab-bar">
<view wx:for="{{tabs}}" wx:key="index" class="tab-item {{current === index ? 'active' : ''}} {{item.isCenter ? 'center-btn' : ''}}" bindtap="switchTab">
<view class="icon-wrapper">
<image src="/assets/icons/{{current === index ? item.selectedIcon : item.icon}}.png" mode="aspectFit" />
<!-- 示例:购物车徽标 -->
<view wx:if="{{index === 3 && cartCount > 0}}" class="badge">{{cartCount}}</view>
</view>
<text wx:if="{{!item.isCenter}}">{{item.text}}</text>
</view>
</view>
/* components/custom-tab-bar/custom-tab-bar.wxss */
.tab-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 100rpx;
display: flex;
justify-content: space-around;
align-items: center;
background: white;
border-top: 1px solid #eee;
padding-bottom: env(safe-area-inset-bottom);
z-index: 999;
}
.tab-item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
position: relative;
}
.center-btn {
position: relative;
top: -40rpx; /* 凸起效果 */
width: 120rpx;
height: 120rpx;
background: #007aff;
border-radius: 50%;
box-shadow: 0 4rpx 12rpx rgba(0,122,255,0.3);
}
.center-btn .icon-img {
width: 56rpx;
height: 56rpx;
}
.icon-img {
width: 48rpx;
height: 48rpx;
}
.tab-text {
font-size: 20rpx;
margin-top: 8rpx;
color: #888;
}
.active .tab-text {
color: #007aff;
}
.badge {
position: absolute;
top: -8rpx;
right: -8rpx;
background: #ff3b30;
color: white;
border-radius: 50%;
min-width: 24rpx;
height: 24rpx;
font-size: 16rpx;
display: flex;
align-items: center;
justify-content: center;
padding: 0 2rpx;
}
// pages/home/index.json
{
"usingComponents": {
"custom-tab-bar": "/components/custom-tab-bar/custom-tab-bar"
}
}
<!-- pages/home/index.wxml -->
<view class="page-container">
<!-- 页面内容 -->
<view>首页内容</view>
</view>
<!-- 底部 tabBar -->
<custom-tab-bar current="0" bindchange="onTabChange" />
⚠️ 注意:每个 tab 页面都要引入,并传入对应的 current(0,1,3,4)
// pages/home/index.js
Page({
data: {
cartCount: 5 // 示例:从全局状态获取
},
onTabChange(e) {
// 如果需要同步 current(一般不需要)
console.log('切换到 tab:', e.detail.index);
}
});
A:因为 switchTab 只能跳转到 app.json 中配置的 tabBar 页面,而发布页通常不是 tab 页面,所以用 navigateTo。
A:可通过全局状态(如 globalData、Event Bus 或 Store)传递数据到 tabBar 组件。
A:在页面最外层加 padding-bottom: 100rpx + safe-area:
.page-container {
min-height: 100vh;
padding-bottom: calc(100rpx + env(safe-area-inset-bottom));
box-sizing: border-box;
}

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online