diff --git a/common/js/util.js b/common/js/util.js index 0caf744..52c96c7 100644 --- a/common/js/util.js +++ b/common/js/util.js @@ -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 { diff --git a/components-diy/diy-bottom-nav.vue b/components-diy/diy-bottom-nav.vue index 1d2089d..c4d7867 100644 --- a/components-diy/diy-bottom-nav.vue +++ b/components-diy/diy-bottom-nav.vue @@ -1,45 +1,30 @@