uniapp微信小程序切換tabbar報錯:switchTab:fail timeout是為什么?
wx.switchTab跳轉(zhuǎn)成功,但tabBar選中狀態(tài)需要點兩次才會切換正常?
針對以上兩個常見的問題,以下代碼指出問題所在
<template>
<view class="custom-tabbar">
<template v-for="(item, index) in tabbarList" :key="index">
<view
v-if="item.isSpecial"
class="tabbar-item relative top-21rpx left-8rpx"
:class="{ active: currentIndex === index }"
@click="changeTab(item, index)"
>
<image
class="w-80rpx h-80rpx mb-10rpx"
:src="currentIndex === index ? item.selectedIconPath : item.iconPath"
mode="scaleToFill"
></image>
<text class="text-22rpx">{{ item.text }}</text>
</view>
<view
v-else
class="tabbar-item relative top-38rpx"
:class="{ active: currentIndex === index }"
@click="changeTab(item, index)"
>
<image
class="w-56rpx h-56rpx"
:src="currentIndex === index ? item.selectedIconPath : item.iconPath"
mode="scaleToFill"
></image>
<text class="text-22rpx">{{ item.text }}</text>
</view>
</template>
</view>
</template>
<script lang="ts" setup>
const tabbarList = ref([
{
iconPath: `https://yanzhouedu-1330414272.cos.ap-guangzhou.myqcloud.com/2025/02/25/f30d1aa588d54f7abcd2c8876800dba8.png`,
selectedIconPath: `https://yanzhouedu-1330414272.cos.ap-guangzhou.myqcloud.com/2025/02/25/7a39f803563c40dbbcd3e91f2ae8fbdb.png`,
pagePath: '/pages/home/index',
text: '首頁',
badge: 0,
isDot: false,
},
{
iconPath: `https://yanzhouedu-1330414272.cos.ap-guangzhou.myqcloud.com/2025/02/25/6372fa14d5a745f78a1891e0d92c6a2d.png`,
selectedIconPath: `https://yanzhouedu-1330414272.cos.ap-guangzhou.myqcloud.com/2025/02/25/87a638c8d7e841a7aef8178f496121ed.png`,
pagePath: '/pages/reserve/index',
text: '預(yù)留',
badge: 0,
isDot: false,
},
{
iconPath: `https://yanzhouedu-1330414272.cos.ap-guangzhou.myqcloud.com/2025/02/25/1bb14fd255e64b22a5265dfde7509e06.png`,
selectedIconPath: `https://yanzhouedu-1330414272.cos.ap-guangzhou.myqcloud.com/2025/02/25/1bb14fd255e64b22a5265dfde7509e06.png`,
pagePath: '/pages/selfStudy/index',
text: '自習(xí)',
isSpecial: true,
badge: 0,
isDot: false,
},
{
iconPath: `https://yanzhouedu-1330414272.cos.ap-guangzhou.myqcloud.com/2025/02/25/dc356ca488cc42c2806e68e638f8b0e6.png`,
selectedIconPath: `https://yanzhouedu-1330414272.cos.ap-guangzhou.myqcloud.com/2025/02/25/3a765bd86f2743029bc53bfe4075094b.png`,
pagePath: '/pages/accompany/index',
text: '陪伴',
badge: 0,
isDot: false,
},
{
iconPath: `https://yanzhouedu-1330414272.cos.ap-guangzhou.myqcloud.com/2025/02/25/62f26d0570f546289d4c74f7ead1ec52.png`,
selectedIconPath: `https://yanzhouedu-1330414272.cos.ap-guangzhou.myqcloud.com/2025/02/25/e8c96e491dcb4aa4826fd8509ca482c1.png`,
pagePath: '/pages/me/index',
text: '我的',
badge: 0,
isDot: false,
},
])
const currentIndex = ref(0)
function changeTab(item, index) {
console.log(item.pagePath, index)
//錯誤原因:由于 手動維護(hù)的選中狀態(tài) 和 uni.switchTab 的頁面跳轉(zhuǎn)邏輯 不同步造成
currentIndex.value = index
uni.switchTab({
url: item.pagePath
})
}
</script >
<style lang="scss" scoped>
.custom-tabbar {
position: fixed;
left: 0;
right: 0;
bottom: 0;
display: flex;
align-items: center;
flex-wrap: nowrap;
background-image: url('https://yanzhouedu-1330414272.cos.ap-guangzhou.myqcloud.com/2025/02/25/f117faba0b4843ec986e70b04045bee7.png');
background-size: cover;
background-repeat: no-repeat;
background-position: top center;
height: 74px;
padding-bottom: env(safe-area-inset-bottom);
box-sizing: content-box;
.tabbar-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: #a3abd8;
&.active {
color: #30a4d7;
}
}
}
</style>
在 Uniapp 中使用自定義 TabBar 時出現(xiàn)選中狀態(tài)需要兩次點擊才能切換的問題,通常是由于 手動維護(hù)的選中狀態(tài) 和 uni.switchTab 的頁面跳轉(zhuǎn)邏輯 不同步造成的。以下是原因分析和解決方案:
問題原因分析
同步代碼與異步跳轉(zhuǎn)的時序沖突
同步代碼立即執(zhí)行:currentIndex.value = index 是同步代碼,立即生效,此時 TabBar 的選中狀態(tài)會瞬間切換到目標(biāo)索引。
異步跳轉(zhuǎn)延遲完成:uni.switchTab 是異步操作,觸發(fā)頁面跳轉(zhuǎn)后,實際頁面切換需要時間(如加載新頁面、執(zhí)行生命周期鉤子等)。
關(guān)鍵問題:在跳轉(zhuǎn)完成前,currentIndex 的更新可能被后續(xù)邏輯覆蓋。頁面生命周期鉤子覆蓋狀態(tài)
目標(biāo)頁面的 onShow 未正確更新狀態(tài):
當(dāng) uni.switchTab 跳轉(zhuǎn)完成后,目標(biāo)頁面會觸發(fā) onShow 生命周期鉤子。
若未在 onShow 中根據(jù)當(dāng)前路徑更新 currentIndex,則可能出現(xiàn)以下情況:
跳轉(zhuǎn)前手動設(shè)置的 currentIndex(如 index=1)已生效。
跳轉(zhuǎn)完成后,目標(biāo)頁面未通過 onShow 更新 currentIndex(例如,仍保留舊值)。
結(jié)果:TabBar 的選中狀態(tài)可能被重置為舊值,導(dǎo)致顯示狀態(tài)與實際路徑不一致。框架內(nèi)部狀態(tài)與手動狀態(tài)的競爭
原生 TabBar 與自定義 TabBar 的邏輯沖突:
uni.switchTab 是小程序原生 API,它可能隱式更新原生 TabBar 的狀態(tài)(即使原生 TabBar 被隱藏)。
若自定義 TabBar 的 currentIndex 未與原生邏輯完全解耦,可能導(dǎo)致:
手動設(shè)置的 currentIndex 短暫生效。
原生邏輯完成后(如頁面跳轉(zhuǎn)),框架內(nèi)部狀態(tài)覆蓋了 currentIndex。
表現(xiàn):第一次點擊時,自定義 TabBar 狀態(tài)短暫切換后又被重置,需要第二次點擊才能同步
解決方案
方案 1:在跳轉(zhuǎn)成功回調(diào)中更新狀態(tài)
利用 uni.switchTab 的 success 回調(diào),確保頁面跳轉(zhuǎn)完成后再更新狀態(tài)。
function changeTab(item, index) {
uni.switchTab({
url: item.pagePath,
success: () => {
// 跳轉(zhuǎn)成功后再更新選中狀態(tài)
currentIndex.value = index;
},
fail: (err) => {
console.error('跳轉(zhuǎn)失敗:', err);
}
});
}
方案 2:完全由頁面路徑控制選中狀態(tài)
放棄手動維護(hù) currentIndex,改為在頁面的 onShow 生命周期中,根據(jù)當(dāng)前頁面路徑動態(tài)計算選中索引(或路徑字符串)。
//方案2.1:通過索引同步狀態(tài)
// 在自定義 TabBar 組件中
const routes = [
'pages/home/index',
'pages/reserve/index',
'pages/selfStudy/index',
'pages/accompany/index',
'pages/me/index',]; // TabBar 頁面路徑列表
// 在頁面生命周期中同步狀態(tài)
onShow() {
// 獲取當(dāng)前頁面路徑
const currentRoute = getCurrentPages().pop()?.route || '';
// 根據(jù)路徑計算選中索引
currentIndex.value = routes.findIndex(path => currentRoute.includes(path));
}
//方案2.2:通過字符串路徑同步狀態(tài)
// 修改后:currentIndex 存儲路徑字符串
const currentIndex = ref<string>('/pages/home/index');
<!-- 模板中判斷選中狀態(tài) -->
<view :class="{ 'active': currentIndex === item.pagePath }"></view>
// 在頁面生命周期中同步狀態(tài)
onShow(() => {
const pages = getCurrentPages();
currentIndex.value = `/${pages[pages.length - 1].route}`; // 或根據(jù)真實路徑更新
});
方案 3:wot-design-uni 的 tabbar 標(biāo)簽欄組件實現(xiàn)
<template>
<view class="custom-tabbar">
<wd-tabbar
:model-value="currRoute"
fixed
:bordered="false"
safeAreaInsetBottom
placeholder
active-color="#30A4D7"
inactive-color="#A3ABD8"
@change="onTabbarChange"
>
<template v-for="item in tabbarStore.tabbarList" :key="item.pagePath">
<wd-tabbar-item
custom-class="relative top--12rpx left-8rpx"
v-if="item.isSpecial"
:name="item.pagePath"
:title="item.text"
>
<template #icon="{ active }">
<image
:src="active ? item.selectedIconPath : item.iconPath"
class="size-80rpx"
mode="scaleToFill"
/>
</template>
</wd-tabbar-item>
<wd-tabbar-item v-else :name="item.pagePath" :title="item.text">
<template #icon="{ active }">
<image
class="size-56rpx"
:src="active ? item.selectedIconPath : item.iconPath"
mode="scaleToFill"
/>
</template>
</wd-tabbar-item>
</template>
</wd-tabbar>
</view>
</template>
<script lang="ts" setup>
import useTabbarStore from '@/store/tabbar'
const tabbarStore = useTabbarStore()
const activePages = getCurrentPages() //uniapp中獲取當(dāng)前頁面路徑的API
const currRoute = ref<string>()
function onTabbarChange(item) {
uni.switchTab({
url: `${item.value}`,
})
}
onLoad(() => {
currRoute.value = `/${activePages[activePages.length - 1].route}`
})
</script>
<style lang="scss" scoped>
.custom-tabbar {
position: fixed;
left: 0;
right: 0;
bottom: 0;
display: flex;
align-items: center;
flex-wrap: nowrap;
background-image: url('https://yanzhouedu-1330414272.cos.ap-guangzhou.myqcloud.com/2025/02/25/f117faba0b4843ec986e70b04045bee7.png');
background-size: cover;
background-repeat: no-repeat;
background-position: top center;
height: 74px;
padding-bottom: env(safe-area-inset-bottom);
box-sizing: content-box;
}
</style>
注意事項:
pages.config.ts文件中tabBar配置iconPath和selectedIconPath必須要填且不能是https鏈接形式(可以填寫本地路徑:static/images/tabbar/home.png),否則微信開發(fā)者工具預(yù)覽二維碼會報下面的錯
Error: 系統(tǒng)錯誤,錯誤碼:800059,error: iconPath=, file not?