ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

unibest + uview-plus 下 tabBar 图标不显示?完整排查与解决方案

2026/9/9 1:00:24 拓冰建站 浏览量
unibest + uview-plus 下 tabBar 图标不显示?完整排查与解决方案 unibest uview-plus 这套组合最近在 uni-app 社区里讨论热度很高尤其从老项目往 Vue3 Vite 迁移的同学基本都会遇到一个问题pages.json 里 tabBar 配置得好好的四个导航项的文字都出来了但底部图标就是不展示。这个问题看着不大排查起来却很头疼因为它在 H5 端正常、在微信小程序端不正常或者本地开发正常、打生产包后不正常。今天把我的排查路径和最终落地的几种完整方案整理出来覆盖 90% 以上的“tabbar icon 不展示”场景希望能帮大家少走弯路。这篇内容适合正在用 unibest 搭建项目、集成了 uview-plus、遇到底部导航图标消失的同学也适合打算把老 uni-app 项目迁移到 unibest 框架的开发者。我会从最基础的路径规则讲起逐步深入到自定义 tabbar、字体图标的坑内容比较全建议收藏后对着自己的项目一步步检查。1. 先别急着改代码30 秒定位问题边界遇到 tabbar 图标不显示我建议先花 30 秒做一次“问题边界确认”避免瞎改代码越改越乱。需要确认的无非三点是所有图标都不显示还是只有某一张不显示是开发环境下不显示还是生产构建后不显示是 H5 端、小程序端还是 App 端不显示。这三个维度直接决定了排查方向。1.1 是全部图标不显示还是只有某一个不显示如果四个 tab 的文字全部正常、而图标全部空白大概率是路径或资源打包的问题——pages.json 里 iconPath 指向了一个编译后不存在的文件或者整个 static 目录没有被正确复制到产物中。如果只有某一个图标不显示那就要重点检查那张图本身。最常见的情况是文件名大小写写错了。Windows 和 macOS 上开发时文件系统不区分大小写iconPath 写成 Home.png 或者 home.png 都能加载但到了 Linux 构建机、或者微信小程序的某些资源处理流程里大小写不匹配就会直接导致图片加载失败。另外还要看看那个文件的后缀是不是 png/jpg格式不对也可能出现“有占位、无图”的现象。还有一种容易被忽视的情况未选中图标正常、选中图标不显示或者反过来。这种情况说明 iconPath 和 selectedIconPath 的配置不对称比如只写了选中态、漏了未选中态或者两张图的实际文件名和配置不一致。我在 uview-plus 的 Tabbar 组件里就没少见过这种写法list 数据里 iconPath 和 selectedIconPath 各写各的结果有一张图找不到。1.2 开发环境正常、生产环境不显示先怀疑构建链路同一个项目在本地 dev server 预览时图标是好的一旦执行 npm run build 后图标全部消失这类问题在 unibest 这种基于 Vite 的 CLI 工程里尤其常见。原因通常是两个方向一个是 base 和 publicPath 相关配置在构建时把静态资源的绝对路径改写错了另一个是静态资源没有被打包进产物目录dist 里根本没有对应的 images 文件夹。排查方法很简单直接用编辑器打开构建后的产物目录找到对应平台的 pages.json比如微信小程序是 dist/build/mp-weixin/pages.json看 tabBar 里的 iconPath 字段究竟是相对路径、绝对路径还是已经被改写过的 hash 路径。同时看一眼产物目录里有没有 static/tabbar 这些东西。这一步能帮你快速区分是路径规则不对还是构建配置把资源漏了。如果是 H5 端构建后不显示还要留意 Vite 的 base 配置。项目部署在子目录时资源加载路径不对往往表现为 tabbar 图标丢失或裂图页面其他图片也可能一起出问题。2. 根因一unibest 的 src 目录结构把 iconPath 的路径带沟里了unibest 和 HBuilderX 创建的传统 uni-app 项目有一个非常大的不同它的源码目录是 srcpages.json 在 src/pages.jsonstatic 目录也在 src/static。很多从传统项目迁过来的人习惯了直接写 static/tabbar/home.png结果在 unibest 里图标就是不显示。这其实是路径敏感性的典型例子。2.1 pages.json 里 iconPath 到底该写什么先说结论在 unibest 的 src 目录结构下pages.json 中 tabBar 的 iconPath 推荐写带前导斜杠的形式比如tabBar: { color: #999999, selectedColor: #FF4A57, backgroundColor: #ffffff, list: [ { pagePath: pages/home/index, text: 首页, iconPath: /static/tabbar/home.png, selectedIconPath: /static/tabbar/home-active.png }, { pagePath: pages/mine/index, text: 我的, iconPath: /static/tabbar/mine.png, selectedIconPath: /static/tabbar/mine-active.png } ] }注意上一段代码中 pagePath 的写法pages/home/index 对应 src/pages/home/index.vue这里不需要写 .vue 后缀也不需要写 src 前缀。为什么是 /static 而不是 static因为 uni-app 编译时会以项目根目录为基准解析 pages.json 里的资源路径。在 unibest 的 src 结构下src 会被视为虚拟的根目录编译时 src/static 会被映射为最终产物的 static。而 iconPath 如果写 static/tabbar/home.png不带斜杠个别平台尤其是小程序会把路径解析成当前页面目录下的相对路径结果找不到文件。2.2 从编译产物反推路径规则如果你不确定自己写的路径对不对最快的办法是看编译产物。以微信小程序为例执行构建后打开 dist/build/mp-weixin/pages.json搜索 tabBar。如果编译系统正常识别你会看到 iconPath 已经被改写为 static/tabbar/home.png 或 tabs/home.png 之类的相对路径并且该路径对应的文件一定存在于 dist/build/mp-weixin/static/tabbar/ 下。把源工程里的路径表达式和产物里的路径一对比就能立刻看出问题出在哪个环节。我见过的最离谱的一个例子是有人写了 ../../static/tabbar/home.png。在小程序端编译时这个相对路径被原样保留产物里根本不存在对应的层级图标自然全部消失。所以在 unibest 项目里尽量不要写相对路径统一写“/static/xxx.png”最干净H5、小程序、App 三个端都不会出大问题。2.3 static 目录到底该放哪些资源不该放哪些资源在 unibest 中pages.json 引用的 tabbar 图标、页面 launch 图等公共静态资源一定放在 src/static 下。被页面内部引用的图片资源虽然也可以放 static但更规范的做法是放到对应页面目录或者 assets 下面由 Vite 按需处理。如果一张图片只在某个页面用一次却扔进了 static会导致小程序主包体积变大因为 static 目录默认会整体拷入产物。建议的目录结构src/ ├── static/ │ └── tabbar/ │ ├── home.png │ ├── home-active.png │ ├── mine.png │ └── mine-active.png ├── pages/ │ ├── home/index.vue │ └── mine/index.vue └── pages.json另外文件名统一用小写字母加连字符或下划线比如 home-active.png而不要用“首页.png”或者“Home 图标.png”这种带空格、中文、大写混排的文件名。之前我有个项目在 macOS 上开发一切正常推到 Git 后在 CI 的 Linux 机器上构建tabbar 图标全体“失踪”文件名大小写变异是罪魁祸首。3. 根因二uview-plus 的 Tabbar 组件和原生 tabBar 撞车了如果你的项目里集成了 uview-plus并且不止配置了 pages.json 里的原生 tabBar还在页面里引入了 uview-plus 的 Tabbar 组件那问题可能就不是资源路径了。这两套东西同时在底部渲染会出现视觉上的重叠、空白、甚至导航错乱乍一看也像是“图标不展示”。3.1 原生 tabBar 和自定义 tabbar到底有什么区别原生 tabBar 是 uni-app 框架基于各端系统组件实现的底部导航你在 pages.json 里加几行配置框架就在每个页面的底部渲染出导航条。它的优点是性能好、跳转关系由框架管理、各端表现统一缺点是定制能力弱想加个中间凸起的发布按钮、改图标选中动画、做角标都比较费劲。自定义 tabbar 则是在 pages.json 里设置 custom: true 后由开发者自己写一个 Vue 组件来完全控制底部导航的渲染。所有图标、文字、点击逻辑、角标都得自己实现。uview-plus 提供的 Tabbar 组件就是为这种场景准备的。如果在 pages.json 里没有设置 custom: true同时又在一个普通页面里手动引入并渲染了 uview-plus 的 Tabbar 组件页面底部就会出现两条导航条。考虑到 uview-plus 的 Tabbar 图标本身需要传入图标名或图片地址一旦 icon 属性传的是空值或非法名称就会出现“原生导航文字正常、自定义导航图标空白”的混乱局面。3.2 uview-plus 的 Tabbar 组件在什么场景下才值得用我的建议是能用原生 tabBar 解决的需求就不要上自定义 tabbar。只有当你确实需要以下能力时才考虑 uview-plus 的 Tabbar中间需要凸起的特殊按钮或者两侧按钮不对称图标需要配合业务状态动态切换比如购物车数量角标导航栏需要根据登录态、角色权限动态改变展示项需要更复杂的字体图标、渐变色、动效uview-plus Tabbar 的典型用法是通过 :list 传入一个数组每个元素包含 name、title、icon或者 iconPath、selectedIconPath同时用 v-model 或 :value 绑定当前选中项。比如template u-tabbar :valuecurrent :listlist changeonChange/u-tabbar /template script setup langts import { ref } from vue const current ref(0) const list [ { name: home, title: 首页, icon: home }, { name: mine, title: 我的, icon: account } ] function onChange(name: string) { console.log(切到, name) } /script这里的 icon 字段传的是 uview-plus 内置图标名不是图片路径。如果你之前用惯了 Element UI 那种图标 name 管理方式uview-plus 也有自己的图标列表文档在官方图标库里查好名称直接用就行。但如果有人习惯性传了 icon: home.png 或者一个不存在的图标名渲染时就会得到一个空白或方框。3.3 样式串扰导致的“假不显示”还有一类诡异情况图标文件本身没问题、路径也对但在 uview-plus 全局样式的影响下tabbar 图标被遮挡或者渲染为透明。这就是样式串扰导致的“假不显示”。常见触发器是自定义了 tabbar 组件的 z-index、opacity或者外层容器设置了 overflow: hidden、高度为 0。我之前排查过一个项目底部导航其实一直存在但高度只有 44rpx 的一半因为某个全局样式把 .u-tabbar 的高度覆盖了图标和文字被挤在可视区域外。开发者工具里一看 Elements元素在但高度只有十几像素图标被切掉了。排查这类问题的方法也很简单打开 Web 开发者工具或小程序开发者工具选中底部导航元素查看它渲染的位置、尺寸、可见性。如果元素存在但尺寸不正常优先检查全局样式中有没有对 tabbar 相关类名做了覆盖。uview-plus 的主题定制能力很强但这也意味着一旦配置不当组件样式会被整体改动不只是颜色变了尺寸和布局也会受影响。4. 根因三图标文件自身的格式与字体图标陷阱路径没错、组件也没冲突图标还是不显示那就要把目光放到图标文件本身了。tabbar 图标有潜在的格式限制很多人不知道导致辛辛苦苦切出来的 SVG 图标在页面上能显示但 tabbar 里就是不行。4.1 tabbar 图标的格式、尺寸与体积硬指标uni-app 官方对原生 tabBar 的图标要求比较明确iconPath 和 selectedIconPath 支持 png、jpg、jpeg 格式不支持 svg、gif、webp。尤其是 svg很多前端设计师偏爱 svg但在原生 tabBar 里直接配 svg小程序端基本不渲染H5 端时好时坏这是最典型的“图标不展示”原因之一。尺寸方面官方推荐 81px × 81px单张图不超过 40kb。实际开发中我一般做成双倍图再压缩用 162×162 的源图导出最后压缩到 81×81保证在 iOS 和 Android 不同屏幕上都能清晰显示。如果原图过大有的小程序平台会静默失败表现同样是图标空白。如果你手头只有一张大尺寸的 PNG建议用图像处理工具把尺寸压到标准值并重新导出。工具上可以用 Greenfish Icon Editor Pro 之类的免费软件功能不算强大但对 PNG 导出这类的需求足够关键是能控制透明背景和输出尺寸还能勾选“删除元数据”选项把体积降下来。4.2 为什么 iconfont 字体图标在原生 tabBar 里只有文字没有图标这是社区里最高频的一个误区。很多人在网上搜到“tabbar 可以用图标字体”于是把字体图标的 class 直接写进原生 tabBar 的 iconPath结果当然是没效果。原生 tabBar 不认 CSS class也不认字体它只认图片路径。如果你确实需要用 iconfont 字体图标唯一的正规路线是放弃原生 tabBar改用自定义 tabbar 组件把字体图标以 class 或 unicode 形式写在组件内部。或者使用 uview-plus 的 Tabbar通过 icon 字段传入内置字体图标名由组件内部的 u-icon 负责渲染。强调一下iconPath 字段永远只能填图片路径不能填字体类名、不能填 unicode、不能写 base64。这个限制在小程序端尤其严格H5 端有时可以蒙混过关但你不会希望自己的 tabbar 在部分端上随机失灵。4.3 uni-icons 和 uview-plus 图标体系的使用注意uni-app 官方有 uni-icons 这套字体图标uview-plus 也有自己的 u-icon。它们本质上都是字体图标渲染依赖字体文件。如果你在自定义 tabbar 里用了uni-icons typehome size24 color#999 /之后图标没有显示第一件事不是检查图标名而是检查字体文件有没有被正确加载。在 unibest 这种 CLI 工程里组件库一般通过 npm 安装字体文件由组件库内部管理。如果你在使用 uni-icons 时没有引入对应的样式文件比如 import uni-icons/uni-icons.css或者把组件库版本升级后没清缓存字体加载失败后图标就会显示成方块或空白但文字内容依然存在。uview-plus 也一样需要确保 main.ts 里正确导入了 uview-plus 的样式和配置。这里给一个自查步骤打开页面的 Network 面板搜索 woff、ttf、eot 这些字体文件请求看有没有 404 或加载失败的记录。如果请求本身就不存在说明样式文件没引进来如果请求 404说明字体文件的路径在构建后被写错了。5. 三套完整解法按需取用理论讲得差不多了下面是实操。根据你项目的实际需求选择一个方案落地。我平时做项目时的推荐顺序是默认方案一需要复杂交互再方案二图标有很强品牌定制需求再方案三。5.1 方案一原生 tabBar 规范 png 图片求稳首选如果只是要一个标准的底部导航不需要特殊样式用原生 tabBar 加静态图片是最省心的方案。第一步把图标按要求准备好。用图像工具导出一套 81×81 像素的 png 图标包含未选中和选中两套分别放到 src/static/tabbar/ 目录下。第二步编辑 src/pages.json配置 tabBar 属性。完整示例{ pages: [ { path: pages/home/index, style: { navigationBarTitleText: 首页 } }, { path: pages/mine/index, style: { navigationBarTitleText: 我的 } } ], tabBar: { color: #999999, selectedColor: #FF4A57, backgroundColor: #ffffff, borderStyle: black, list: [ { pagePath: pages/home/index, text: 首页, iconPath: /static/tabbar/home.png, selectedIconPath: /static/tabbar/home-active.png }, { pagePath: pages/mine/index, text: 我的, iconPath: /static/tabbar/mine.png, selectedIconPath: /static/tabbar/mine-active.png } ] } }第三步重新运行或构建。如果之前已经跑过老版本建议先清缓存再启动避免旧产物干扰。微信小程序端记得在开发者工具里“清缓存 - 清除文件缓存”。这套方案的好处是各端表现一致几乎不会出现图标不展示的怪问题缺点是 tabbar 样式无法高度定制选中图标颜色需要提前做成两张图。5.2 方案二自定义 tabbar uview-plus Tabbar 组件灵活定制需要中间凸起、动态角标、多端差异化样式时用 uview-plus 的 Tabbar 组件重写底部导航。先修改 pages.json{ tabBar: { custom: true, color: #999999, selectedColor: #FF4A57, backgroundColor: #ffffff, list: [ { pagePath: pages/home/index, text: 首页 }, { pagePath: pages/mine/index, text: 我的 } ] } }注意即使 custom 为 truelist 依然要写全页面路径和文字因为框架需要根据它注册导航关系。然后在组件目录里创建一个 CustomTabbar.vue外层容器用来模拟原生 tabbar 的位置。一个最基础的实现template view classcustom-tabbar u-tabbar :valuecurrent :listlist changeonChange/u-tabbar /view /template script setup langts import { ref } from vue const props defineProps{ current: number }() const emit defineEmits{ (e: change, index: number): void }() const list [ { name: home, title: 首页, icon: home }, { name: mine, title: 我的, icon: account } ] function onChange(name: string) { const index list.findIndex((item) item.name name) emit(change, index) } /script style scoped .custom-tabbar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 999; } /style接下来在每个 tab 页面引入这个组件并传当前页面对应的 current 值点击切换时再用 uni.switchTab 跳转。比如在首页template view CustomTabbar :current0 changeonTabChange / /view /template script setup langts import CustomTabbar from /components/CustomTabbar.vue function onTabChange(index: number) { if (index 1) { uni.switchTab({ url: /pages/mine/index }) } } /script需要注意“自定义 tabbar uview-plus Tabbar”这套组合里图标名一定要填写 uview-plus 内置图标库中存在的名字不确定时可以查看官方图标列表页面。用 uview-plus Tabbar 的好处是选中切换的动画、角标、红点这些能力都是现成的icon 名对应内置字体图标颜色会自动跟随选中状态不用维护两张 png。缺点是需要手动管理每个页面的 current 和跳转逻辑比原生 tabBar 多写不少代码。5.3 方案三iconfont 字体图标 自定义 tabbar品牌定制团队里有设计师或者你希望 tabbar 图标风格和整体设计系统完全统一用 iconfont 字体图标是长久之计。第一步到 iconfont 平台选择或上传图标生成项目的字体文件下载压缩包。把其中的 iconfont.ttf 放到 src/static/fonts/ 下。第二步在自定义 tabbar 组件里引入字体和样式style font-face { font-family: tabbar-font; src: url(/static/fonts/iconfont.ttf) format(truetype); } .tabbar-icon { font-family: tabbar-font !important; font-size: 24px; font-style: normal; } /style第三步模板里用类名或 unicode 渲染template view classcustom-tabbar view v-for(item, index) in menuList :keyitem.text classtabbar-item clickonSwitch(index) view classtabbar-icon :classcurrent index ? item.activeClass : item.class/view text classtabbar-text{{ item.text }}/text /view /view /template这套方案的可定制性最强图标颜色、大小通过 CSS 控制图标名称管理也清晰。但它依赖字体文件正常加载在部分小程序平台的字体引用路径需要额外处理比如将字体文件转为 base64 丢进 CSS或者确保服务器能返回正确的 MIME 类型。如果不能接受这个复杂程度建议回到方案一。6. 常见问题与排查技巧实录最后把我在多个 unibest uview-plus 项目中实际遇到的问题整理成速查表再分享几个印象深刻的排查过程。6.1 问题速查表现象可能原因解决办法所有 tabbar 图标都不显示pages.json 里 iconPath 路径在编译后失效改成 /static/xxx.png并确认文件在 src/static 下只有某个图标不显示文件名大小写不一致或格式不对统一小写命名确认 png/jpg 格式H5 开发正常build 后不显示Vite base 配置问题检查 base 是否为 ./重新构建并强刷小程序开发工具正常真机不显示旧缓存、文件没打进主包清缓存重新编译检查 static 目录是否在产物中原生 tabBar 下用字体类名不显示原生 tabBar 只认图片路径改用图片或自定义 tabbar自定义 tabbar 图标变方框字体文件未加载成功检查样式是否引入、字体文件是否打包底部导航存在但图标被切一半全局样式覆盖了组件尺寸检查 z-index、height、overflow杜绝全局样式污染选中态和未选中态只有一种显示iconPath 与 selectedIconPath 配置不完整两个字段都补全6.2 我实际踩过的坑与解决过程先说一个 H5 端的经典坑。项目用的是 unibest部署在服务器子目录下本地 dev 一切正常npm run build 之后 tabbar 图标全没了。打开浏览器控制台发现静态资源的请求路径全部指向了根目录 /static/...而不是子目录下的路径。我把 Vite 配置里的 base 改成了 ./重新构建后图标恢复正常。这个问题其实和 unibest 没有直接关系但遇到“开发正常、部署后不显示”的时候优先检查这一项。再说一个 uview-plus 的坑。我在一个项目里引入了 uview-plus 的 Tabbar 组件list 里传的是自定义的 iconPath 图片路径但渲染出来只有文字没有图。后来翻源码才发现uview-plus 的 TabbarItem 在同时有 icon 和 iconPath 时会优先处理 icon 属性而 icon 传的是一个不存在的图标名导致字体图标渲染失败。把 icon 字段删除、只保留 iconPath问题就解决了。还有一个印象很深的微信小程序端坑。tabbar 图标在开发者工具里完全正常真机预览时却少了两张。后来发现这两张图片是从某个素材网站下载的虽然也是 png但文件内部其实包含了 alpha 通道的异常数据微信小程序真机的图片解码器对它兼容性不好。处理办法是把图片重新导出一遍勾选“删除元数据”和“重新压缩 alpha 通道”文件从一百多 KB 压到二十几 KB真机上就正常显示了。最后分享一个排查小技巧遇到 tabbar 图标问题先不要碰代码把开发者工具打开在网络面板或资源面板里找到 tabbar 对应的图片请求看它有没有加载、返回码是多少、路径指向哪里。这一步能排除掉至少一半的路径问题。如果资源请求都不存在就说明 pages.json 里的配置没有生效或者编译产物有问题优先去检查编译配置而不是图片本身。这套排查逻辑我后来在几个从 HBuilderX 老项目迁到 unibest 的项目里反复验证过效果很稳定。核心就一句话先确认路径规则再检查组件冲突最后排查文件本身大多数 tabbar icon 不展示的问题都能在三步之内定位。如果你也用 unibest 加 uview-plus建议从一开始就把 tabbar 图标放到 src/static/tabbar 下统一命名、统一尺寸后续能省不少事。最后再分享一个小技巧改完 tabbar 配置后最好执行一次完整的重新构建而不是增量刷新别问我为什么试过的都知道。