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