前言
H5 有时底部按钮是固定定位,当页面上面需要用到输入内容时,会弹起软键盘,然后把底部固定的按钮也弹起来了,我们希望弹起软键盘时,底部的固定定位按钮隐藏,这里就需要对移动端软键盘弹起收起进行监听。而且也解决部分IOS手机的兼容问题。
一、解决方法
/**
* 监听H5软键盘弹起
* @param callback
* @param differenceRange
* @returns
*/
export const monitorSoftKeyboard: Function = (
callback: ({ isUp, isDown }: { isUp?: boolean; isDown?: boolean }) => void, // 监听软键盘弹起或降落的回调
differenceRange: number = 20 // 默认差值范围 20
) => {
const originalHeight =
document.documentElement.clientHeight || document.body.clientHeight;
const onResize = () => {
// 键盘弹起与隐藏都会引起窗口的高度发生变化,这是主要的监听依据;
const resizeHeight =
document.documentElement.clientHeight || document.body.clientHeight;
// 兼容IOS系统的某些大屏手机【从未弹起的软键盘clientHeight】和【弹起再收起后的clientHeight】不完全相同,存在差值;
// 如果差值小于默认差值范围,即20,则认为软键盘已收起。
if (Math.abs(originalHeight - resizeHeight) <= differenceRange) {
// 软键盘收起
callback({ isUp: false, isDown: true });
} else {
// 软键盘弹起
callback({ isUp: true, isDown: false });
}
};
window.addEventListener("resize", onResize);
return () => window.removeEventListener("resize", onResize);
};
// ------------------------------page.tsx-------------------------------
const [showBottom, setShowBottom] = useState<boolean>(true);
useEffect(() => {
const remove = monitorSoftKeyboard(({ isDown }) => {
if (isDown) {
setShowBottom(true);
} else {
setShowBottom(false);
}
});
return () => {
remove();
};
}, []);
二、React Hook 实现形式
import { useEffect, useState } from 'react';
type MonitorSoftKeyboardAction = {
/**
* 软键盘是否收起
*/
isDown?: boolean;
/**
* 软键盘是否弹起
*/
isUp?: boolean;
};
type Props = {
/**
* 监听软键盘弹起或收起的回调
* @param params
* @returns
*/
callback?: (params?: MonitorSoftKeyboardAction) => void;
/**
* 差值范围,默认 20,兼容IOS可用
*/
differenceRange?: number; // 差值范围,默认 20,兼容IOS可用
};
// 默认差值范围 20
const DIFFERENCE_RANGE = 20;
/**
* 监听H5软键盘弹起&收起
* @param props
* @returns
*/
const useMonitorSoftKeyboard = (props?: Props) => {
const [isDown, setIsDown] = useState<boolean>(true);
useEffect(() => {
const originalHeight = document.documentElement.clientHeight || document.body.clientHeight;
const monitorSoftKeyboard = () => {
// 键盘弹起与隐藏都会引起窗口的高度发生变化,这是主要的监听依据;
const resizeHeight = document.documentElement.clientHeight || document.body.clientHeight;
// 默认差值范围 20
const differenceRange =
typeof props?.differenceRange === 'number' ? props?.differenceRange : DIFFERENCE_RANGE;
// 兼容IOS系统的某些大屏手机【从未弹起的软键盘clientHeight】和【弹起再收起后的clientHeight】不完全相同,存在差值;
// 如果差值小于默认差值范围,即20,则认为软键盘已收起。
if (Math.abs(originalHeight - resizeHeight) < differenceRange) {
// 软键盘收起
setIsDown(true);
props?.callback?.({ isDown: true, isUp: false });
} else {
// 软键盘弹起
setIsDown(false);
props?.callback?.({ isDown: false, isUp: true });
}
};
window.addEventListener('resize', monitorSoftKeyboard);
return () => {
window.removeEventListener('resize', monitorSoftKeyboard);
};
}, [props]);
return { isDown, isUp: !isDown } as MonitorSoftKeyboardAction;
};
export default useMonitorSoftKeyboard;
三、解释
- 在 iOS 系统中,软键盘的弹起和收起确实不会触发
window.onresize
事件。这是一个已知的行为,与 Android 系统不同,Android 系统在软键盘弹起和收起时会触发window.onresize
事件; - 在 iOS 中软键盘弹起时,仅会引起
scrollTop
值改变,虽然我们可以通过输入框的获取焦点情况来做判断,但也只能在 iOS 中采用这个方案,因为在 Android 中存在主动收起键盘后,输入框并没有失焦,而 iOS 中键盘收起后就会失焦; - 无论 iOS 还是 Android 在软键盘弹起的时候,会改变 body 的可视区域,也就是
clientHeight
;