H5 (React) 移动端监听软键盘弹起、收起

前言

H5 有时底部按钮是固定定位,当页面上面需要用到输入内容时,会弹起软键盘,然后把底部固定的按钮也弹起来了,我们希望弹起软键盘时,底部的固定定位按钮隐藏,这里就需要对移动端软键盘弹起收起进行监听。

解决方法

// ------------------------------utils.ts-------------------------------

/**
 * 监听移动端软键盘弹起
 * @param callback
 */
export const monitorSoftKeyboard: Function = (
  callback: ({ isUp, isDown }: { isUp?: boolean; isDown?: boolean }) => void
) => {
  const originalHeight = document.documentElement.clientHeight || document.body.clientHeight;
  const onResize = () => {
    // 键盘弹起与隐藏都会引起窗口的高度发生变化
    const resizeHeight = document.documentElement.clientHeight || document.body.clientHeight;
    // 由于IOS大屏手机特殊原因,弹起软键盘再恢复的大小和一开始的有落差,可能比原来小,或者比原来大,差值20符合大部分情况,
    // 而大部分键盘弹起的高度远不止20,所以无其他影响,为兼容部分IOS处理
    const acceptableRange = 20;
    if (Math.abs(originalHeight - resizeHeight) <= acceptableRange) {
      // 初次记录的原始高度 和 后面变化resizeHeight,如果差值小于20,则表示软键盘已收起
      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();
  };
}, []);

Hooks 实现形式

import { useEffect, useState } from 'react';

/**
 * 监听移动端软键盘弹起
 * @returns
 */
const useMonitorSoftKeyboard = () => {
  // 记录软键盘是否降下(收起), 默认是收起的
  const [isDownSoftKeyboard, setIsDownSoftKeyboard] = useState<boolean>(true);

  useEffect(() => {
    // 初始化页面之后,记录原窗口高度
    const originalHeight = document.documentElement.clientHeight || document.body.clientHeight;

    const monitorSoftKeyboard = () => {
      // 键盘弹起与隐藏都会引起窗口的高度发生变化
      const resizeHeight = document.documentElement.clientHeight || document.body.clientHeight;
      // 由于IOS大屏手机特殊原因,弹起软键盘再恢复的大小和一开始的有落差,可能比原来小,或者比原来大,差值20符合大部分情况,
      // 而大部分键盘弹起的高度远不止20,所以无其他影响,为兼容部分IOS处理
      const acceptableRange = 20;
      if (Math.abs(originalHeight - resizeHeight) < acceptableRange) {
        // 初次记录的原始高度 和 后面变化resizeHeight,如果差值小于20,则表示软键盘已收起
        setIsDownSoftKeyboard(true);
      } else {
        // 软键盘弹起
        setIsDownSoftKeyboard(false);
      }
    };

    window.addEventListener('resize', monitorSoftKeyboard);

    return () => {
      window.removeEventListener('resize', monitorSoftKeyboard);
    };
  }, []);

  return { isDownSoftKeyboard, isUpSoftKeyboard: !isDownSoftKeyboard } as {
    isDownSoftKeyboard: boolean;
    isUpSoftKeyboard: boolean;
  };
};

export default useMonitorSoftKeyboard;

解释

  1. 在android中软键盘弹起或收起时,会改变window的高度,因此监听window的onresize事件;但是 ios 中软键盘的弹起收起并不触发 window.onresize 事件;
  2. 在 ios 中软键盘弹起时,仅会引起 scrollTop 值改变,但是我们可以通过输入框的获取焦点情况来做判断,但也只能在 ios 中采用这个方案,因为在 android 中存在主动收起键盘后,但输入框并没有失焦,而ios中键盘收起后就会失焦;
  3. 另外,focusin和focusout支持冒泡,对应focus和blur, 使用focusin和focusout的原因是focusin和focusout可以冒泡,focus和blur不会冒泡,这样就可以使用事件代理,处理多个输入框存在的情况。

你可能感兴趣的:(React,前端常见,前端,react.js,android,ios,react,native)