公众号:程序员白特,欢迎一起交流学习~
来源:DAHUIAAAAAA,https://juejin.cn/post/7338335869709385780?searchId=20240424162151EE1DFC79521D9C9269CA
实现效果
话不多说,先上效果和 demo 地址:
demo 地址:https://codesandbox.io/p/devbox/keyboard-7fsqr8?file=%2Fsrc%2Fkeyboard.ts%3A54%2C24
体验地址:https://7fsqr8-5173.csb.app
实现原理
要实现一个吸附在键盘上的 input,可以分为以下步骤:
- 监听键盘高度的变化
- 获取「键盘顶部距离视口顶部的高度」
- 设置 input 的位置
第一步:监听监听键盘键盘高度的变化
要监听键盘高度的变化,我们得先看看在键盘展开或收起的时候,分别会触发哪些浏览器事件:
-
iOS 和部分 Android 浏览器
展开:键盘展示时会依次触发 visualViewport resize -> focusin -> visualViewport scroll,部分情况下手动调用 input.focus 不触发 focusin
收起:键盘收起时会依次触发 visualViewport resize -> focusout -> visualViewport scroll
-
其他 Android 浏览器
展开:键盘展示的时候会触发一段连续的 window resize,约过 200 毫秒稳定
收起:键盘收起的时候会触发一段连续的 window resize,约过 200 毫秒稳定,但是部分手机上有些异常的 case:键盘收起时 viewport 会先变小,然后变大,最后再变小
总结两者来看,我们要监听键盘高度的变化,可以添加以下监听事件:
if (window.visualViewport) {
window.visualViewport?.addEventListener("resize", listener);
window.visualViewport?.addEventListener("scroll", listener);
} else {
window.addEventListener("resize", listener);
}
window.addEventListener("focusin", listener);
window.addEventListener("focusout", listener);
===========================
📚 题外话: 获取键盘展开和收起状态
===========================
在实际业务中,获取键盘展开和收起的状态,同样很常见,要完成状态的判断,我们可以设定以下规则:
判断键盘展开:当 visualViewport resize/window.reszie、visualViewport scroll、focusin 任意一个事件触发时,如果高度减少,并且屏幕减少的高度(键盘高度)大于 200px 时,判断键盘为展开状态(由于 focusin 部分情况下不触发,所以还需要监听其他事件辅助判断键盘是否为展开状态)
判断键盘收起:当 visualViewport resize/window.reszie、visualViewport scroll、focusout 任意一个事件触发时,如果高度增加,并且屏幕减少的高度(键盘高度)小于 200px,判断键盘为收起状态
// 获取当前视口高度
const height = window.visualViewport
? window.visualViewport.height
: window.innerHeight;
// 获取视口增量:视口高度 - 上次获取的视口高度
const diffHeight = height - lastWinHeight;
// 获取键盘高度:默认屏幕高度 - 当前视口高度
const keyboardHeight = DEFAULT_HEIGHT - height;
// 如果高度减少,且键盘高度大于 200,则视为键盘弹起
if (diffHeight < 0 && keyboardHeight > 200) {
onKeyboardShow();
} else if (diff > 0) {
onKeyboardHide();
}
同时,为了避免 “收起时 viewport 会先变小,然后变大,最后再变小” 这种