Skip to content

Tabbar 权限机制梳理(用于说明白“还有 tabbar 的权限”这一块)

  • 路由来源与当前模块识别

    • 各个 tab 页(商城首页、租赁管理首页、餐饮工作台等)在各自页面的 onShow 里写入当前路由到 Pinia:
      • 典型代码(比如 [Workbench.vue](file:///d:/work/code/wat-front-end-h5/src/pages/community/workbench/Workbench.vue#L336-L357)、[BuildingList.vue](file:///d:/work/code/wat-front-end-h5/src/pages/rental-manage/building/BuildingList.vue#L742-L761)、[Mine.vue](file:///d:/work/code/wat-front-end-h5/src/pages/rental-manage/mine/Mine.vue#L13-L22)):
        ts
        const commonStore = useCommonStore()
        const { ctx } = getCurrentInstance()
        onShow(() => {
          commonStore.setCommonData('curTabbarRoute', ctx.route)
          commonStore.setCommonData('isUpdateTabbar', false)
        })
    • useTabbar 钩子里通过 curTabbarRoute 反推出“当前属于哪个业务模块”:
      • 预先把所有 tabbar 项按模块归类成 modulePagePaths
        ts
        const modulePagePaths = computed(() => {
          const map: Record<TabbarItem['module'], string[]> = {
            default: [],
            rentalManage: [],
            mealAdmin: [],
          }
          tabbarList.value.forEach((item) => {
            map[item.module].push(item.pagePath)
          })
          return map
        })
      • 根据当前路由查找到所属模块:
        ts
        const currentModule = computed(() => {
          const currentPagePath = curTabbarRoute.value
          return (
            (Object.entries(modulePagePaths.value).find(([_, paths]) =>
              paths.includes(currentPagePath),
            )?.[0] as TabbarItem['module']) || 'default'
          )
        })
  • 按模块过滤 Tabbar(模块级权限控制)

    • useTabbar 中定义完整的 tabbarList,每一项标记 module: 'default' | 'rentalManage' | 'mealAdmin'(见 [useTabbar.ts](file:///d:/work/code/wat-front-end-h5/src/hooks/useTabbar.ts#L1-L121))。
    • 再通过 currentModule 计算出当前模块下应该显示的 tabbar 项:
      ts
      const filteredTabbarList = computed(() => {
        return tabbarList.value.filter((item) => item.module === currentModule.value)
      })
    • WatTabbar 组件只渲染 filteredTabbarList(见 [WatTabbar.vue](file:///d:/work/code/wat-front-end-h5/src/components/wat-tabbar/WatTabbar.vue#L1-L35)):
      vue
      <wd-tabbar :model-value="curTabbarRoute" @change="handleTabbarChange">
        <block v-for="(item, index) in filteredTabbarList" :key="index">
          <!-- 根据 iconType 决定展示方式,这里略 -->
        </block>
      </wd-tabbar>
    • 这样一来:
      • 当当前路由在 默认商城 模块时,只能看到商城相关 tab(首页/商城/购物车/停车优惠/我的)。
      • 当当前路由在 租赁管理 模块时,只能看到租赁相关 tab(首页/房产/数据概览 等)。
      • 当当前路由在 餐饮管理 模块时,只能看到餐饮工作台、数据概览、订单等 tab。
    • 这个就是“模块级的 Tabbar 权限控制”:不同业务角色或业务入口进来后,只暴露与当前模块相关的底部导航,避免跨模块互相跳转。
  • Tabbar 高亮与路由联动

    • useTabbar 中通过 watch(curTabbarRoute) 在路由变化时自动维护 active 状态:
      ts
      const setTabbarItemActive = () => {
        for (const item of tabbarList.value) {
          item.active = item.pagePath === curTabbarRoute.value
        }
        commonStore.setCommonData('isUpdateTabbar', true)
      }
      
      watch(
        () => curTabbarRoute.value,
        () => {
          if (isUpdateTabbar.value) return
          setTabbarItemActive()
        },
        { immediate: true },
      )
    • WatTabbar 使用 curTabbarRoute 作为 wd-tabbarmodel-value,并在 @change 事件中调用 uni.switchTab({ url: \/${value}` })`,保证点击底部导航后走的是统一的 tabbar 路由切换逻辑。
  • Tabbar 与主题(皮肤)联动

    • [tabbar.vue](file:///d:/work/code/wat-front-end-h5/src/layouts/tabbar.vue#L1-L74) 中通过 useTabbar 拿到 currentModule,再配合 useTheme 做主题切换:
      ts
      const { currentModule } = useTabbar()
      const { theme, themeVars, switchTheme, toggleTheme } = useTheme()
      
      watchEffect(() => {
        switchTheme(currentModule.value)
      })
      
      const themeClass = computed(() => {
        switch (currentModule.value) {
          case 'rentalManage':
            return 'rental-theme'
          default:
            return 'mall-theme'
        }
      })
    • 同一套框架下,不同模块不仅 tabbar 不同,整体主题色、样式也一起切换,实现“模块隔离 + 视觉上也区分开”。
  • Web / App 自定义 Tabbar 替换原生

    • 底层用的是自定义 Tabbar Layout:
      • H5 端通过 Teleport 挂到 uni 原生 .uni-tabbar 的位置上,并主动移除原生 tabbar(见 [tabbar.vue](file:///d:/work/code/wat-front-end-h5/src/layouts/tabbar.vue#L27-L60))。
      • App 端在 onShow 里调用 uni.hideTabBar() 隐藏原生,再用自定义 Tabbar 占位。
    • 这样 route 拦截 + 自定义 tabbar 的权限过滤 是一套统一逻辑,保证多端行为一致。

简历第 4 点(整合登录拦截 + 路由拦截 + Tabbar 权限)的优化写法

下面给你一个直接可用的“第 4 点”版本,把你之前的登录/路由/权限这块和 Tabbar 权限一并说清楚(偏真实项目说明风格):

4)负责前端登录与权限体系设计与落地:基于 uni-app 的路由拦截统一做登录校验,按 pages 元信息动态生成登录白名单,未登录访问受保护页面时自动重定向到登录页并带上 redirect;在 HTTP 拦截器中统一处理 401,结合节流避免重复弹登录。封装基于 Pinia 的 useTabbar 钩子,将底部导航抽象为按业务模块(商城、租赁管理、餐饮管理)划分的配置表,通过当前路由反推所在模块并过滤可见 Tabbar 项,同时结合自定义 Tabbar + Teleport 替换原生 Tabbar,在 H5/APP 端实现“模块隔离的导航权限控制”和按模块切换主题皮肤。

如果你觉得太长,可以用一个稍微精简一点的版本:

4)搭建完整登录与前端权限体系:路由层通过白名单做登录拦截,401 由 HTTP 拦截器统一处理并引导重新登录;封装基于 Pinia 的 useTabbar,按业务模块(商城/租赁管理/餐饮管理)动态过滤底部导航项,并在 H5/APP 端用自定义 Tabbar 替换原生 Tabbar,实现多模块隔离的导航权限和主题切换。

你可以根据你简历整体篇幅选择“完整版”或“精简版”,内容上已经把“还有 tabbar 的权限”这一块融合进去了。