safeArea.js 2.6 KB

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