refactor(nav): 动态控制导航栏返回按钮显示逻辑

1. 新增isTabBarRootPage工具方法判断是否为tab根页面
2. 在全局混入中添加isTabRootPage计算属性
3. 替换多处硬编码的isBack属性为动态绑定
4. 优化shouldShowTabBar计算属性的代码逻辑
This commit is contained in:
2026-06-16 15:34:10 +08:00
parent 92700f9a21
commit e51c03235f
6 changed files with 116 additions and 39 deletions

View File

@@ -1,14 +1,68 @@
// 内部 helper:获取当前页面实例
const _getCurrentPage = () => {
const pages = getCurrentPages();
return pages.length === 0 ? null : pages[pages.length - 1];
};
// 内部 helper:获取当前页面路由(统一提取 route 或 $page.path)
const _getCurrentRoute = (currentPage) => {
if (!currentPage) return '';
if (currentPage.route) return currentPage.route;
if (currentPage.$page && currentPage.$page.path) return currentPage.$page.path;
return '';
};
// 内部 helper:判断 tabBarList 是否已加载且有 list 配置
const _isValidTabBarList = (tabBarList) => {
return tabBarList && tabBarList.list;
};
// 内部 helper:规范化路由:无前导斜杠时补全
const _normalizeLeadingSlash = (route) => {
if (!route) return route;
return route.startsWith('/') ? route : '/' + route;
};
// 内部 helper:通过 $util 方法的安全调用
const _callUtil = (vm, method, ...args) => {
if (vm.$util && vm.$util[method]) {
return vm.$util[method](...args);
}
return null;
};
export default {
onLoad() { },
onShow() {
// 刷新多语言
this.$langConfig.refresh();
// TabBar 根页面时隐藏系统导航栏的返回按钮
// (uni-app 的系统导航栏在通过 navigateTo 跳转到 tab 页时可能残留返回键)
const tabBarList = this.$store.state.tabBarList;
if (!_isValidTabBarList(tabBarList)) return;
const currentRoute = _getCurrentRoute(_getCurrentPage());
if (!currentRoute) return;
const isRoot = _callUtil(this, 'isTabBarRootPage', currentRoute, tabBarList) || false;
if (isRoot) {
// #ifdef MP-WEIXIN || MP-BAIDU || MP-TOUTIAO || MP-QQ || MP-ALIPAY
try { uni.hideHomeButton(); } catch (e) { /* 兼容 */ }
// #endif
}
},
computed: {
// 是否是英文环境
isEnEnv() {
return this.$langConfig.getCurrentLocale() === 'en-us';
},
// 动态判断:当前页面是否是 TabBar 根页面(tab 根页不应显示返回按钮)
isTabRootPage() {
const tabBarList = this.$store.state.tabBarList;
if (!_isValidTabBarList(tabBarList)) return false;
const currentRoute = _getCurrentRoute(_getCurrentPage());
if (!currentRoute) return false;
return _callUtil(this, 'isTabBarRootPage', currentRoute, tabBarList) || false;
},
themeStyle() {
return this.$store.state.themeStyle;
},
@@ -24,43 +78,18 @@ export default {
},
shouldShowTabBar() {
const tabBarList = this.$store.state.tabBarList;
if (!tabBarList || !tabBarList.list) {
return false;
}
if (!_isValidTabBarList(tabBarList)) return false;
const mode = tabBarList.page_visibility_mode;
const routeList = tabBarList.page_routes || [];
if (!mode || mode === 'all') {
return true;
}
if (mode === 'none') {
return false;
}
const pages = getCurrentPages();
if (pages.length === 0) {
return true;
}
const currentPage = pages[pages.length - 1];
let currentRoute = '';
if (currentPage.route) {
currentRoute = currentPage.route;
} else if (currentPage.$page && currentPage.$page.path) {
currentRoute = currentPage.$page.path;
}
if (!currentRoute) {
return true;
}
if (!currentRoute.startsWith('/')) {
currentRoute = '/' + currentRoute;
}
const inList = this.$util && this.$util.isPageInRouteList
? this.$util.isPageInRouteList(currentRoute, routeList)
: false;
if (mode === 'whitelist') {
return inList;
}
if (mode === 'blacklist') {
return !inList;
}
if (!mode || mode === 'all') return true;
if (mode === 'none') return false;
const currentPage = _getCurrentPage();
if (!currentPage) return true;
const currentRoute = _normalizeLeadingSlash(_getCurrentRoute(currentPage));
if (!currentRoute) return true;
const inList = _callUtil(this, 'isPageInRouteList', currentRoute, routeList) || false;
if (mode === 'whitelist') return inList;
if (mode === 'blacklist') return !inList;
return true;
},
tabBarPagePaddingStyle() {

View File

@@ -341,6 +341,24 @@ function _findMatchingTabUrl(currentPagePath, tabBarList, packageEntryTab) {
return tabUrls.find(url => _getPackageName(url) === packageName) || null;
}
/**
* 判断给定路径是否是 TabBar 根页面(与 diy_bottom_nav 中任意一项精确相等)
* @param {string} pagePath 当前页面路径(可以带/不带前导斜杠、可以带 query)
* @param {Object|null} tabBarList tabBar 配置对象($store.state.tabBarList)
* @returns {boolean} 如果是 TabBar 根页面返回 true;路径无效/未配置 tabBarList 时返回 false
*/
export const isTabBarRootPage = (pagePath, tabBarList) => {
if (!pagePath) return false;
if (!tabBarList || !tabBarList.list || !Array.isArray(tabBarList.list)) return false;
const normalizedCurrent = _normalizePath(pagePath);
if (!normalizedCurrent) return false;
return tabBarList.list.some(item => {
if (!item || !item.link || !item.link.wap_url) return false;
const normalizedTab = _normalizePath(item.link.wap_url);
return normalizedTab === normalizedCurrent;
});
};
/**
* 检查tabBar是否激活
* @param {string} linkUrl 链接路径 /pages/goods/category
@@ -404,6 +422,9 @@ export default {
/** 解析 link 对象得到最终可跳转的 URL(优先级: page_key → wap_url) */
resolveLinkUrl,
/** 判断给定路径是否是 TabBar 根页面(用于动态控制返回按钮显示) */
isTabBarRootPage,
/**
* 页面跳转
* @param {string} to 跳转链接 /pages/idnex/index
@@ -436,6 +457,33 @@ export default {
}
}
// 动态 diy tabBar:如果目标是 diy_bottom_nav 中的 tab 根页
// 注意:uni.switchTab 仅对 pages.json 中 tabBar.list 注册的页面有效,
// 其他 DIY 配置页面调用 switchTab 会静默失败(点击无响应)。
// 因此使用 uni.redirectTo 替换当前页:不进栈 → 无返回按钮 → 对任意页面都有效。
const diyTabBar = store.state.tabBarList;
if (diyTabBar && diyTabBar.list && Array.isArray(diyTabBar.list)) {
const cleanUrl = url.split('?')[0];
const isDiyTabRoot = diyTabBar.list.some(item => {
if (!item || !item.link || !item.link.wap_url) return false;
const normalizedTab = _normalizePath(item.link.wap_url);
const normalizedUrl = _normalizePath(cleanUrl);
return normalizedTab === normalizedUrl;
});
if (isDiyTabRoot) {
const adaptedUrl = adaptSubpackageUrl(cleanUrl);
const inSystemTabBar = systemTabBarList.some(sysUrl => adaptedUrl === sysUrl || cleanUrl === sysUrl);
const navApi = inSystemTabBar ? uni.switchTab : uni.redirectTo;
navApi({
url,
fail: (err) => {
console.error('[navigate] tabBar 跳转失败:', cleanUrl, err);
}
});
return;
}
}
// 如果url不包含tabBarList中的路径,根据mode判断跳转方式
switch (mode) {
case 'tabbar':