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",
|
2026-06-02 13:08:29 +08:00
|
|
|
|
pagePath: "/pages/order/userorder-list"
|
2026-05-27 15:45:10 +08:00
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
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>
|