Uniapp - 自定义 Tabbar 实现

222 阅读1分钟

场景复现

需要根据不同的业务场景显示不同的 Tabbar ,官方 Tabbar 配置无法支持,只能通过自定义 Tabbar 实现

解决方案

方案一

  1. 正常配置 Tabbar 页面,但需要将 Tabbar 隐藏
  "tabBar": {
    "custom": true,
    "list": [
      {
        "pagePath": "pages/home"
      },
      {
        "pagePath": "pages/test"
      }
    ]
  }

依然在 pages.json 中正常配置 Tabbar 页面,避免跳转 Tabbar 路径时出现默认的页面切换动画效果

微信小程序可使用 custom: true 隐藏( Uniapp 官方文档 目前并没有写明这个参数,但 微信小程序 原生支持)

微信小程序自定义 Tabbar developers.weixin.qq.com/miniprogram…

其他端可采用 uni.hideTabBar()Uniapp tabbar height 配置(小程序环境不支持)实现

  1. 自定义布局实现 Tabbar 相关逻辑即可

方案二

完全采用自定义动态组件方式实现

实现自定义 Tabbar 状态缓存

image.png

默认 Tabbar 页面是自带状态缓存的,自定义 Tabbar 实现由于 uni 在非 h5 端不支持 keep-alive<component /> ,需手动通过 v-ifv-show 实现(参考 antfu/v-lazy-show),通过 v-if 控制首次渲染,后续切换通过 v-show 控制,即可实现简易自定义 Tabbar 关联 页面/组件 状态缓存

示例:

<script setup>
const userTabbarMap = reactive({
  home: { label: '首页', icon: 'tabbar_home', rendered: false },
  teacher: { label: '教师', icon: 'tabbar_teacher', rendered: false },
  found: { label: '广场', icon: 'tabbar_found', rendered: false },
  mine: { label: '我的', icon: 'tabbar_mine', rendered: false },
})

/** TODO: 其他身份 tabbar 配置 */
const teacherTabbarMap = {}

const curTabbar = ref('')

watch(curTabbar, v => (userTabbarMap[v].rendered = true))

// 由具体业务逻辑控制
curTabbar.value = 'home'
</script>

<template>
  <view class="h-screen flex-(~ col)">
    <view class="flex-1 overflow-auto">
      <!-- 通过 v-if 控制首次渲染,后续切换通过 v-show 控制 -->
      <Home v-if="userTabbarMap.home.rendered" v-show="curTabbar === 'home'" />
      <Teacher v-if="userTabbarMap.teacher.rendered" v-show="curTabbar === 'teacher'" />
      <Found v-if="userTabbarMap.found.rendered" v-show="curTabbar === 'found'" />
      <Mine v-if="userTabbarMap.mine.rendered" v-show="curTabbar === 'mine'" />
    </view>

    <!-- tabbar -->
    <view class="h-15 bg-white flex">
      <view v-for="(v, k) in userTabbarMap" :key="k" @click="curTabbar = k" class="flex-1 flex-(~ col) justify-center items-center">
        <image :src="handleAssetsUrl(curTabbar === k ? `${v.icon}_active` : `${v.icon}`)" class="size-6.5" />
        <text class="text-(3 #999) mt-.5" :class="{ '!text-#000': curTabbar === k }">{{ v.label }}</text>
      </view>
    </view>
  </view>
</template>

参考

github.com/antfu/v-laz…

github.com/dcloudio/un…