uni.onkeyboardheightchange 在 h5 端不触发,因其依赖 5+app 原生能力,而 h5 运行于浏览器,无系统级键盘高度回调;唯一可行方案是监听 window.innerheight 变化并防抖判定键盘状态。

uni-app 的 uni.onKeyboardHeightChange 在 H5 端完全不触发,iOS 下键盘弹出遮挡必须靠 window.innerHeight 变化 + 防抖检测来模拟,没有原生事件可用。
为什么 H5 端不能用 keyboardHeightChange
这个 API 是 5+App 原生层提供的,只在 App 平台(iOS/Android)生效。H5 端运行在浏览器中,既无原生键盘事件下发,也无系统级高度回调。写监听函数不会报错,但永远不会进回调——不是代码问题,是平台能力缺失。
-
uni.onKeyboardHeightChange在 H5 和小程序里均被静默忽略,日志都看不到 - 试图在 H5 页面
onFocus里调uni.pageScrollTo滚动,大概率失败:节点查不到、视口未稳定、boundingClientRect()返回null - iOS Safari 对
scrollIntoView支持不稳定,尤其当输入框在position: fixed或transform容器内时,经常失效
用 window.innerHeight 变化检测键盘弹出
这是 H5 端唯一可行的兜底方案,核心逻辑是监听窗口高度突变,并排除页面缩放、横竖屏切换等干扰。
- 注册
window.addEventListener('resize', handler),每次触发时取window.innerHeight - 记录上一次正常高度(比如页面加载完成后的值),设为
baseHeight - 当新高度比
baseHeight小150px以上,且持续 200ms 不变,才判定为键盘弹出 - 收起判断更关键:需等高度恢复到
baseHeight ± 10px并稳定 300ms,再清空状态,否则滚动会回跳 - 别用
setTimeout简单延时,要配合performance.now()或Date.now()做时间戳比对
滚动到输入框的时机和方式
H5 端不能依赖 uni.pageScrollTo,得用原生 scrollIntoView 或手动计算 scrollTop,但必须卡准时机。
- 不要在
@focus立即执行滚动:iOS 键盘动画约 300ms,此时getBoundingClientRect()可能返回错误坐标 - 推荐做法:在
resize判定为键盘弹出后,setTimeout(() => { scrollIntoView() }, 350) -
scrollIntoView({ block: 'nearest', inline: 'start' })比默认行为更稳,避免过度滚动 - 如果输入框在
scroll-view内,必须操作该容器的scrollTop,而非整个页面;用ref拿到容器 DOM 后调element.scrollTop = targetTop - container.offsetTop - 务必加
catch:Safari 有时抛TypeError: Illegal invocation,直接忽略即可
cursor-spacing 和 adjust-position 在 H5 端无效
这两个属性是 uni-app 编译到 App 平台时透传给原生 input 的,H5 端编译后就是普通 HTML <input> 标签,浏览器根本不认识它们。
- 写
adjust-position="true"或cursor-spacing="100"在 H5 页面里纯属冗余,Vue 会把它当普通 prop 渲染成 DOM 属性,但无任何效果 - 想控制光标与键盘距离,只能靠 CSS:给输入框父容器加
padding-bottom: 120px,并在键盘弹出时动态增减;但要注意,这会导致页面内容“被顶高”,需配合position: fixed或transform: translateY()补偿 - 真正可靠的留白策略是:键盘弹出时,把输入框所在区域设为
position: fixed; bottom: 0; width: 100%;,并用z-index确保它浮在键盘上方
最易被忽略的一点:iOS Safari 的 resize 事件在键盘收起后可能延迟触发,甚至漏发。不能只靠一次 height 恢复就重置状态,得结合 focusout + blur + visibilitychange 三重校验,否则用户切到其他 App 再切回来,页面状态就错乱了。











