• H5 移动端 键盘遮挡焦点元素解决方案


    前言


    最近在做 webapp,遇到了很多移动端兼容的问题,其中一个问题就是:输入框触发 focus 后,键盘弹出,然后遮住了输入框。

    然后在AndroidIOS上,这个问题的表现形式不一样,而原生键盘和第三方键盘也不一样,但引起的问题都是一样的:输入框被遮住了。

    需要的效果


    在键盘弹出时,获得焦点的输入框要在可视区域内,效果如下图:

    键盘弹出、收起的表现


    1. IOS:

      输入框获取焦点,键盘弹出,webview高度不会改变,但webview会往上滚,且最大滚动高度scrollTop为键盘高度。

      点击键盘上的收起按钮,或者输入框以外的页面区域时,输入框失去焦点,键盘收起。

    2. Android:

      输入框获取焦点,键盘弹出,但是webview高度会发生改变,高度为原高度减去软键盘高度。

      点击输入框以外的区域时,输入框失去焦点,软键盘收起。而点击键盘上的收起按钮时,键盘收起 ,但输入框并不会失去焦点,

    解决方案


    当输入框被挡住,在IOS中,webview会往上滚一段距离,使得获取焦点的输入框自动处于可视区,而在Android里,只会改变webview高度,而不会发生焦点元素滚动到可视区的事情。

    所以IOS可以不用管,而Android需要在键盘弹出的时候,将输入框滚动到可视区。

    获取设备类型


    首先是要获取设备类型,通过navigator.userAgent获取即可。

    const judgeDeviceType = (() => {
      let deviceType = null;
    
      return () => {
        if (!deviceType) {
          const ua = window.navigator.userAgent.toLocaleLowerCase();
          const isIOS = /iphone|ipad|ipod/.test(ua);
          const isAndroid = /android/.test(ua);
          const isMiuiBrowser = /miuibrowser/.test(ua);
    
          deviceType = {
            isIOS: isIOS,
            isAndroid: isAndroid,
            isMiuiBrowser: isMiuiBrowser
          };
        }
    
        return deviceType;
      };
    })();
    

    监听事件


    IOS 可以通过focusblur事件监听键盘弹出、收起,但 Android 不行,但因为webview高度会变,所以通过监听resize事件解决。

    export function listenAndroidKeybord() {
      const { isAndroid } = judgeDeviceType();
    
      if (isAndroid) {
        const androidResize = function() {
          // 将当前焦点元素滚动到可视区
          activeElementScrollIntoView();
        };
    
        // android 键盘弹出、收起,可视区高度会发生变化
        window.addEventListener('resize', androidResize, false);
    
        return () => {
          window.removeEventListener('resize', androidResize, false);
        };
      }
    }
    

    将元素滚动到可视区


    要将元素滚动到可视区,主要有两个方法:scrollIntoViewscrollIntoViewIfNeeded,兼容性在移动端都很不错。

    function activeElementScrollIntoView() {
      const activeEl = document.activeElement;
    
      if (
        activeEl.tagName === 'INPUT' || 
        activeEl.tagName === 'TEXTAREA'
      ) {
        window.setTimeout(() => {
          if ('scrollIntoView' in activeEl) {
            activeElt.scrollIntoView();
          } else {
            activeEl.scrollIntoViewIfNeeded();
          }
        }, 100);
      }
    }
    

    MiuiBrowser


    以上代码可以说解决了大部分浏览器键盘遮挡问题了,但我用自己的小米手机自带的小米浏览器测试时,出了问题,键盘弹出,页面纹丝不动,手动去拖,有时行,有时不行。

    搞了很久,发现了两个问题,我这手机上自带的小米浏览器,userAgent 上没有带Android标识,但有MiuiBrowser标识,。然后,页面有时能拖动,有时不能拖动,我猜应该是webview的可视区高度变化有问题,或者是我的代码监听resize导致有问题。

    解决方案

    1. 增加设备类型判断

      const ua = window.navigator.userAgent.toLocaleLowerCase();
      const isMiuiBrowser = /miuibrowser/.test(ua);
      
    2. 通过监听focusblur事件来监听键盘弹出、收起,然后给body加高度

      body, html {
        height: 100%;
      }
      
      function listenMiuiBrowserKeybord() {
        const { isMiuiBrowser } = judgeDeviceType();
      
        if (isMiuiBrowser) {
          const inputFocus = function() {
            document.body.style.marginBottom = '50px';
            activeElementScrollIntoView();
          };
      
          const inputBlur = function() {
            document.body.style.marginBottom = '0px';
            activeElementScrollIntoView();
          };
      
          let $inputs = document.getElementsByTagName('input');
          for (let i = 0; i < $inputs.length; i++) {
            $inputs[i].addEventListener('focus', inputFocus, false);
            $inputs[i].addEventListener('blur', inputBlur, false);
          }
      
          return () => {
            for (let i = 0; i < $inputs.length; i++) {
              $inputs[i].removeEventListener('focus', inputFocus, false);
              $inputs[i].removeEventListener('blur', inputBlur, false);
            }
          };
        }
      }
      

    坑点:这种方案虽然解决了弹出问题,但点击键盘收起按钮,Android 下输入框并不会失去焦点,需要失去焦点才能让 body 增加的高度变为 0。

    备注


    解决方案并不完善,踩坑路漫漫。

  • 相关阅读:
    chapter01
    2019.07.11
    系统进程
    Linex第五-第七章
    Linex第三章第四章
    Linux 系统管理 第二章第三章
    2019/7/24
    使用.htaccess进行浏览器图片文件缓存
    div+css3实现漂亮的多彩标签云,鼠标移动会有动画
    搜索排序的作弊与反作弊,面壁人与智子的巅峰对决
  • 原文地址:https://www.cnblogs.com/guolao/p/11936709.html
Copyright © 2020-2023  润新知