From 3c795256e838c0e7c30c5f3282e9d010d4e2536c Mon Sep 17 00:00:00 2001 From: ZF sun <34314687@qq.com> Date: Sat, 20 Dec 2025 15:57:11 +0800 Subject: [PATCH] =?UTF-8?q?chore(js):=20=E6=96=B0=E5=A2=9Enavigation.js?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/js/navigation.js | 288 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 288 insertions(+) create mode 100644 common/js/navigation.js diff --git a/common/js/navigation.js b/common/js/navigation.js new file mode 100644 index 0000000..0550cd0 --- /dev/null +++ b/common/js/navigation.js @@ -0,0 +1,288 @@ +import { EventSafety } from './event-safety' + +export class NavigationHelper { + constructor() { + this.navigationCache = new Map() + } + + // 安全地获取导航栏高度 + async getNavigationHeight(component, options = {}) { + const cacheKey = `nav_height` + + // 检查缓存 + if (this.navigationCache.has(cacheKey) && !options.forceRefresh) { + return this.navigationCache.get(cacheKey) + } + + // 获取高度 + try { + // 尝试直接获取 uni-page-head + const height = await this.getDirectNavigationHeight(component) + if (height > 0) { + this.navigationCache.set(cacheKey, height) + return height + } + + // 备用方案:平台特定方法 + const platformHeight = await this.getPlatformNavigationHeight() + this.navigationCache.set(cacheKey, platformHeight) + return platformHeight + } catch (error) { + console.warn('获取导航栏高度失败,使用默认值:', error) + const defaultHeight = this.getDefaultNavHeight() + this.navigationCache.set(cacheKey, defaultHeight) + return defaultHeight + } + } + + // 直接查询导航栏高度 + getDirectNavigationHeight(component) { + return new Promise((resolve) => { + const query = uni.createSelectorQuery().in(component) + + query.select('.uni-page-head').boundingClientRect((rect) => { + if (rect && rect.height > 0) { + console.log('直接查询导航栏高度成功:', rect.height) + resolve(rect.height) + } else { + console.warn('未找到 uni-page-head 元素或高度为0') + resolve(0) + } + }).exec() + }) + } + + // 平台特定的高度获取 + getPlatformNavigationHeight() { + return new Promise((resolve) => { + // #ifdef MP-WEIXIN + // 微信小程序精确计算 + try { + const menuButtonInfo = wx.getMenuButtonBoundingClientRect() + const systemInfo = uni.getSystemInfoSync() + + const height = menuButtonInfo.bottom + + (menuButtonInfo.top - systemInfo.statusBarHeight) + console.log('微信小程序导航栏高度:', height) + resolve(height) + } catch (error) { + console.error('微信小程序高度计算失败:', error) + resolve(44) + } + + // #endif + + // #ifdef H5 + // H5环境:尝试获取自定义导航栏或使用默认值 + if (typeof document !== 'undefined') { + const customNav = document.querySelector('.uni-page-head') + if (customNav) { + resolve(customNav.offsetHeight) + } else { + resolve(44) // 默认导航栏高度 + } + } else { + resolve(44) + } + // #endif + + // #ifdef APP-PLUS + // App端:状态栏 + 导航栏 + try { + const statusBarHeight = plus.navigator.getStatusbarHeight() + resolve(statusBarHeight + 44) + } catch (error) { + console.error('App端高度获取失败:', error) + resolve(88) + } + // #endif + + // 默认值 + resolve(44) + }) + } + + // 获取默认高度 + getDefaultHeight() { + // #ifdef MP-WEIXIN + return 44 // 微信小程序默认 + // #endif + // #ifdef H5 + return 44 // H5默认 + // #endif + // #ifdef APP-PLUS + return 88 // App默认(状态栏44 + 导航栏44) + // #endif + return 44 + } + + // 获取状态栏高度 + getStatusBarHeight() { + // #ifdef MP-WEIXIN + const systemInfo = uni.getSystemInfoSync() + return systemInfo.statusBarHeight || 20 + // #endif + // #ifdef H5 + return 0 // H5通常没有状态栏 + // #endif + // #ifdef APP-PLUS + try { + return plus.navigator.getStatusbarHeight() + } catch (error) { + return 44 + } + // #endif + return 0 + } + + // 获取安全区域 + getSafeAreaInsets() { + try { + const systemInfo = uni.getSystemInfoSync() + return systemInfo.safeArea || { + top: 0, + bottom: 0, + left: 0, + right: 0 + } + } catch (error) { + return { + top: 0, + bottom: 0, + left: 0, + right: 0 + } + } + } + + // 创建安全的事件处理器 + createSafeEventHandler(handler, options = {}) { + return EventSafety.wrapEventHandler(handler, options) + } + + // 安全地处理服务请求事件 + createServiceRequestHandler(component) { + return this.createSafeEventHandler((event) => { + return this.handleServiceRequest(event, component) + }, { + onError: (error, event) => { + this.handleNavigationError(error, event, component) + } + }) + } + + // 处理服务请求 + async handleServiceRequest(event, component) { + console.log('处理导航相关服务请求:', event.type) + + // 安全检查事件目标 + if (this.shouldProcessNavigationRequest(event)) { + await this.processNavigationRequest(event, component) + } + } + + // 检查是否应该处理导航请求 + shouldProcessNavigationRequest(event) { + // 方法1:检查事件类型 + if (event.type === 'service.requestComponentInfo') { + return true + } + + // 方法2:检查目标元素 + if (event.matches('.navigation-component') || event.matches('.uni-page-head')) { + return true + } + + // 方法3:检查事件详情 + if (event.detail && event.detail.componentType === 'navigation') { + return true + } + + return false + } + + // 处理导航请求 + async processNavigationRequest(event, component) { + try { + // 获取导航栏信息 + const navInfo = await this.getNavigationInfo(component) + + // 发送响应 + this.emitNavigationResponse(navInfo, component) + + } catch (error) { + console.error('处理导航请求失败:', error) + throw error + } + } + + + // 获取完整的导航信息 + async getNavigationInfo(component) { + const [navHeight, statusBarHeight, safeArea] = await Promise.all([ + this.getNavigationHeight(component), + this.getStatusBarHeight(), + this.getSafeAreaInsets() + ]) + + return { + navHeight, + statusBarHeight, + safeArea, + timestamp: Date.now() + } + } + + // 发送导航响应 + emitNavigationResponse(navInfo, component) { + if (component && component.$emit) { + component.$emit('navigation.infoResponse', { + success: true, + data: navInfo, + timestamp: Date.now() + }) + } + } + + // 错误处理 + handleNavigationError(error, event, component) { + console.error('导航处理错误:', { + error: error.message, + eventType: event?.type, + component: component?.$options?.name + }) + + // 发送错误响应 + if (component && component.$emit) { + component.$emit('navigation.infoError', { + success: false, + error: error.message, + timestamp: Date.now() + }) + } + + // 显示用户友好的错误信息 + this.showError('导航服务暂时不可用') + } + + // 显示错误提示 + showError(message) { + uni.showToast({ + title: message, + icon: 'none', + duration: 2000 + }) + } + + // 清理缓存 + clearCache() { + this.navigationCache.clear() + console.log('导航缓存已清理') + } + +} + +// 创建全局实例 +const navigationHelper = new NavigationHelper() + +export default navigationHelper \ No newline at end of file