必须使用 uni.onwindowresize 监听 app 端屏幕旋转,因其在 ios/android 原生 webview 中稳定返回实时视口尺寸,而 orientationchange、screen.orientation 等标准 api 在真机上基本不可用或失效。

App端监听屏幕旋转不能靠 orientationchange 或 screen.orientation,这些在 iOS/Android 原生 WebView 里基本不可用或返回假值。真正能稳定拿到方向变化的,只有 uni.onWindowResize —— 它返回的是实时视口尺寸,不是设备物理朝向,但对 UI 布局足够可靠。
为什么必须用 uni.onWindowResize 而不是其他事件
因为 App 端(尤其是 iOS)不暴露标准 screen.orientation API,window.addEventListener('orientationchange') 在多数真机上根本不会触发;plus.screen 相关方法只控制锁定,不提供监听能力;而 uni.onWindowResize 是 uni-app 封装的跨端回调,底层实际监听了原生窗口尺寸变更,在 App 端也稳定生效。
- iOS 上 windowWidth/windowHeight 会随旋转真实变化,且无延迟
- Android 部分机型(如 MIUI)可能有 100–200ms 滞后,但比轮询或加速度计更轻量、更准确
- 不要用
window.innerWidth/window.innerHeight替代——它们在 App 端常返回固定值,不随旋转更新
uni.onWindowResize 的正确注册和清理方式
这个监听器必须手动销毁,否则页面卸载后仍驻留内存,下次进同名页面会触发多次回调,导致布局错乱。
- 在
onLoad或onShow里注册:uni.onWindowResize(this.handleResize) - 在
onUnload里必须调用uni.offWindowResize(this.handleResize),否则泄漏 - 别在
onLoad里直接写箭头函数回调:uni.onWindowResize(() => {...})——这样无法被offWindowResize正确移除 - 如果页面支持多实例(如 tabbar 页面反复进出),
onShow中注册前先off一次更稳妥
判断横竖屏的真实逻辑,不是简单比较 windowWidth > windowHeight
这个等式在绝大多数场景下成立,但有例外:刘海屏、全面屏、折叠屏设备在竖屏时也可能出现 windowWidth > windowHeight(比如 iPhone 14 Pro Max 竖屏下宽度为 430,高度为 932,但某些横屏弹窗场景下视口被压缩)。更健壮的做法是结合比例与阈值:
- 用
Math.abs(res.size.windowWidth - res.size.windowHeight) > 100排除“接近正方形”的误判 - 再用
res.size.windowWidth / res.size.windowHeight > 1.2判断是否明显宽于高 - 避免硬编码 class 切换,优先用响应式变量驱动
v-if或class绑定,例如::class="{ 'landscape-layout': isLandscape }" - CSS 层面配合
@media (orientation: landscape)做兜底,但注意:该媒体查询在 App 端部分 Android WebView 中不触发,不能单独依赖
App 端监听后千万别做的三件事
很多开发者在拿到 isLandscape === true 后立刻执行危险操作:
- 不要调用
document.querySelector手动改 DOM style 或 class——uni-app 的响应式系统会覆盖它,且下次 setData 可能还原错误状态 - 不要在回调里直接调用
uni.setScreenOrientation想“纠正方向”——iOS 上静默失败,Android 上可能触发 Activity 重建,造成白屏 - 不要基于此去调
canvas.width/height——uni.getSystemInfo返回的是设备物理尺寸,不是当前视口,应改用uni.createSelectorQuery().in(this).select('#myCanvas').boundingClientRect()动态取
真正需要适配的,是布局结构、字体大小、按钮位置这些视觉层,而不是试图“说服系统横过来”。App 端的方向由原生配置决定,JS 层只负责响应,不负责驱动。











