H5 移動端 鍵盤遮擋焦點元素解決方案

来源:https://www.cnblogs.com/guolao/archive/2019/11/26/11936709.html
-Advertisement-
Play Games

前言 最近在做 webapp,遇到了很多移動端相容的問題,其中一個問題就是:輸入框觸發 focus 後,鍵盤彈出,然後遮住了輸入框。 然後在 和`IOS`上,這個問題的表現形式不一樣,而原生鍵盤和第三方鍵盤也不一樣,但引起的問題都是一樣的:輸入框被遮住了。 需要的效果 在鍵盤彈出時,獲得焦點的輸入框 ...


前言


最近在做 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。

備註


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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • avaScript操作資料庫JS操作Access資料庫,跟其他語言操作差不多,總結了一下習慣代碼,僅供參考學習。現在在F盤有文件abc.mdf,表名為Student,一共2個欄位,Id數字類型主鍵,stuName文本類型,現對該表進行增刪改查的操作: 1.查詢<HTML><HEAD><TITLE>數 ...
  • var LayVerifyExtend = { notnullNonnegativeInteger: function (value, item) { //value:表單的值、item:表單的DOM對象 if (!/^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\d+)?$/.t ...
  • 1、新建一個layui.extend.js文件,頁面調用時這個文件放到layui.js後面。 2、基礎的配置卸載config中,擴展的組件寫入extend,組件的路徑是相對於config下base的路徑。 例如: layui.config({ version: false, //一般用於更新模塊緩存 ...
  • rem佈局 1. 技術選型 方案:採取單獨製作移動頁面方案 技術:佈局採取rem適配佈局(less rem+媒體查詢) 設計圖紙:750px尺寸 2. 相關文件夾結構 3. 設置視口標簽以及引入初始化央視 ~~~html ~~~ 4. 設置公共的common.less文件 設置好最常見的屏幕尺寸,利 ...
  • 今天,在頁面上碰到一個非 select 標簽的下拉框,打算進行定位和模擬選中。 <input aria-invalid="false" autocomplete="disabled" placeholder="請選擇" type="text" class="AABBCC-input DDCC-inp ...
  • 1.在指南的緩存章節里webpack.config.js文件中,使用new的方法會報錯 const webpack = require('webpack'); + new webpack.optimize.CommonsChunkPlugin({ + name: 'vendor' + }), new ...
  • 運用Taro實現多端導航欄/tabbar實例 (H5 + 小程式 + React Native) 最近一直在搗鼓taro開發,雖說官網介紹支持編譯到多端,但是網上大多數實例都是H5、小程式,很少有支持RN端。恰好Taro是基於React技術,想著之前也做過一些react項目,如是抱著好奇深究了一番, ...
  • 練習1:求兩個數字的和:獲取任意的兩個數字的和 function getSum(x, y) { return x + y; } console.log(getSum(10, 20)); 練習2:求1-100之間所有的數字的和 function geteverySum() { var sum = 0; ...
一周排行
    -Advertisement-
    Play Games
  • Dapr Outbox 是1.12中的功能。 本文只介紹Dapr Outbox 執行流程,Dapr Outbox基本用法請閱讀官方文檔 。本文中appID=order-processor,topic=orders 本文前提知識:熟悉Dapr狀態管理、Dapr發佈訂閱和Outbox 模式。 Outbo ...
  • 引言 在前幾章我們深度講解了單元測試和集成測試的基礎知識,這一章我們來講解一下代碼覆蓋率,代碼覆蓋率是單元測試運行的度量值,覆蓋率通常以百分比表示,用於衡量代碼被測試覆蓋的程度,幫助開發人員評估測試用例的質量和代碼的健壯性。常見的覆蓋率包括語句覆蓋率(Line Coverage)、分支覆蓋率(Bra ...
  • 前言 本文介紹瞭如何使用S7.NET庫實現對西門子PLC DB塊數據的讀寫,記錄了使用電腦模擬,模擬PLC,自至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1.Windows環境下鏈路層網路訪問的行業標準工具(WinPcap_4_1_3.exe)下載鏈接:http ...
  • 從依賴倒置原則(Dependency Inversion Principle, DIP)到控制反轉(Inversion of Control, IoC)再到依賴註入(Dependency Injection, DI)的演進過程,我們可以理解為一種逐步抽象和解耦的設計思想。這種思想在C#等面向對象的編 ...
  • 關於Python中的私有屬性和私有方法 Python對於類的成員沒有嚴格的訪問控制限制,這與其他面相對對象語言有區別。關於私有屬性和私有方法,有如下要點: 1、通常我們約定,兩個下劃線開頭的屬性是私有的(private)。其他為公共的(public); 2、類內部可以訪問私有屬性(方法); 3、類外 ...
  • C++ 訪問說明符 訪問說明符是 C++ 中控制類成員(屬性和方法)可訪問性的關鍵字。它們用於封裝類數據並保護其免受意外修改或濫用。 三種訪問說明符: public:允許從類外部的任何地方訪問成員。 private:僅允許在類內部訪問成員。 protected:允許在類內部及其派生類中訪問成員。 示 ...
  • 寫這個隨筆說一下C++的static_cast和dynamic_cast用在子類與父類的指針轉換時的一些事宜。首先,【static_cast,dynamic_cast】【父類指針,子類指針】,兩兩一組,共有4種組合:用 static_cast 父類轉子類、用 static_cast 子類轉父類、使用 ...
  • /******************************************************************************************************** * * * 設計雙向鏈表的介面 * * * * Copyright (c) 2023-2 ...
  • 相信接觸過spring做開發的小伙伴們一定使用過@ComponentScan註解 @ComponentScan("com.wangm.lifecycle") public class AppConfig { } @ComponentScan指定basePackage,將包下的類按照一定規則註冊成Be ...
  • 操作系統 :CentOS 7.6_x64 opensips版本: 2.4.9 python版本:2.7.5 python作為腳本語言,使用起來很方便,查了下opensips的文檔,支持使用python腳本寫邏輯代碼。今天整理下CentOS7環境下opensips2.4.9的python模塊筆記及使用 ...