小智 ESP32 服务端 Manager-Mobile Tabbar 四策略详解:原生导航、缓存自定义与无缓存方案的选型与实现指南
2026/9/24 13:49:15 网站建设 项目流程
  • 后端
  • 物联网
  • 语音
  • 人工智能
  • AI 应用
  • AI Agent
  • RAG

【免费下载链接】xiaozhi-esp32-server

本项目为xiaozhi-esp32提供后端服务,帮助您快速搭建ESP32设备控制服务器。Backend service for xiaozhi-esp32, helps you quickly build an ESP32 device control server.

项目地址:https://gitcode.com/gh_mirrors/xia/xiaozhi-esp32-server
点击查看免费下载

本文围绕小智 ESP32 服务端移动端管理应用(manager-mobile)中底部导航栏(tabbar)的四种实现策略展开,系统讲解「无 tabbar」「原生 tabbar」「有缓存自定义 tabbar」「无缓存自定义 tabbar」四种方案的能力边界、优缺点与源码级实现细节。读者读完可以掌握该模板中 tabbar 策略的切换方式、tabbarList.ts的核心配置字段、图标渲染机制以及页面缓存与路由切换的底层原理,从而为自己的 uni-app 项目选型并落地合适的底部导航方案。

一、背景:tabbar 在 Manager-Mobile 中的位置

在小智 ESP32 服务端项目中,manager-mobile 是基于 uni-app(Vue 3 + TypeScript)构建的移动端管理应用,主要包含首页、配网、系统设置等页面。其底部导航栏的实现集中收敛在一个独立目录中:

main/manager-mobile/src/layouts/fg-tabbar/ ├── fg-tabbar.vue # 自定义 tabbar 渲染组件 ├── tabbar.md # 四种策略说明文档(本文核心依据) ├── tabbar.ts # tabbar 选中状态(reactive + storageSync) └── tabbarList.ts # 策略开关、tabbar 列表与 pages.json tabBar 配置

其中 tabbar.md 明确了 tabbar 分为4 种情况(策略),分别用数字 0、1、2、3 标识;而 tabbarList.ts 中的TABBAR_MAP常量正是这四种策略的程序化映射。二者一一对应,是理解整个 tabbar 体系的钥匙。

二、四种 tabbar 策略总览

根据 tabbar.md,四种策略的核心差异集中在三个维度:是否显示底部导航栏页面是否有缓存切换底层 API(switchTab还是navigateTo

策略值名称切换 API页面缓存导航栏形态
0无 tabbar无(单页面入口)底部不显示 tabbar
1原生 tabbarswitchTab系统原生 tabbar
2有缓存自定义 tabbarswitchTab第三方 UI 库 tabbar 组件,隐藏原生 tabbar
3无缓存自定义 tabbarnavigateTo第三方 UI 库 tabbar 组件

在源码 tabbarList.ts 中,四种策略被定义为:

export const TABBAR_MAP = { NO_TABBAR: 0, // 无 tabbar NATIVE_TABBAR: 1, // 完全原生 tabbar CUSTOM_TABBAR_WITH_CACHE: 2, // 有缓存自定义 tabbar CUSTOM_TABBAR_WITHOUT_CACHE: 3, // 无缓存自定义 tabbar } // TODO:通过这里切换使用tabbar的策略 export const selectedTabbarStrategy = TABBAR_MAP.NATIVE_TABBAR

当前仓库默认启用的是策略 1(原生 tabbar),开发者只需修改selectedTabbarStrategy这一处即可在四种策略间切换。

三、策略 0:无 tabbar(临时活动页场景)

适用场景:只有一个页面入口,底部不显示任何 tabbar,常用于临时活动页、落地页、引导页等单页场景。

  • 优势:页面形态最纯粹,不受底部导航约束,适合全屏沉浸式展示;
  • 注意点:此策略下tabbarList不生效(源码注释明确标注「NO_TABBAR(0) 时,tabbarList 不生效」)。

从实现上看,当selectedTabbarStrategy = 0时,tabbarList.ts 中cacheTabbarEnablefalse,因此最终导出的tabBarundefinedpages.json中不会生成tabBar配置,也就不会渲染任何底部导航:

// 0和1 需要显示底部的tabbar的各种配置,以利用缓存 export const tabBar = cacheTabbarEnable ? _tabbar : undefined

四、策略 1:原生 tabbar(默认策略)

适用场景:页面结构稳定、追求首屏渲染速度与性能的常规业务 App。

原生 tabbar 是框架(uni-app / 微信小程序等)内置的底部导航,通过switchTab进行页面切换:

  • 优势:原生自带,最先渲染,加载最快;页面有缓存,切换不丢失状态;
  • 劣势:图标只能使用 2 组图片(未选中iconPath与选中selectedIconPath)来切换状态;修改颜色只能重新替换图片(或借助 iconfont 变通),扩展定制能力有限。

对应源码配置位于 tabbarList.ts:

const _tabbar: TabBar = { // 只有微信小程序支持 custom。App 和 H5 不生效 custom: selectedTabbarStrategy === TABBAR_MAP.CUSTOM_TABBAR_WITH_CACHE, color: '#e6e6e6', selectedColor: '#667dea', backgroundColor: '#fff', borderStyle: 'black', height: '50px', fontSize: '10px', iconWidth: '24px', spacing: '3px', list: tabbarList as unknown as TabBar['list'], }

原生策略下每个 tab 项需要提供两张图片。仓库中已内置三组 tab 图标(static/tabbar):robot/robot_activate(首页)、network/network_activate(配网)、system/system_activate(系统),分别对应iconPathselectedIconPath字段。

说明:策略 1 与策略 2 均通过switchTab切换,因此cacheTabbarEnable在两者下都为true,从而保证pages.json生成原生tabBar配置以复用框架缓存能力。

五、策略 2:有缓存自定义 tabbar

适用场景:既需要switchTab带来的页面缓存,又希望拥有高度可定制的图标、配色与动效。

该策略使用第三方 UI 库(本项目为 wot-design-uni 的wd-tabbar)渲染自定义 tabbar,并隐藏原生 tabbar的显示:

  • 优势:可随意配置自己想要的 SVG icon,切换字体颜色方便;页面有缓存;可以实现各种自定义动效;
  • 劣势:首次点击 tabbar 会闪烁(自定义组件渲染与页面切换存在时序差)。

自定义 tabbar 的渲染在 fg-tabbar.vue 中完成,切换逻辑如下:

function selectTabBar({ value: index }: { value: number }) { const url = tabbarList[index].path tabbarStore.setCurIdx(index) if (cacheTabbarEnable) { uni.switchTab({ url }) // 策略 2:有缓存 } else { uni.navigateTo({ url }) // 策略 3:无缓存 } }

同时,页面onLoad时会主动隐藏原生 tabbar,避免出现「两个 tabbar 叠加」的问题:

onLoad(() => { // 解决原生 tabBar 未隐藏导致有2个 tabBar 的问题 const hideRedundantTabbarEnable = selectedTabbarStrategy === TABBAR_MAP.CUSTOM_TABBAR_WITH_CACHE hideRedundantTabbarEnable && uni.hideTabBar({ fail(err) { console.log('hideTabBar fail: ', err) }, success(res) { console.log('hideTabBar success: ', res) }, }) })

此外需注意custom: truecustom字段只有微信小程序支持,App 端与 H5 端不生效(见 tabbarList.ts 注释)。

六、策略 3:无缓存自定义 tabbar

适用场景:同样需要自定义图标与配色,但可以接受页面状态不保留的轻量场景。

  • 优势:可随意配置 SVG icon,切换字体颜色方便,可实现自定义动效;
  • 劣势:首次点击 tabbar 会闪烁,且页面无缓存——因为底层使用的是navigateTo(每次切换都会重新创建页面实例),而非switchTab

从代码逻辑看,策略 3 与策略 2 在渲染层完全一致(都走wd-tabbar),唯一区别是cacheTabbarEnablefalse,从而切换走uni.navigateTo分支。该策略适合对状态保留要求不高的页面组合,避免因缓存带来额外内存开销。

七、核心配置详解:tabbarList.ts

tabbarList.ts 是整个 tabbar 体系的「总控文件」,承担三类职责:策略开关、列表数据、pages.json 的 tabBar 注入

7.1 列表数据结构与图标类型

type FgTabBarItem = TabBar['list'][0] & { icon: string iconType: 'uiLib' | 'unocss' | 'iconfont' }

当前内置的三个 tab 项(tabbarList.ts):

页面文本原生图标(iconPath / selectedIconPath)自定义图标(icon / iconType)
pages/index/index首页robot.png / robot_activate.pnghome / uiLib
pages/device-config/index配网network.png / network_activate.pngi-carbon-network-3 / uiLib
pages/settings/index系统system.png / system_activate.pngi-carbon-settings / uiLib

源码注释明确了三条配置约定(tabbarList.ts):

  • 策略 1(原生)时:需要填iconPathselectedIconPath两张图片;
  • 策略 2/3(自定义)时:需要填iconiconType
  • 策略 0(无 tabbar)时:tabbarList不生效。

7.2 四种图标渲染方式

在 fg-tabbar.vue 模板中,wd-tabbar-item根据iconType分四种情况渲染图标:

  • uiLib:直接使用 UI 框架(wot-design-uni)自带的 icon 组件,如:icon="item.icon"
  • unocss:使用 UnoCSS 原子类(h-40rpx w-40rpx)配合图标类名,并通过is-active/is-inactive切换选中态样式;
  • iconfont:使用 iconfont 字体图标,同样以 class 方式渲染;
  • local:使用本地图片资源,通过<image :src="item.icon" />渲染。

值得注意的是,模板中还支持了文档未单独列出的local(本地图片)渲染分支,说明自定义 tabbar 的图标方案实际上比文档列举的 svg/iconfont 更灵活,还可以直接放本地图片。

7.3 缓存开关与 tabBar 注入

// NATIVE_TABBAR(1) 和 CUSTOM_TABBAR_WITH_CACHE(2) 时,需要tabbar缓存 export const cacheTabbarEnable = selectedTabbarStrategy === TABBAR_MAP.NATIVE_TABBAR || selectedTabbarStrategy === TABBAR_MAP.CUSTOM_TABBAR_WITH_CACHE

cacheTabbarEnable是一个派生开关:只有策略 1、2 为true。它同时决定了三件事——switchTab分支、原生 tabbar 是否显示、以及pages.json中是否注入tabBar配置。

八、页面状态管理:tabbar.ts

自定义 tabbar 的选中索引由一个轻量状态对象维护(tabbar.ts):

export const tabbarStore = reactive({ curIdx: uni.getStorageSync('app-tabbar-index') || 0, setCurIdx(idx: number) { this.curIdx = idx uni.setStorageSync('app-tabbar-index', idx) }, })

这里有两个设计要点:

  1. 刻意不用 Pinia:注释明确说明「使用 reactive 简单状态,而不是 pinia 全局状态」,因为 tabbar 索引是极简的 UI 状态,引入全局 store 反而增加复杂度;
  2. storageSync 持久化:每次设置curIdx都会同步写入app-tabbar-index,这样刷新浏览器(H5 端)或重启小程序时,能恢复到正确的 tabbar 页面,避免「刷新后回到默认页」的体验断裂。

九、与 pages.config.ts 的集成

uniapp 项目中页面与 tabBar 的声明通过 pages.config.ts 完成,该文件在构建时生成pages.json

import { defineUniPages } from '@uni-helper/vite-plugin-uni-pages' import { tabBar } from './src/layouts/fg-tabbar/tabbarList' export default defineUniPages({ // ... // tabbar 的配置统一在 "./src/layouts/fg-tabbar/tabbarList.ts" 文件中 tabBar: tabBar as any, })

由此形成了一条清晰的配置链路:

tabbarList.ts(策略 + 列表 + tabBar 对象) └── pages.config.ts(注入 tabBar → 生成 pages.json) └── 页面路由声明与原生 tabbar 渲染

源码在 tabbarList.ts 中给出了一条重要提醒:本文件的任何代码更改之后,都需要重新运行(重新构建),否则pages.json不会更新导致错误。这是切换策略时最常见的坑,务必牢记。

十、布局集成:default.vue 与 tabbar.vue

项目中存在两套布局(src/layouts):

  • default.vue:仅提供wd-config-providerwd-toastwd-message-box等全局能力,不渲染 tabbar
  • tabbar.vue:在 default 基础上额外引入<FgTabbar />组件(fg-tabbar.vue),用于自定义 tabbar 策略的页面布局。

在 fg-tabbar.vue 中,只有当策略为 2 或 3(自定义 tabbar)时才渲染wd-tabbar组件:

const customTabbarEnable = selectedTabbarStrategy === TABBAR_MAP.CUSTOM_TABBAR_WITH_CACHE || selectedTabbarStrategy === TABBAR_MAP.CUSTOM_TABBAR_WITHOUT_CACHE

wd-tabbar开启safe-area-inset-bottom(安全区适配)、borderedplaceholderfixed等属性,兼顾 iPhone 底部安全区与页面占位,避免内容被固定导航遮挡。

十一、路由拦截器对 tabbar 切换的兼容

项目在 router/interceptor.ts 中注册了全局路由拦截器(基于黑名单的登录拦截),并通过uni.addInterceptor同时拦截了navigateToreLaunchredirectToswitchTab四种跳转方式:

uni.addInterceptor('navigateTo', navigateToInterceptor) uni.addInterceptor('reLaunch', navigateToInterceptor) uni.addInterceptor('redirectTo', navigateToInterceptor) uni.addInterceptor('switchTab', navigateToInterceptor)

这意味着无论采用switchTab(策略 1/2)还是navigateTo(策略 3)进行 tab 切换,都会被登录拦截逻辑统一覆盖,切换 tabbar 策略不会造成路由鉴权漏洞;且拦截器对 url 做了规范化处理(相对路径转绝对路径),与 fg-tabbar.vue 中「path 从 pages.config.ts 得到,并补全/前缀」的约定一致。

十二、实操指南:如何切换与验证

结合源码,切换 tabbar 策略只需两步:

  1. 修改策略开关:在 tabbarList.ts 中修改selectedTabbarStrategyTABBAR_MAP中的 0/1/2/3 之一;
  2. 重启/重新构建项目:由于pages.json由构建期生成,修改后必须重新运行,否则配置不生效。

同时按策略补齐字段:

  • 策略 1:确认每个 tab 项都填了iconPathselectedIconPath(图片位于 static/tabbar);
  • 策略 2/3:确认填了iconiconType,并根据uiLib/unocss/iconfont/local四种类型准备对应的图标资源;
  • 策略 2:微信小程序端生效custom: true,App/H5 端不生效,需注意平台差异。

十三、选型建议与总结

结合文档的优劣势说明与源码实现,四种策略的选型建议如下:

  • 策略 0(无 tabbar):仅用于单页入口、临时活动页、引导页等场景;
  • 策略 1(原生 tabbar):默认推荐。追求首屏性能与页面缓存,对图标样式要求不高时优先选择,代价是定制能力弱(仅两组图片);
  • 策略 2(有缓存自定义):需要「缓存 + 高度定制」时的最佳折中,代价是首次点击闪烁、且custom配置在微信小程序外不生效;
  • 策略 3(无缓存自定义):当页面无需保留状态、且希望自定义能力最大化时使用,代价是每次切换都会重建页面。

总结来看,小智 ESP32 服务端的 manager-mobile 通过 tabbarList.ts 这一个「策略总控」文件,将四种 tabbar 方案的切换成本压缩到了极致:一处常量、一次重启、按策略补齐图标字段即可完成切换。这种「配置驱动、组件收敛」的设计,配合switchTab/navigateTo的 API 差异与storageSync的状态持久化,为同类 uni-app 项目的底部导航实现提供了一个结构清晰、易于维护的参考范本。至于动效等「花里胡哨」的效果,正如 tabbar.md 末尾的提示所说:需要开发者自行实现,模板本身并不提供。

  • 后端
  • 物联网
  • 语音
  • 人工智能
  • AI 应用
  • AI Agent
  • RAG

【免费下载链接】xiaozhi-esp32-server

本项目为xiaozhi-esp32提供后端服务,帮助您快速搭建ESP32设备控制服务器。Backend service for xiaozhi-esp32, helps you quickly build an ESP32 device control server.

项目地址:https://gitcode.com/gh_mirrors/xia/xiaozhi-esp32-server
点击查看免费下载

相关推荐

上一篇:MongoDB内存服务器使用教程
下一篇:NgRx 数据管理在Angular中的实战指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询