safeArea.js 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. const DEFAULT_NAV_CONTENT_HEIGHT = 44
  2. const DEFAULT_GAP = 8
  3. const DEFAULT_HORIZONTAL_PADDING = 8
  4. function getSystemInfo() {
  5. try {
  6. return uni.getSystemInfoSync() || {}
  7. } catch (error) {
  8. return {}
  9. }
  10. }
  11. function getMenuButtonRect() {
  12. try {
  13. const rect = uni.getMenuButtonBoundingClientRect?.()
  14. return rect && rect.width ? rect : null
  15. } catch (error) {
  16. return null
  17. }
  18. }
  19. export function computeSafeAreaMetrics() {
  20. const systemInfo = getSystemInfo()
  21. const menuRect = getMenuButtonRect()
  22. const statusBarHeight = Number(systemInfo.statusBarHeight || 20)
  23. const windowWidth = Number(systemInfo.windowWidth || 375)
  24. let navContentHeight = DEFAULT_NAV_CONTENT_HEIGHT
  25. let navTopGap = DEFAULT_GAP
  26. let capsuleWidth = 0
  27. let capsuleRightSafeWidth = 0
  28. if (menuRect) {
  29. navTopGap = Math.max(Number(menuRect.top || 0) - statusBarHeight, DEFAULT_GAP)
  30. navContentHeight = Math.max(Number(menuRect.height || 0) + navTopGap * 2, DEFAULT_NAV_CONTENT_HEIGHT)
  31. capsuleWidth = Number(menuRect.width || 0)
  32. const rightInset = Math.max(windowWidth - Number(menuRect.right || windowWidth), 0)
  33. capsuleRightSafeWidth = Math.max(capsuleWidth + rightInset + DEFAULT_HORIZONTAL_PADDING, 96)
  34. } else {
  35. // 无胶囊位(H5、无自定义导航栏等):不预留右侧占位;样式里已有 32rpx 水平内边距
  36. capsuleRightSafeWidth = 0
  37. }
  38. const topSafeHeight = statusBarHeight
  39. const headerHeight = topSafeHeight + navContentHeight
  40. return {
  41. statusBarHeight,
  42. topSafeHeight,
  43. navContentHeight,
  44. headerHeight,
  45. navTopGap,
  46. capsuleWidth,
  47. capsuleRightSafeWidth,
  48. }
  49. }
  50. export function applySafeAreaCssVars(metrics) {
  51. if (typeof document === 'undefined' || !document?.documentElement) return
  52. const root = document.documentElement.style
  53. root.setProperty('--sq-safe-top', `${metrics.topSafeHeight}px`)
  54. root.setProperty('--sq-nav-height', `${metrics.navContentHeight}px`)
  55. root.setProperty('--sq-header-height', `${metrics.headerHeight}px`)
  56. root.setProperty('--sq-capsule-right-safe', `${metrics.capsuleRightSafeWidth}px`)
  57. }
  58. export function initGlobalSafeArea() {
  59. const metrics = computeSafeAreaMetrics()
  60. const app = getApp?.()
  61. if (app) {
  62. app.globalData = app.globalData || {}
  63. app.globalData.safeArea = metrics
  64. }
  65. applySafeAreaCssVars(metrics)
  66. return metrics
  67. }
  68. export function getGlobalSafeArea() {
  69. const app = getApp?.()
  70. return app?.globalData?.safeArea || computeSafeAreaMetrics()
  71. }