ImageTabBar.vue 2.65 KB
<template>
  <view class="bar safe-bottom">
    <view
      v-for="item in items"
      :key="item.key"
      class="item"
      @click="go(item.path)"
    >
      <image
        class="ico"
        :src="current === item.key ? item.selectedIcon : item.icon"
        mode="aspectFit"
      />
      <text :class="['txt', current === item.key ? 'txt-on' : '']">{{
        item.text
      }}</text>
    </view>
  </view>
</template>

<script setup lang="ts">
import { getMpToken } from "@/utils/api/http";
import { getMpLoginChannel } from "@/utils/api/mpSession";
import { markUploadFormClearOnNextEnter } from "@/utils/uploadTabClear";

const props = defineProps<{
  current: "home" | "upload" | "user";
}>();

/* 小程序里自定义组件内图片需相对组件目录,否则 /static 可能加载失败;与 pages.json tabBar 同源文件 */
// #ifdef MP
const TAB = "../static/tabbar";
// #endif
// #ifndef MP
const TAB = "/static/tabbar";
// #endif

const items = [
  {
    key: "home" as const,
    path: "/pages/home/home",
    text: "首页",
    icon: `${TAB}/home.png`,
    selectedIcon: `${TAB}/home_on.png`,
  },
  {
    key: "upload" as const,
    path: "/pages/upload/upload",
    text: "上传",
    icon: `${TAB}/up.png`,
    selectedIcon: `${TAB}/up_on.png`,
  },
  {
    key: "user" as const,
    path: "/pages/user/user",
    text: "我的",
    icon: `${TAB}/my.png`,
    selectedIcon: `${TAB}/my_on.png`,
  },
];

function go(url: string) {
  // #ifdef MP-WEIXIN
  if (url === "/pages/upload/upload" || url === "/pages/user/user") {
    const ok = !!getMpToken() && getMpLoginChannel() === "weixin";
    if (!ok) {
      const tab = url.includes("upload") ? "upload" : "user";
      uni.reLaunch({ url: `/pages/login/login?tab=${tab}` });
      return;
    }
  }
  // #endif
  // 从上传页切到其他 tab 时再标记清空;选图/拍照也会触发页面 onHide,不能依赖 onHide 清表单
  if (props.current === "upload" && url !== "/pages/upload/upload") {
    markUploadFormClearOnNextEnter();
  }
  uni.switchTab({ url });
}
</script>

<style scoped>
.bar {
  position: fixed;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 50;
  display: flex;
  height: 100rpx;
  align-items: center;
  justify-content: space-around;
  border-top: 1rpx solid #e5e7eb;
  background: #fff;
  box-sizing: content-box;
}

.safe-bottom {
  padding-bottom: env(safe-area-inset-bottom);
}

.item {
  display: flex;
  flex: 1;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100rpx;
}

.ico {
  width: 48rpx;
  height: 48rpx;
}

.txt {
  margin-top: 6rpx;
  font-size: 22rpx;
  color: #6b7280;
}

.txt-on {
  color: #4a90e2;
  font-weight: 500;
}
</style>