209 lines
7.1 KiB
Vue
209 lines
7.1 KiB
Vue
<template>
|
||
<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>
|
||
</template>
|
||
|
||
<script>
|
||
import { mapState, mapMutations } from 'vuex';
|
||
import request from "@/utils/request";
|
||
|
||
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: {
|
||
// 保留对消息数量的映射
|
||
...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;
|
||
}
|
||
}
|
||
// =================================================
|
||
},
|
||
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']),
|
||
|
||
// 设置全局选中索引(简化调用)
|
||
setCurrentTabIndex(index) {
|
||
this.SET_CURRENT_TAB_INDEX(index);
|
||
},
|
||
|
||
// 强制重建 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;
|
||
|
||
// 依然更新全局高亮,确保其他可能依赖 Vuex 状态的逻辑正常运行
|
||
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();
|
||
}
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style lang="scss">
|
||
.icon {
|
||
height: 54rpx;
|
||
width: 54rpx;
|
||
}
|
||
::v-deep .uv-tabbar__content {
|
||
z-index: 999 !important;
|
||
}
|
||
</style> |