refactor(utils&tabbar): 重构tabbar高亮逻辑与分包路径适配
1. 修复store中tabBarList初始值为null替代空字符串 2. 重构adaptSubpackageUrl,优化正则匹配与移除冗余映射 3. 新增路径归一化、分包名提取工具函数 4. 重写checkTabBarActive,新增精确匹配、packageEntryTab优先级匹配逻辑 5. 重构diy-bottom-nav组件的路由更新与高亮校验逻辑,统一路径处理流程
This commit is contained in:
@@ -256,13 +256,11 @@ export const adaptSubpackageUrl = (url) => {
|
||||
* 系统当前的支持tarbarList(包含动态tabBar),注意这是实际分包后的路径
|
||||
* 根据匹配映射关系,修改url为实际分包后的路径
|
||||
*/
|
||||
// 定义前缀映射表
|
||||
// 定义前缀映射表(key=旧前缀, value=新分包前缀)
|
||||
const urlPrefixMap = {
|
||||
'/pages/promotion/': '/pages_promotion/',
|
||||
'/pages/order/': '/pages_order/',
|
||||
'/pages/goods/': '/pages_goods/',
|
||||
|
||||
'/pages/contact/': '/pages_tool/contact/',
|
||||
'/pages/member/': '/pages_tool/member/',
|
||||
'/pages/login/': '/pages_tool/login/',
|
||||
'/pages/agreement/': '/pages_tool/agreement/',
|
||||
@@ -282,29 +280,67 @@ export const adaptSubpackageUrl = (url) => {
|
||||
'/pages/webview/': '/pages_tool/webview/',
|
||||
};
|
||||
|
||||
// 构建正则表达式
|
||||
// 构建正则表达式(加 ^ 锚定前缀,避免路径中间出现 /pages/xxx/ 时误匹配)
|
||||
const prefixes = Object.keys(urlPrefixMap);
|
||||
if (prefixes.length === 0) return url;
|
||||
|
||||
const regex = new RegExp(
|
||||
Object.keys(urlPrefixMap).map(key =>
|
||||
'^(' + prefixes.map(key =>
|
||||
key.replace(/\//g, '\\/').replace(/\*/g, '.*')
|
||||
).join('|'),
|
||||
'g'
|
||||
).join('|') + ')'
|
||||
);
|
||||
|
||||
// 替换函数
|
||||
function replacePrefix(str) {
|
||||
return str.replace(regex, match => {
|
||||
for (const [oldPrefix, newPrefix] of Object.entries(urlPrefixMap)) {
|
||||
if (match.startsWith(oldPrefix)) {
|
||||
return match.replace(oldPrefix, newPrefix);
|
||||
}
|
||||
}
|
||||
return match; // 默认返回原匹配
|
||||
const newPrefix = urlPrefixMap[match];
|
||||
return newPrefix || match;
|
||||
});
|
||||
}
|
||||
|
||||
return replacePrefix(url);
|
||||
}
|
||||
|
||||
// 归一化任意路径:确保以 '/' 开头,去除 query,适配子包
|
||||
function _normalizePath(path) {
|
||||
if (!path) return '';
|
||||
const normalized = path.startsWith('/') ? path : '/' + path;
|
||||
return adaptSubpackageUrl(normalized).split('?')[0];
|
||||
}
|
||||
|
||||
// 从归一化路径提取分包名(parts[1])
|
||||
function _getPackageName(normalizedPath) {
|
||||
const parts = normalizedPath.split('/');
|
||||
return parts[1] || '';
|
||||
}
|
||||
|
||||
// 给定当前页面路径 + tab 配置,返回当前页面所属的 tab URL
|
||||
// 优先级:精确匹配 > packageEntryTab > 分包名回退匹配
|
||||
function _findMatchingTabUrl(currentPagePath, tabBarList, packageEntryTab) {
|
||||
if (!tabBarList || !tabBarList.list || !Array.isArray(tabBarList.list)) return null;
|
||||
|
||||
const tabUrls = tabBarList.list
|
||||
.filter(item => item.link && item.link.wap_url)
|
||||
.map(item => _normalizePath(item.link.wap_url));
|
||||
|
||||
const normalizedCurrent = _normalizePath(currentPagePath);
|
||||
|
||||
// 1) 精确匹配 → 当前页面就是 tab 页面
|
||||
const exactMatch = tabUrls.find(url => url === normalizedCurrent);
|
||||
if (exactMatch) return exactMatch;
|
||||
|
||||
// 2) 通过 packageEntryTab(由 updateCurrentRoute/redirectTo 写入)
|
||||
const packageName = _getPackageName(normalizedCurrent);
|
||||
if (packageEntryTab && typeof packageEntryTab === 'object' && packageEntryTab[packageName]) {
|
||||
const entryTab = packageEntryTab[packageName];
|
||||
const normalizedEntry = _normalizePath(entryTab);
|
||||
if (tabUrls.includes(normalizedEntry)) return normalizedEntry;
|
||||
}
|
||||
|
||||
// 3) 回退:同分包内的第一个 tab(基于分包名匹配)
|
||||
return tabUrls.find(url => _getPackageName(url) === packageName) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查tabBar是否激活
|
||||
* @param {string} linkUrl 链接路径 /pages/goods/category
|
||||
@@ -314,78 +350,37 @@ export const adaptSubpackageUrl = (url) => {
|
||||
* @returns {boolean} 是否激活
|
||||
*/
|
||||
export const checkTabBarActive = (linkUrl, currentPageRoute, tabBarList, packageEntryTab) => {
|
||||
const adaptedLinkUrl = adaptSubpackageUrl(linkUrl);
|
||||
const adaptedCurrentRoute = adaptSubpackageUrl(currentPageRoute);
|
||||
// 1) 归一化 linkUrl:统一前导 '/' + 子包路径适配 + 去除 query
|
||||
const normalizedLink = _normalizePath(linkUrl);
|
||||
const normalizedCurrent = _normalizePath(currentPageRoute);
|
||||
|
||||
// 去除查询参数,仅比较路径部分
|
||||
const cleanLinkUrl = adaptedLinkUrl.split('?')[0];
|
||||
const cleanCurrentRoute = adaptedCurrentRoute.split('?')[0];
|
||||
if (!normalizedLink) return false;
|
||||
|
||||
const linkUrlParts = cleanLinkUrl.split('/');
|
||||
const currentPageRouteParts = cleanCurrentRoute.split('/');
|
||||
// 2) 精确匹配:当前页面就是 linkUrl 指向的页面
|
||||
if (normalizedLink === normalizedCurrent) return true;
|
||||
|
||||
// 首先尝试精确匹配(整个路径匹配)
|
||||
if (cleanLinkUrl === cleanCurrentRoute) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 如果没有精确匹配,且传入了 tabBarList,使用动态判断逻辑
|
||||
// 3) 若传入 tabBarList,使用动态判断逻辑
|
||||
if (tabBarList && tabBarList.list && Array.isArray(tabBarList.list)) {
|
||||
// 获取所有 tab 项的链接(去除查询参数)
|
||||
const tabUrls = tabBarList.list
|
||||
.filter(item => item.link && item.link.wap_url)
|
||||
.map(item => adaptSubpackageUrl(item.link.wap_url).split('?')[0]);
|
||||
.map(item => _normalizePath(item.link.wap_url));
|
||||
|
||||
// 检查当前 linkUrl 是否是合法的 tab URL
|
||||
if (!tabUrls.includes(cleanLinkUrl)) {
|
||||
return false;
|
||||
}
|
||||
if (!tabUrls.includes(normalizedLink)) return false;
|
||||
|
||||
// 获取当前页面所属的分包名(parts[1])
|
||||
const currentPackageName = currentPageRouteParts[1];
|
||||
const linkPackageName = linkUrlParts[1];
|
||||
// 找出当前页面所属的 tab
|
||||
const matchingTabUrl = _findMatchingTabUrl(currentPageRoute, tabBarList, packageEntryTab);
|
||||
|
||||
// 如果 linkUrl 和当前页面不在同一个分包,直接返回 false
|
||||
if (linkPackageName !== currentPackageName) {
|
||||
return false;
|
||||
}
|
||||
// 当前页面若命中某个 tab,则只有该 tab 高亮
|
||||
if (matchingTabUrl) return normalizedLink === matchingTabUrl;
|
||||
|
||||
// 获取当前页面路径的二级目录(parts[2])
|
||||
const currentPageSecondPart = currentPageRouteParts[2];
|
||||
|
||||
// 检查当前页面路径是否匹配某个 tab 的精确路径
|
||||
const currentMatchingTab = tabUrls.find(url => {
|
||||
if (!url) return false;
|
||||
const parts = url.split('/');
|
||||
return parts[2] === currentPageSecondPart;
|
||||
});
|
||||
|
||||
// 如果当前页面能精确匹配到某个 tab,那么只有该 tab 高亮
|
||||
if (currentMatchingTab) {
|
||||
return cleanLinkUrl === currentMatchingTab;
|
||||
}
|
||||
|
||||
// 当前页面不是任何 tab 的精确匹配(是子页面)
|
||||
// 使用 packageEntryTab 来确定应该高亮的 tab
|
||||
if (packageEntryTab && typeof packageEntryTab === 'object') {
|
||||
const entryTab = packageEntryTab[currentPackageName];
|
||||
if (entryTab) {
|
||||
const entryTabParts = entryTab.split('/');
|
||||
return linkUrlParts[2] === entryTabParts[2];
|
||||
}
|
||||
}
|
||||
|
||||
// 基于二级路径匹配(fallback)
|
||||
try {
|
||||
if (linkUrlParts[2] === currentPageSecondPart) {
|
||||
return true;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('diy-bottom-nav verify error:', error);
|
||||
}
|
||||
|
||||
return false;
|
||||
// 4) 同分包回退:linkUrl 和当前页面在同一分包 → 高亮
|
||||
const linkPackage = _getPackageName(normalizedLink);
|
||||
const currentPackage = _getPackageName(normalizedCurrent);
|
||||
return linkPackage && currentPackage && linkPackage === currentPackage;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export default {
|
||||
|
||||
Reference in New Issue
Block a user