safeArea.js 3.69 KB
export const getSafeArea = () => {
  // 获取系统信息(UniApp 跨端 API)
  const systemInfo = uni.getSystemInfoSync();

  // 顶部状态栏高度(所有机型都有,非安全区但常用)
  const statusBarHeight = systemInfo.statusBarHeight || 0;

  // 底部安全距离(全面屏/刘海屏机型有值,非全面屏为 0)
  let safeAreaInsetBottom = systemInfo.safeAreaInsets?.bottom || 0;

  // 兼容旧版小程序(部分机型 safeAreaInsets 可能不存在)
  if (typeof safeAreaInsetBottom !== 'number') {
    const safeArea = systemInfo.safeArea || {};
    safeAreaInsetBottom = systemInfo.screenHeight - (safeArea.bottom || systemInfo.screenHeight);
  }

  // 胶囊按钮默认信息(适配非微信小程序端:H5、App、其他小程序)
  const menuButtonInfo = {
    height: 32, // 默认胶囊高度(符合常见设计规范)
    width: 80, // 默认胶囊宽度
    top: statusBarHeight + 4, // 默认顶部位置(状态栏下4px)
    bottom: statusBarHeight + 36, // 默认底部位置(状态栏高度 + 胶囊高度)
    right: 16, // 默认右侧位置(距离屏幕左边16px)
  };

  // 【关键修复】仅在微信小程序环境中获取真实胶囊信息
  // 判断微信小程序环境:通过 systemInfo.appPlatform === 'mp-weixin'(UniApp 统一判断标准)
  if (systemInfo.appPlatform === 'mp-weixin') {
    try {
      // 微信小程序专属 API:获取胶囊菜单信息
      const menuBtn = uni.getMenuButtonBoundingClientRect();
      // 验证返回结果有效(避免 null/undefined)
      if (menuBtn && typeof menuBtn.height === 'number' && menuBtn.height > 0) {
        menuButtonInfo.height = menuBtn.height;
        menuButtonInfo.width = menuBtn.width || 80;
        menuButtonInfo.top = menuBtn.top || statusBarHeight + 4;
        menuButtonInfo.bottom = menuBtn.bottom || statusBarHeight + 36;
        menuButtonInfo.right = menuBtn.right || 16;
      }
    } catch (e) {
      // 异常时保留默认值,不影响整体功能
      console.warn('微信小程序获取胶囊信息失败,使用默认值:', e);
    }
  }

  return {
    statusBarHeight,
    safeAreaInsetBottom,
    menuButtonInfo,
  };
};

/**
 * 快捷获取顶部安全距离(状态栏高度)
 * @returns {number} 顶部状态栏高度(px)
 */
export const getTopSafeArea = () => {
  return getSafeArea().statusBarHeight;
};

/**
 * 快捷获取底部安全距离
 * @returns {number} 底部安全距离(px)
 */
export const getBottomSafeArea = () => {
  return getSafeArea().safeAreaInsetBottom;
};

/**
 * 快捷获取胶囊按钮高度
 * @returns {number} 胶囊高度(px)(微信小程序返回真实值,其他端返回默认32px)
 */
export const getMenuButtonHeight = () => {
  return getSafeArea().menuButtonInfo.height;
};

/**
 * 快捷获取胶囊按钮宽度
 * @returns {number} 胶囊宽度(px)(微信小程序返回真实值,其他端返回默认80px)
 */
export const getMenuButtonWidth = () => {
  return getSafeArea().menuButtonInfo.width;
};

/** 获取 wd-navbar 导航栏高度 */
export function getNavbarHeight() {
  const systemInfo = uni.getSystemInfoSync();
  const statusBarHeight = systemInfo.statusBarHeight || 0;
  // #ifdef MP-WEIXIN
  // 小程序:根据胶囊按钮位置计算导航栏高度,确保内容与胶囊垂直居中
  const menuButtonInfo = uni.getMenuButtonBoundingClientRect();
  // 导航栏高度 = (胶囊顶部到状态栏底部的距离) * 2 + 胶囊高度
  const navBarHeight = (menuButtonInfo.top - statusBarHeight) * 2 + menuButtonInfo.height;
  return statusBarHeight + navBarHeight;
  // #endif
  // #ifndef MP-WEIXIN
  // H5/App:状态栏高度 + 导航栏高度(44px)
  return statusBarHeight + 44;
  // #endif
}