微信小程序 getSystemInfo 提示已废弃、屏幕高度算错胶囊还对不齐?getWindowInfo 和 getDeviceInfo 怎么接才稳

开发者工具里突然出现「wx.getSystemInfo / getSystemInfoSync 已废弃」的黄字,自定义导航栏却还是对不齐胶囊,或者用 windowHeight 算出来的页面底部被 Home 条挡住------这多半不是「接口坏了」,而是还在用一把大而全的旧接口,去量几件已经拆开的尺寸。较新的基础库把系统信息拆成了窗口、设备、应用和开关几组同步接口。下面按「先看黄字和错位分别出在哪 → 用新接口按需取值并兼容旧基础库 → 用菜单按钮矩形把自定义导航算准 → 高度、安全区和横竖屏收口」来接。

1. 先分清:是废弃提示,还是高度、胶囊真的算错

不要一看到废弃提示就把所有 getSystemInfoSync 删掉再重写一遍。先判断卡在哪一类:

  1. 只是提示废弃:功能正常,但开发者工具或真机日志在告诫旧接口会在后续基础库移除。这时优先替换调用,而不是先改布局公式。
  2. 高度算错 :底部按钮被挡住、列表少一截、100vh 感觉的全屏其实溢出或留白。常见原因是把 screenHeight 和 windowHeight 混用,或没减掉状态栏、安全区。
  3. 胶囊对不齐 :自定义导航栏的标题、返回按钮和右上角官方胶囊高低不一,甚至重叠。这通常不是「再调一次系统信息」能修,而要同时用窗口信息和 wx.getMenuButtonBoundingClientRect()。

getSystemInfo 把窗口尺寸、设备型号、基础库版本、授权开关塞在同一个返回值里,调用一次看起来省事,但字段含义在不同机型、开发者工具和 PC 端并不一致,也是官方拆分接口的原因。

2. 用拆分后的同步接口按需取值,旧基础库再回退

较新基础库里,这几组接口是同步的,直接返回对象,不必再写 success 回调:

  • wx.getWindowInfo():和布局有关的尺寸,例如 pixelRatio、screenWidth / screenHeight、windowWidth / windowHeight、statusBarHeight、safeArea、screenTop。做导航栏、全屏页、安全区,优先用它。
  • wx.getDeviceInfo():品牌、型号、系统、平台等设备信息。不要拿它来算像素高度。
  • wx.getAppBaseInfo():基础库版本、宿主、语言、主题、字号等。对比 SDKVersion、适配暗黑模式,用这一组。
  • wx.getSystemSetting():系统蓝牙、定位、Wi-Fi、屏幕方向等开关。
  • wx.getAppAuthorizeSetting():相册、定位、麦克风、通知等授权状态,和 wx.getSetting 互补。

旧基础库没有这些接口时,再回退到 getSystemInfoSync,不要一上来就假设新接口一定存在:

js 复制代码
function getWindowInfoCompat() {
  if (typeof wx.getWindowInfo === 'function') {
    return wx.getWindowInfo()
  }
  const sys = wx.getSystemInfoSync()
  return {
    pixelRatio: sys.pixelRatio,
    screenWidth: sys.screenWidth,
    screenHeight: sys.screenHeight,
    windowWidth: sys.windowWidth,
    windowHeight: sys.windowHeight,
    statusBarHeight: sys.statusBarHeight || 0,
    safeArea: sys.safeArea,
    screenTop: sys.screenTop || 0
  }
}

function getAppBaseInfoCompat() {
  if (typeof wx.getAppBaseInfo === 'function') {
    return wx.getAppBaseInfo()
  }
  const sys = wx.getSystemInfoSync()
  return {
    SDKVersion: sys.SDKVersion,
    language: sys.language,
    version: sys.version,
    theme: sys.theme,
    host: sys.host,
    fontSizeSetting: sys.fontSizeSetting
  }
}

建议在 App 启动时算一次并缓存到全局,页面里不要每次 setData 或 onShow 都同步取一遍。尺寸在同一次冷启动里通常不会变;真正会变的是横竖屏和窗口变化,这时再在 wx.onWindowResize 里更新。

注意:getDeviceInfo 里部分敏感字段在较新基础库可能需要额外声明或权限,和布局无关的型号信息不要放在每个页面的首屏路径上顺手取。

3. 自定义导航栏要对齐胶囊,不能只靠 statusBarHeight

只拿 statusBarHeight + 44 当导航高度,在部分 Android、iPad、PC 端和开发者工具里会对不齐。官方胶囊的位置才是标尺,用 wx.getMenuButtonBoundingClientRect() 取出 top、height、right:

js 复制代码
function getNavBarMetrics() {
  const win = getWindowInfoCompat()
  const menu = wx.getMenuButtonBoundingClientRect() || {}
  const statusBarHeight = win.statusBarHeight || 0
  const menuHeight = menu.height || 32
  const menuTop = menu.top || statusBarHeight + 4
  const gap = Math.max(menuTop - statusBarHeight, 0)
  const navBarHeight = menuHeight + gap * 2
  return {
    statusBarHeight,
    navBarHeight,
    totalHeight: statusBarHeight + navBarHeight,
    menuRight: (win.windowWidth || 0) - (menu.right || 0),
    menuWidth: menu.width || 87,
    windowWidth: win.windowWidth
  }
}

计算时记住这几条:

  1. 左右留白要对着胶囊 。标题不要写到胶囊底下;右侧预留 windowWidth - menu.right,左侧返回按钮的垂直中心和胶囊中心对齐。
  2. 高度用「状态栏 + 两倍间隙 + 胶囊高度」 。间隙是 menu.top - statusBarHeight,不要写死 8 或 44。
  3. 开发者工具、PC 端、iPad 的胶囊位置和手机不同。公式要吃真实矩形,不要按某款 iPhone 的截图像素反推。
  4. 菜单按钮矩形偶发为 0 。极少数时机(过早在 App.onLaunch 里取、或窗口尚未就绪)会拿到空值。判空后用 statusBarHeight 做一次兜底,并在首页 onReady 再算一次。

自定义导航开启时,页面还要在 json 里设 navigationStyle: custom,并给页面根节点加上 totalHeight 的 padding-top,避免内容顶到胶囊后面。

4. 屏幕高度、安全区和横竖屏不要混用字段

布局算错,经常是字段选错,而不是接口没调用成功:

  1. screenHeight 是整屏,windowHeight 是可用窗口 。有原生导航栏时,windowHeight 通常已经去掉了导航;自定义导航时则接近整屏可用高度。用错会表现为「底部按钮被顶出屏幕」或「下面空出一截」。
  2. 底部安全区看 safeArea 。全面屏的 Home 指示条不能靠经验值 34。可用高度更稳的算法是:以窗口底部为准,再取 safeArea.bottom 与窗口高度的差值作为 safeAreaBottom。没有 safeArea 时再按 0 处理,不要给所有安卓机统一加 34。
  3. 全屏页还要看 screenTop。从自定义窗或半屏进入时,窗口不一定从屏幕顶端开始。
  4. rpx 换算用 windowWidth / 750 。不要混用 screenWidth,在有调试条或分栏时会偏。
  5. 横竖屏会变 。监听 wx.onWindowResize,或在页面 onResize 里重新取 getWindowInfo 并更新导航和安全区,不要假设启动时的缓存永远正确。
  6. 真机和开发者工具不一致。工具里的状态栏、胶囊和安全区都是模拟值。上线前用 iOS、Android 各一台,把「系统导航 / 自定义导航 / 横屏 / 有 TabBar / 无 TabBar」走一遍。

底部固定栏可以写成:

js 复制代码
function getSafeAreaBottom() {
  const win = getWindowInfoCompat()
  const safe = win.safeArea
  if (!safe || !win.windowHeight) return 0
  return Math.max(win.windowHeight - safe.bottom, 0)
}

5. 上线前核对

  1. 新基础库走 getWindowInfo / getAppBaseInfo 等拆分接口,旧基础库才回退 getSystemInfoSync,不要只删警告不兼容。
  2. 自定义导航用菜单按钮矩形计算高度和左右留白,标题和返回按钮垂直对齐胶囊,判空并在 onReady 复核。
  3. 页面高度、全屏和底部按钮分清 screenHeight、windowHeight 和 safeArea,不要给所有机型写死 44 或 34。
  4. 尺寸启动时缓存,横竖屏和窗口变化时再更新;不要在每个 setData 里同步取系统信息。
  5. 真机验证系统导航与自定义导航、有无 TabBar、横屏、开发者工具与正式版是否一致。

系统信息已经按用途拆开了。窗口尺寸负责排版,设备信息负责识别机型,应用信息负责基础库和主题。把自定义导航对准胶囊,再把安全区留给底部操作,废弃提示和「高度算错、胶囊对不齐」就可以一次性收口。


本文由 DEVDIY 整理。我们日常做微信小程序定制与上线前检查时,会把系统信息改成「按用途拆开取值,自定义导航对准胶囊,安全区留给底部操作」,避免只靠一条旧的同步接口去算所有布局。

相关推荐
FungLeo2 小时前
成为全栈·Vue 管理后台篇·用 fetch 建一层可控的请求内核
前端·javascript·vue.js·http·fetch·formdata·接口封装
用户84298142418102 小时前
ByteJS,让重要的 JavaScript 以字节码运行。
javascript
dreams_dream3 小时前
微信小程序-使用npm包
微信小程序·小程序·npm
FungLeo4 小时前
成为全栈·Vue 管理后台篇·Vue Router如何守住多角色后台边界
前端·javascript·vue.js·rbac·vue router·路由守卫·前端权限
L1mbo4 小时前
Lite模式 缓解微信开发者工具卡顿,附 uni-app 实践方案
前端·微信小程序
FungLeo4 小时前
成为全栈·Vue管理后台篇·仪表盘不是几张卡片:组合统计接口与角色视图
前端·javascript·vue.js·rbac·仪表盘·管理后台·tanstack query
程序员大阳4 小时前
HTML+CSS+JS对话式实战(7)-学生端活动报名功能开发
javascript·css·html·活动报名
西安小哥5 小时前
做 Agent 写到第三个小时,我开始给它算账
javascript
西安小哥5 小时前
让大模型操作浏览器跑了两周,我发现瓶颈根本不在模型
javascript