refactor(utils&tabbar): 重构tabbar高亮逻辑与分包路径适配
1. 修复store中tabBarList初始值为null替代空字符串 2. 重构adaptSubpackageUrl,优化正则匹配与移除冗余映射 3. 新增路径归一化、分包名提取工具函数 4. 重写checkTabBarActive,新增精确匹配、packageEntryTab优先级匹配逻辑 5. 重构diy-bottom-nav组件的路由更新与高亮校验逻辑,统一路径处理流程
This commit is contained in:
@@ -1,45 +1,30 @@
|
||||
<template>
|
||||
<view data-component-name="diy-bottom-nav" v-if="shouldShowTabBar">
|
||||
<view class="tab-bar" :style="{ backgroundColor: tabBarList.backgroundColor }">
|
||||
<view class="tabbar-border"></view>
|
||||
<view class="item" v-for="(item, index) in tabBarList.list" :key="item.id" @tap.stop="redirectTo(item.link)">
|
||||
<view class="bd">
|
||||
<block v-if="item.link.wap_url == '/pages_goods/cart'">
|
||||
<view class="icon" v-if="tabBarList.type == 1 || tabBarList.type == 2"
|
||||
:animation="cartAnimation" id="tabbarCart">
|
||||
<block v-if="verify(item.link)">
|
||||
<image v-if="item.selected_icon_type == 'img'"
|
||||
:src="$util.img(item.selectedIconPath)" />
|
||||
<diy-icon v-if="item.selected_icon_type == 'icon'" :icon="item.selectedIconPath"
|
||||
:value="item.selected_style ? item.selected_style : null"></diy-icon>
|
||||
</block>
|
||||
<block v-else>
|
||||
<image v-if="item.icon_type == 'img'" :src="$util.img(item.iconPath)" />
|
||||
<diy-icon v-if="item.icon_type == 'icon'" :icon="item.iconPath"
|
||||
:value="item.style ? item.style : null"></diy-icon>
|
||||
</block>
|
||||
<view class="cart-count-mark font-size-activity-tag"
|
||||
:class="{ max: item.link.wap_url == '/pages_goods/cart' && cartNumber > 99 }"
|
||||
:style="{ background: 'var(--price-color)' }" v-if="cartNumber > 0">
|
||||
{{ cartNumber > 99 ? '99+' : cartNumber }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="tabbar-border"></view>
|
||||
<view class="item" v-for="(item, index) in tabBarList.list" :key="item.id" @tap.stop="redirectTo(item.link)">
|
||||
<view class="bd">
|
||||
<view class="icon" v-if="tabBarList.type == 1 || tabBarList.type == 2"
|
||||
:animation="isCartItem(item.link) ? cartAnimation : null"
|
||||
:id="isCartItem(item.link) ? 'tabbarCart' : null">
|
||||
<block v-if="verify(item.link)">
|
||||
<image v-if="item.selected_icon_type == 'img'"
|
||||
:src="$util.img(item.selectedIconPath)" />
|
||||
<diy-icon v-if="item.selected_icon_type == 'icon'" :icon="item.selectedIconPath"
|
||||
:value="item.selected_style ? item.selected_style : null"></diy-icon>
|
||||
</block>
|
||||
<block v-else>
|
||||
<view class="icon" v-if="tabBarList.type == 1 || tabBarList.type == 2">
|
||||
<block v-if="verify(item.link)">
|
||||
<image v-if="item.selected_icon_type == 'img'"
|
||||
:src="$util.img(item.selectedIconPath)" />
|
||||
<diy-icon v-if="item.selected_icon_type == 'icon'" :icon="item.selectedIconPath"
|
||||
:value="item.selected_style ? item.selected_style : null"></diy-icon>
|
||||
</block>
|
||||
<block v-else>
|
||||
<image v-if="item.icon_type == 'img'" :src="$util.img(item.iconPath)" />
|
||||
<diy-icon v-if="item.icon_type == 'icon'" :icon="item.iconPath"
|
||||
:value="item.style ? item.style : null"></diy-icon>
|
||||
</block>
|
||||
</view>
|
||||
<image v-if="item.icon_type == 'img'" :src="$util.img(item.iconPath)" />
|
||||
<diy-icon v-if="item.icon_type == 'icon'" :icon="item.iconPath"
|
||||
:value="item.style ? item.style : null"></diy-icon>
|
||||
</block>
|
||||
<view class="cart-count-mark font-size-activity-tag"
|
||||
:class="{ max: cartNumber > 99 }"
|
||||
:style="{ background: 'var(--price-color)' }"
|
||||
v-if="isCartItem(item.link) && cartNumber > 0">
|
||||
{{ cartNumber > 99 ? '99+' : cartNumber }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="label"
|
||||
v-if="(tabBarList.type == 1 || tabBarList.type == 3) && tabBarList.theme == 'diy'"
|
||||
:style="{ color: verify(item.link) ? tabBarList.textHoverColor : tabBarList.textColor }">
|
||||
@@ -129,53 +114,79 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 更新当前路由
|
||||
// 统一归一化路径:currentPage.route 不带前导 '/',但 tab 的 wap_url 带前导 '/'
|
||||
// 统一加前导 '/' 后再 split,确保 parts[1]=分包名、parts[2]=页面名
|
||||
_normalizeRoute(route) {
|
||||
if (!route) return '';
|
||||
return route.startsWith('/') ? route : '/' + route;
|
||||
},
|
||||
// 从归一化路径中提取分包名(parts[1])
|
||||
_getPackageName(normalizedRoute) {
|
||||
const parts = normalizedRoute.split('?')[0].split('/');
|
||||
return parts[1] || '';
|
||||
},
|
||||
// 判断某个链接是否指向购物车页面
|
||||
isCartItem(link) {
|
||||
if (!link || !link.wap_url) return false;
|
||||
return adaptSubpackageUrl(link.wap_url).split('?')[0] === '/pages_goods/cart';
|
||||
},
|
||||
// 更新当前路由,追踪每个分包的入口 tab
|
||||
updateCurrentRoute() {
|
||||
let currentPages = getCurrentPages();
|
||||
let currentPage = currentPages[currentPages.length - 1];
|
||||
if (currentPage && currentPage.route) {
|
||||
const newRoute = currentPage.route;
|
||||
const newRouteParts = newRoute.split('/');
|
||||
const currentPages = getCurrentPages();
|
||||
const currentPage = currentPages[currentPages.length - 1];
|
||||
if (!currentPage || !currentPage.route) return;
|
||||
|
||||
if (this.tabBarList && this.tabBarList.list) {
|
||||
const tabUrls = this.tabBarList.list
|
||||
.filter(item => item.link && item.link.wap_url)
|
||||
.map(item => adaptSubpackageUrl(item.link.wap_url).split('?')[0]);
|
||||
// 归一化:补全前导 '/',确保后续 split('/') 后 parts[1]=分包名
|
||||
const newRoute = this._normalizeRoute(currentPage.route);
|
||||
const newRouteParts = newRoute.split('?')[0].split('/');
|
||||
const currentPackageName = newRouteParts[1] || '';
|
||||
|
||||
let currentMatchingTab = null;
|
||||
for (const tabUrl of tabUrls) {
|
||||
if (this.tabBarList && this.tabBarList.list && currentPackageName) {
|
||||
const tabUrls = this.tabBarList.list
|
||||
.filter(item => item.link && item.link.wap_url)
|
||||
.map(item => adaptSubpackageUrl(item.link.wap_url).split('?')[0]);
|
||||
|
||||
// 1) 当前页面精确命中某个 tab → 该 tab 就是入口
|
||||
let entryTab = tabUrls.find(tabUrl => tabUrl === newRoute.split('?')[0]);
|
||||
|
||||
// 2) 当前页面在同一分包内 → 用分包名匹配
|
||||
if (!entryTab) {
|
||||
entryTab = tabUrls.find(tabUrl => {
|
||||
const tabParts = tabUrl.split('/');
|
||||
if (tabParts[2] === newRouteParts[2] && tabParts[1] === newRouteParts[1]) {
|
||||
currentMatchingTab = tabUrl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return tabParts[1] === currentPackageName;
|
||||
});
|
||||
}
|
||||
|
||||
let entryTab = null;
|
||||
if (currentMatchingTab) {
|
||||
entryTab = currentMatchingTab;
|
||||
} else {
|
||||
const prevPage = currentPages[currentPages.length - 2];
|
||||
if (prevPage && prevPage.route) {
|
||||
const prevRouteParts = prevPage.route.split('/');
|
||||
for (const tabUrl of tabUrls) {
|
||||
const tabParts = tabUrl.split('/');
|
||||
if (tabParts[2] === prevRouteParts[2] && tabParts[1] === prevRouteParts[1]) {
|
||||
entryTab = tabUrl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 3) 回退到上一页的分包匹配
|
||||
if (!entryTab) {
|
||||
const prevPage = currentPages[currentPages.length - 2];
|
||||
if (prevPage && prevPage.route) {
|
||||
const prevParts = this._normalizeRoute(prevPage.route).split('?')[0].split('/');
|
||||
const prevPackageName = prevParts[1] || '';
|
||||
entryTab = tabUrls.find(tabUrl => {
|
||||
const tabParts = tabUrl.split('/');
|
||||
return tabParts[1] === prevPackageName;
|
||||
});
|
||||
if (entryTab && prevPackageName !== currentPackageName) {
|
||||
// 上一页在别的分包 → 只记录到上一页的分包,不污染当前分包
|
||||
this.$store.commit('setPackageEntryTab', {
|
||||
...this.packageEntryTab,
|
||||
[prevPackageName]: entryTab
|
||||
});
|
||||
entryTab = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (entryTab) {
|
||||
const updatedEntryTab = { ...this.packageEntryTab, [newRouteParts[1]]: entryTab };
|
||||
this.$store.commit('setPackageEntryTab', updatedEntryTab);
|
||||
}
|
||||
}
|
||||
|
||||
this.currentRoute = newRoute;
|
||||
if (entryTab) {
|
||||
this.$store.commit('setPackageEntryTab', {
|
||||
...this.packageEntryTab,
|
||||
[currentPackageName]: entryTab
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.currentRoute = newRoute;
|
||||
},
|
||||
redirectTo(link) {
|
||||
this.$emit('callback');
|
||||
@@ -183,11 +194,13 @@ export default {
|
||||
if (link && link.wap_url) {
|
||||
const decodedUrl = decodeEntity(link.wap_url);
|
||||
const adaptedUrl = adaptSubpackageUrl(decodedUrl);
|
||||
const urlParts = adaptedUrl.split('/');
|
||||
const packageName = this._getPackageName(adaptedUrl);
|
||||
|
||||
if (urlParts.length >= 2 && urlParts[1]) {
|
||||
const updatedEntryTab = { ...this.packageEntryTab, [urlParts[1]]: adaptedUrl };
|
||||
this.$store.commit('setPackageEntryTab', updatedEntryTab);
|
||||
if (packageName) {
|
||||
this.$store.commit('setPackageEntryTab', {
|
||||
...this.packageEntryTab,
|
||||
[packageName]: adaptedUrl.split('?')[0]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,17 +209,17 @@ export default {
|
||||
verify(link) {
|
||||
if (link == null || link == '' || !link.wap_url) return false;
|
||||
|
||||
let currentPages = getCurrentPages();
|
||||
let currentPage = currentPages[currentPages.length - 1];
|
||||
let currentPageRoute = currentPage && currentPage.route ? '/' + currentPage.route : '';
|
||||
let linkUrl = link.wap_url;
|
||||
const currentPages = getCurrentPages();
|
||||
const currentPage = currentPages[currentPages.length - 1];
|
||||
const currentPageRoute = currentPage && currentPage.route
|
||||
? this._normalizeRoute(currentPage.route)
|
||||
: '';
|
||||
|
||||
if (linkUrl === this.$util.INDEX_PAGE_URL && this.name === 'DIY_VIEW_INDEX') {
|
||||
if (link.wap_url === this.$util.INDEX_PAGE_URL && this.name === 'DIY_VIEW_INDEX') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 使用通用的 checkTabBarActive 函数来判断 tab 高亮状态
|
||||
return checkTabBarActive(linkUrl, currentPageRoute, this.tabBarList, this.packageEntryTab);
|
||||
return checkTabBarActive(link.wap_url, currentPageRoute, this.tabBarList, this.packageEntryTab);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user