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。

備注


解決方案並不完善,踩坑路漫漫。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM