mrr.sj.front/components/tabbar/tabbar.vue

209 lines
7.1 KiB
Vue
Raw Normal View History

2026-03-24 11:45:13 +08:00
<template>
2026-05-27 15:45:10 +08:00
<uv-tabbar
v-if="tabbarReady"
:key="refreshKey"
fixed
:value="currentTabIndex"
@change="onTabChange"
activeColor="#FF4767"
:placeholder="false"
:safeAreaInsetBottom="false"
:customStyle="{height:'110rpx'}"
>
<uv-tabbar-item
v-for="(item, idx) in tabbarList"
:key="idx"
:name="idx"
:text="item.text"
:badge="getNum(idx)"
:customStyle="{height:'110rpx'}"
@click="onItemClick(idx)"
>
<template v-slot:active-icon>
<image class="icon" :src="item.selectedIconPath"></image>
</template>
<template v-slot:inactive-icon>
<image class="icon" :src="item.iconPath"></image>
</template>
</uv-tabbar-item>
</uv-tabbar>
2026-03-24 11:45:13 +08:00
</template>
<script>
2026-05-27 15:45:10 +08:00
import { mapState, mapMutations } from 'vuex';
import request from "@/utils/request";
2026-03-25 13:34:16 +08:00
2026-05-27 15:45:10 +08:00
export default {
name: "tab-bar",
// 不再需要 props.selected完全由 Vuex 控制高亮
data() {
return {
refreshKey: 0, // 强制重建标识
tabbarReady: false, // 组件就绪标识
tabbarList: [ // tab 配置
{
iconPath: "/static/images/tabbar/new_home_gray.png",
text: "首页",
selectedIconPath: "/static/images/tabbar/new_home.png",
pagePath: "/pages/home/home"
},
{
iconPath: "/static/images/tabbar/new_order_gray.png",
text: "订单",
selectedIconPath: "/static/images/tabbar/new_order.png",
pagePath: "/pages/order/all-orders"
},
{
iconPath: "/static/images/tabbar/new_message_gray.png",
text: "消息",
selectedIconPath: "/static/images/tabbar/new_message.png",
pagePath: "/pages/message/message"
},
{
iconPath: "/static/images/tabbar/new_my_gray.png",
text: "我的",
selectedIconPath: "/static/images/tabbar/new_my.png",
pagePath: "/pages/my/my"
}
]
};
},
computed: {
2026-05-27 16:38:14 +08:00
// 保留对消息数量的映射
...mapState(['messageNum']),
// ========= 动态计算当前高亮索引 =========
// 替代原先直接获取 Vuex 的方式,改为根据当前真实路由计算,解决刷新状态丢失问题
currentTabIndex() {
try {
// 获取当前页面栈
const pages = getCurrentPages();
if (pages && pages.length > 0) {
// 获取当前页面实例
const currentPage = pages[pages.length - 1];
// 拼接当前页面路径(兼容不同平台获取路由的方式)
const currentPath = '/' + (currentPage.route || currentPage.__route__);
// 在 tabbarList 中查找匹配当前路径的索引
const index = this.tabbarList.findIndex(item => item.pagePath === currentPath);
if (index !== -1) {
return index;
}
}
// 如果由于某些原因匹配不到,降级去取 Vuex 中的值(防止其他极端情况报错)
return this.$store.state.currentTabIndex || 0;
} catch (e) {
return this.$store.state.currentTabIndex || 0;
}
}
// =================================================
2026-05-27 15:45:10 +08:00
},
watch: {
// 当 tabbarList 内容变化(如异步更新图标)时,强制重建组件
tabbarList: {
deep: true,
handler() {
this.rebuildTabbar();
}
}
},
created() {
// 初始化时延迟显示,避免闪烁
this.tabbarReady = false;
this.$nextTick(() => {
this.tabbarReady = true;
// 如果需要异步加载图标,取消下面注释
// this.getButtonImg();
});
},
methods: {
...mapMutations(['SET_CURRENT_TAB_INDEX']),
2026-03-25 13:34:16 +08:00
2026-05-27 15:45:10 +08:00
// 设置全局选中索引(简化调用)
setCurrentTabIndex(index) {
this.SET_CURRENT_TAB_INDEX(index);
},
2026-03-24 11:45:13 +08:00
2026-05-27 15:45:10 +08:00
// 强制重建 uv-tabbar用于异步更新图标后
rebuildTabbar() {
this.tabbarReady = false;
this.$nextTick(() => {
this.refreshKey++;
this.tabbarReady = true;
});
},
// 获取角标数字(只有消息 tab 且数量 > 0 才显示)
getNum(index) {
if (index === 2 && this.messageNum > 0) {
return this.messageNum;
}
return null;
},
// 异步更新图标(保留你的业务逻辑)
async getButtonImg() {
try {
let res = await request.post("/sj/poster/getButtonImg", {});
if (res.code === 200) {
this.tabbarList.forEach((item, index) => {
if (res.data[index]?.iconPath) {
item.iconPath = res.data[index].iconPath;
}
if (res.data[index]?.selectedIconPath) {
item.selectedIconPath = res.data[index].selectedIconPath;
}
});
this.$store.commit("setTabbarList", this.tabbarList);
// 图标更新后,强制重建组件
this.rebuildTabbar();
}
} catch (err) {
console.error('getButtonImg 请求失败', err);
}
},
// uv-tabbar 的 change 事件(组件内部触发)
onTabChange(val) {
const idx = parseInt(val, 10);
this.doJump(idx);
},
// 手动点击 item 时触发
onItemClick(idx) {
this.doJump(idx);
},
// 实际跳转逻辑 + 更新全局高亮
doJump(index) {
const idx = parseInt(index, 10);
if (isNaN(idx) || !this.tabbarList[idx]) return;
2026-05-27 16:38:14 +08:00
// 依然更新全局高亮,确保其他可能依赖 Vuex 状态的逻辑正常运行
2026-05-27 15:45:10 +08:00
this.setCurrentTabIndex(idx);
// 跳转页面
const targetPage = this.tabbarList[idx].pagePath;
uni.switchTab({
url: targetPage,
fail: (err) => console.error('switchTab 失败', err)
});
// 保留你原有的消息更新方法
if (typeof this.messageUpudateNum === 'function') {
this.messageUpudateNum();
}
}
}
};
2026-03-24 11:45:13 +08:00
</script>
<style lang="scss">
2026-05-27 15:45:10 +08:00
.icon {
height: 54rpx;
width: 54rpx;
}
::v-deep .uv-tabbar__content {
z-index: 999 !important;
}
2026-03-24 11:45:13 +08:00
</style>