一、前言
微信小程序原生的 tabBar 提供了底部导航栏的基础功能,但其样式和交互受限,难以满足日益增长的 UI 设计需求。因此,越来越多的小程序项目选择使用 自定义 tabBar 来实现更灵活、更美观的底部导航。
本文将带你从零开始,手把手实现一个完整的 微信小程序自定义 tabBar 案例,包括:
✅ tabBar 的结构设计
✅ 动态切换页面
✅ 图标与文字高亮状态管理
✅ 样式美化与响应式适配
✅ 页面跳转逻辑处理
✅ 完整代码示例
并通过图文结合的方式帮助你掌握如何在实际项目中灵活应用自定义 tabBar。
二、为什么需要自定义 tabBar?
| 原生 tabBar 局限 | 自定义 tabBar 优势 |
|---|---|
| 样式固定,无法修改图标大小、颜色等 | 可自由定制样式 |
| 最多只能配置 5 个 tab 页 | 灵活扩展,可做横向滚动 |
| 不支持中间凸起按钮 | 支持自定义布局 |
| 难以集成动态数据 | 可绑定数据、响应事件 |
三、项目目标
我们将实现一个类似美团风格的自定义 tabBar,包含以下功能模块:
| 模块 | 功能描述 |
|---|---|
| 底部导航栏 | 包含首页、分类、购物车、我的 四个 tab |
| 图标+文字 | 每个 tab 显示图标与文字 |
| 高亮状态切换 | 当前 tab 图标与文字变色 |
| 页面切换 | 点击 tab 切换对应页面内容 |
| 样式统一管理 | 使用公共样式文件控制主题 |
四、项目结构说明
project/
├── app.js
├── app.json
├── app.wxss
├── components/
│ └── custom-tab-bar/
│ ├── tab-bar.js
│ ├── tab-bar.json
│ ├── tab-bar.wxml
│ └── tab-bar.wxss
├── pages/
│ ├── index/
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ ├── category/
│ ├── cart/
│ └── user/
└── utils/
我们通过封装一个组件 custom-tab-bar 实现底部导航栏,并在主页中调用该组件。
五、自定义 tabBar 组件实现
✅ 1. 创建组件目录
components/custom-tab-bar/
├── tab-bar.js
├── tab-bar.json
├── tab-bar.wxml
└── tab-bar.wxss
✅ 2. tab-bar.json(组件配置)
javascript
{
"component": true
}
✅ 3. tab-bar.wxml(组件结构)
XML
<view class="tab-bar">
<block wx:for="{{list}}" wx:key="index">
<view
class="tab-bar-item {{currentIndex == index ? 'active' : ''}}"
bindtap="switchTab"
data-index="{{index}}"
data-path="{{item.pagePath}}"
>
<image class="icon" src="{{currentIndex == index ? item.selectedIconPath : item.iconPath}}" mode="aspectFit"/>
<text class="text">{{item.text}}</text>
</view>
</block>
</view>
✅ 4. tab-bar.wxss(组件样式)
css
.tab-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 98rpx;
display: flex;
justify-content: space-around;
align-items: center;
background-color: #fff;
border-top: 1rpx solid #eee;
}
.tab-bar-item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.icon {
width: 48rpx;
height: 48rpx;
margin-bottom: 6rpx;
}
.text {
font-size: 24rpx;
color: #666;
}
.tab-bar-item.active .text {
color: #ff6600;
}
✅ 5. tab-bar.js(组件逻辑)
javascript
Component({
properties: {
list: {
type: Array,
value: []
},
currentIndex: {
type: Number,
value: 0
}
},
methods: {
switchTab(e) {
const index = e.currentTarget.dataset.index;
const path = e.currentTarget.dataset.path;
this.triggerEvent('tabchange', { index, path });
}
}
});
六、在页面中使用自定义 tabBar
✅ 1. 引入组件
在 pages/index/index.json 中引入组件:
javascript
{
"usingComponents": {
"custom-tab-bar": "/components/custom-tab-bar/tab-bar"
}
}
✅ 2. index.wxml 中使用组件
XML
<view class="container">
<!-- 页面主体内容 -->
<swiper current="{{currentTab}}" duration="300" style="height:100%">
<swiper-item wx:for="{{tabPages}}" wx:key="index">
<block wx:if="{{currentTab == index}}">
<view wx:if="{{index == 0}}">首页内容</view>
<view wx:if="{{index == 1}}">分类内容</view>
<view wx:if="{{index == 2}}">购物车内容</view>
<view wx:if="{{index == 3}}">我的内容</view>
</block>
</swiper-item>
</swiper>
<!-- 自定义 tabBar -->
<custom-tab-bar
list="{{tabList}}"
currentIndex="{{currentTab}}"
bind:tabchange="onTabChange"
/>
</view>
✅ 3. index.js 页面逻辑
javascript
Page({
data: {
currentTab: 0,
tabList: [
{ text: '首页', iconPath: '/images/icon-home.png', selectedIconPath: '/images/icon-home-active.png', pagePath: 'index' },
{ text: '分类', iconPath: '/images/icon-category.png', selectedIconPath: '/images/icon-category-active.png', pagePath: 'category' },
{ text: '购物车', iconPath: '/images/icon-cart.png', selectedIconPath: '/images/icon-cart-active.png', pagePath: 'cart' },
{ text: '我的', iconPath: '/images/icon-user.png', selectedIconPath: '/images/icon-user-active.png', pagePath: 'user' }
],
tabPages: ['index', 'category', 'cart', 'user']
},
onTabChange(e) {
const { index, path } = e.detail;
this.setData({ currentTab: index });
// 可选:跳转到对应页面
// wx.navigateTo({ url: `/pages/${path}/${path}` });
}
});
七、样式优化建议
✅ 1. 图标尺寸统一
- 推荐使用 SVG 或 PNG 图标,统一尺寸为
48rpx x 48rpx - 高亮图标建议使用不同颜色区分
✅ 2. 文字颜色变化
- 默认颜色
#666 - 高亮颜色
#ff6600(橙色)或根据品牌色调整
✅ 3. 添加阴影效果(可选)
css
.tab-bar {
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1);
}
八、实战扩展:中间凸起按钮(如"发布"按钮)
如果希望实现类似小红书或抖音的中间凸起按钮,可以修改 tab-bar.wxml 如下:
XML
<view class="tab-bar">
<block wx:for="{{list}}" wx:key="index">
<view
class="tab-bar-item {{currentIndex == index ? 'active' : ''}}"
bindtap="switchTab"
data-index="{{index}}"
data-path="{{item.pagePath}}"
>
<image class="icon" src="{{currentIndex == index ? item.selectedIconPath : item.iconPath}}" mode="aspectFit"/>
<text class="text">{{item.text}}</text>
</view>
</block>
<!-- 中间按钮 -->
<view class="center-button" bindtap="onCenterClick">
<image class="icon" src="/images/icon-publish.png" mode="aspectFit"/>
<text class="text">发布</text>
</view>
</view>
并在 tab-bar.wxss 中添加样式:
css
.center-button {
position: absolute;
top: -20rpx;
left: 50%;
transform: translateX(-50%);
width: 100rpx;
height: 100rpx;
background-color: #ff6600;
border-radius: 50%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: #fff;
z-index: 10;
}
九、常见问题与解决方案
| 问题 | 原因 | 解决方案 |
|---|---|---|
| tabBar 不显示 | 组件未正确引入 | 检查 usingComponents 配置 |
| 切换无反应 | 未绑定 tabchange 事件 |
检查事件监听是否正确 |
| 图标路径错误 | 路径不正确 | 使用绝对路径或检查层级关系 |
| 页面未更新 | 数据未触发 setData |
检查数据绑定 |
| 无法点击中间按钮 | z-index 层级被遮挡 | 设置更高 z-index |
十、总结对比表:原生 vs 自定义 tabBar
| 特性 | 原生 tabBar | 自定义 tabBar |
|---|---|---|
| 样式灵活性 | ❌ | ✅ |
| 图标/文字自定义 | ❌ | ✅ |
| 中间凸起按钮 | ❌ | ✅ |
| 页面切换控制 | ✅ | ✅ |
| 多 tab 扩展能力 | ❌ | ✅ |
| 开发复杂度 | 简单 | 中等 |
| 维护成本 | 低 | 中等 |
十一、结语
感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!