微信小程序案例 - 自定义 tabBar

一、前言

微信小程序原生的 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(组件配置)

{ "component": true }

✅ 3. tab-bar.wxml(组件结构)

<view> <block wx:for="{{list}}" wx:key="index"> <viewactive' : ''}}" bindtap="switchTab" > <image src="{{currentIndex == index ? item.selectedIconPath : item.iconPath}}" mode="aspectFit"/> <text>{{item.text}}</text> </view> </block> </view>

✅ 4. tab-bar.wxss(组件样式)

.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(组件逻辑)

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 中引入组件:

{ "usingComponents": { "custom-tab-bar": "/components/custom-tab-bar/tab-bar" } }

✅ 2. index.wxml 中使用组件

<view> <!-- 页面主体内容 --> <swiper current="{{currentTab}}" duration="300"> <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 页面逻辑

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. 添加阴影效果(可选)

.tab-bar { box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1); }

八、实战扩展:中间凸起按钮(如“发布”按钮)

如果希望实现类似小红书或抖音的中间凸起按钮,可以修改 tab-bar.wxml 如下:

<view> <block wx:for="{{list}}" wx:key="index"> <viewactive' : ''}}" bindtap="switchTab" > <image src="{{currentIndex == index ? item.selectedIconPath : item.iconPath}}" mode="aspectFit"/> <text>{{item.text}}</text> </view> </block> <!-- 中间按钮 --> <view bindtap="onCenterClick"> <image src="/images/icon-publish.png" mode="aspectFit"/> <text>发布</text> </view> </view>

并在 tab-bar.wxss 中添加样式:

.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 扩展能力
开发复杂度简单中等
维护成本中等

十一、结语

感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!

Read more

【前端】前端面试题

【前端】前端面试题

前端面试题 闭包 1. 定义: 闭包(Closure) 是指一个函数能够访问并记住其外部作用域中的变量,即使外部函数已经执行完毕。闭包由两部分组成: * 一个函数(通常是内部函数)。 * 该函数被创建时所在的作用域(即外部函数的变量环境) functionouter(){let count =0;// 外部函数的变量functioninner(){ count++;// 内部函数访问外部变量 console.log(count);}return inner;}const counter =outer();counter();// 输出 1counter();// 输出 2 2. 闭包的核心原理 * 作用域链:函数在定义时,会记住自己的词法环境(即外部作用域)。当内部函数访问变量时,会沿着作用域链向上查找。 * 变量持久化:闭包使得外部函数的变量不会被垃圾回收,因为内部函数仍持有对它们的引用 3. 闭包的常见用途 3.1 私有变量封装 通过闭包隐藏内部变量,

【技术干货】用 Claude 4.6 直接“写”出可上线的前端 UI:从画布工具到代码工作流的升级思路

【技术干货】用 Claude 4.6 直接“写”出可上线的前端 UI:从画布工具到代码工作流的升级思路

摘要 本文从 Google Stitch 热度切入,对比“AI 画布式 UI 生成”与“代码内 UI 生成”两种路径,系统拆解如何用 Claude 4.6 + 前端设计规则,在真实代码库中迭代出可上线的 UI。附完整 Python API 调用示例与提示词模板,并结合多模型平台薛定猫 AI 的接入方式,帮助前端/全栈开发者把 AI UI 生成直接融入开发流水线。 一、背景:从“好看截图”到“可上线 UI” 当前 AI UI 方向大致两类路径: 1. 画布式设计工具 代表:Google Stitch

别再用 Electron 了!教你用 WebView2 实现 3MB 极致轻量化 Web 打包方案(附神器)

别再用 Electron 了!教你用 WebView2 实现 3MB 极致轻量化 Web 打包方案(附神器)

文章摘要:         你还在忍受 Electron 打包后动辄 100MB+ 的体积吗?你还在为本地 HTML 跨域(CORS)、源码保护、机器码授权而头秃吗?本文将带你体验微软新一代 WebView2 技术,并分享一款支持实时预览、全全局拖拽交互的打包神器。3MB 体积,1.5GB 大文件秒开,彻底解放前端生产力! 😱 为什么 2026 年了,我们还要逃离 Electron? 做前端桌面化开发,Electron 确实是老大哥,但它的缺点和优点一样明显: * 太胖了: 一个最简单的 Hello World,打包出来都要 150MB 起步。 * 太吃内存: 每个窗口都是一个 Chrome 进程,老爷机直接卡死。 * 开发繁琐: 想要实现“老板键”、“机器码授权”、“关机重启”,需要写大量的

基于.Net的Web API 控制器及方法相关注解属性

文章目录 * 1. 路由与 HTTP 方法 (`Microsoft.AspNetCore.Mvc` 命名空间) * 2. 参数绑定源 (`Microsoft.AspNetCore.Mvc` 命名空间) * 3. 响应类型与格式 (`Microsoft.AspNetCore.Mvc` 命名空间) * 4. 授权与认证 (`Microsoft.AspNetCore.Authorization` 命名空间) * 5. Swagger/OpenAPI 文档增强 (`Swashbuckle.AspNetCore.Annotations` 或 `Microsoft.AspNetCore.Mvc`) 这些属性主要用于定义 API 的路由、HTTP 方法、参数绑定、响应类型、授权、Swagger 文档等,通常位于控制器类或 Action