const DEFAULT_NAV_CONTENT_HEIGHT = 44 const DEFAULT_GAP = 8 const DEFAULT_HORIZONTAL_PADDING = 8 function getSystemInfo() { try { return uni.getSystemInfoSync() || {} } catch (error) { return {} } } function getMenuButtonRect() { try { const rect = uni.getMenuButtonBoundingClientRect?.() return rect && rect.width ? rect : null } catch (error) { return null } } export function computeSafeAreaMetrics() { const systemInfo = getSystemInfo() const menuRect = getMenuButtonRect() const statusBarHeight = Number(systemInfo.statusBarHeight || 20) const windowWidth = Number(systemInfo.windowWidth || 375) let navContentHeight = DEFAULT_NAV_CONTENT_HEIGHT let navTopGap = DEFAULT_GAP let capsuleWidth = 0 let capsuleRightSafeWidth = 0 if (menuRect) { navTopGap = Math.max(Number(menuRect.top || 0) - statusBarHeight, DEFAULT_GAP) navContentHeight = Math.max(Number(menuRect.height || 0) + navTopGap * 2, DEFAULT_NAV_CONTENT_HEIGHT) capsuleWidth = Number(menuRect.width || 0) const rightInset = Math.max(windowWidth - Number(menuRect.right || windowWidth), 0) capsuleRightSafeWidth = Math.max(capsuleWidth + rightInset + DEFAULT_HORIZONTAL_PADDING, 96) } else { // 无胶囊位(H5、无自定义导航栏等):不预留右侧占位;样式里已有 32rpx 水平内边距 capsuleRightSafeWidth = 0 } const topSafeHeight = statusBarHeight const headerHeight = topSafeHeight + navContentHeight return { statusBarHeight, topSafeHeight, navContentHeight, headerHeight, navTopGap, capsuleWidth, capsuleRightSafeWidth, } } export function applySafeAreaCssVars(metrics) { if (typeof document === 'undefined' || !document?.documentElement) return const root = document.documentElement.style root.setProperty('--sq-safe-top', `${metrics.topSafeHeight}px`) root.setProperty('--sq-nav-height', `${metrics.navContentHeight}px`) root.setProperty('--sq-header-height', `${metrics.headerHeight}px`) root.setProperty('--sq-capsule-right-safe', `${metrics.capsuleRightSafeWidth}px`) } export function initGlobalSafeArea() { const metrics = computeSafeAreaMetrics() const app = getApp?.() if (app) { app.globalData = app.globalData || {} app.globalData.safeArea = metrics } applySafeAreaCssVars(metrics) return metrics } export function getGlobalSafeArea() { const app = getApp?.() return app?.globalData?.safeArea || computeSafeAreaMetrics() }