react在安卓下輸入框被手機鍵盤遮擋問題

秋収冬藏發表於2019-03-01

問題概述

  今天遇到了一個問題,在安卓手機上,當我要點選輸入“店鋪名稱”時,手機軟鍵盤彈出來剛好把輸入框擋住了;擋住就算了,關鍵是頁面還不能向上滑動,整個手機視窗被壓為原來的二分之一左右;

    

react在安卓下輸入框被手機鍵盤遮擋問題

然後

  然後找了一些方案,不過不大適用,或者是有點麻煩;所以需要整合一下,
  首先,我想一下我要實現的效果

想要實現的效果

    

react在安卓下輸入框被手機鍵盤遮擋問題

  如圖,當手機鍵盤出現時,頁面是可以自由滾動的,而且當前聚焦的輸入框往紅線處靠齊,這樣就剛好在剩下的視窗的垂直正中間,這樣就不會出現輸入框被擋住,看不到自己輸入的內容了 ;

第一步,使螢幕壓小時,頁面內容可以滾動檢視

  如下圖所示,黑色框代表螢幕,藍色框代表頁面大小,當螢幕被壓小時,頁面內容必須保持原來的高度:
    

react在安卓下輸入框被手機鍵盤遮擋問題

  實現原理,頁面一進來時,我就獲取視窗的高度,給最外層的div設定一個最小高度,這樣就算視窗壓小了,頁面還能維持原來的高度,可以滾動瀏覽:

      let initWindowHeight=window.innerHeight
      let wrapDiv=document.getElementsByClassName(`animated-router-forward-enter-done`)[0]
      wrapDiv.style.minHeight =initWindowHeight+`px`
複製程式碼

第二步,滾到紅線處

(2018/9/3補充:關於第二步,評論區有更加簡單的實現方法)
  由於我們不能直接知道軟鍵盤什麼時候出來,不過軟鍵盤出來的時候視窗高度會縮小,所以我們可以通過監聽視窗大小變化事件來判斷軟鍵盤是否彈出,比如瀏覽器視窗高度突然縮小25%以上,那麼我們就認為是軟鍵盤出來了,然後我們獲取聚焦input距離頁面頂部的距離,計算距離紅線有多少距離,假設距離是60,那麼我們就讓頁面向上滾動60,這時input就剛剛好到了紅線處;

  window.onresize=function(){ 
        if(initWindowHeight-window.innerHeight>initWindowHeight/4&&document.querySelectorAll(`:focus`).length>0){
           //offset是封裝好的一個獲取元素距離頁面頂部滾動距離的方法
           if(offset(document.querySelectorAll(`:focus`)[0]).top>initWindowHeight/4){
             document.body.scrollTop=offset(document.querySelectorAll(`:focus`)[0]).top-initWindowHeight/4
           }
        }else if(window.innerHeight-initWindowHeight<20){
            document.body.scrollTop=0
        }
        
    };
複製程式碼

完整程式碼

  因為可能有多個頁面要呼叫,所以我把程式碼放到一個單獨的js檔案中:

function pageInputScroll() {
    
    let initWindowHeight=window.innerHeight
    setTimeout(() => {
      let wrapDiv=document.getElementsByClassName(`animated-router-forward-enter-done`)[0]
      //console.log(wrapDiv.style)
      wrapDiv.style.minHeight =initWindowHeight+`px`
         
     }, 500);
     //由於我們不能直接知道軟鍵盤什麼時候出來,不過軟鍵盤出來的時候視窗高度會縮小,所以我們可以通過監聽視窗大小變化事件來判斷軟鍵盤是否彈出
    window.onresize=function(){ //如果瀏覽器視窗高度縮小25%以上,就認為是軟鍵盤出來了
        if(initWindowHeight-window.innerHeight>initWindowHeight/4&&document.querySelectorAll(`:focus`).length>0){
           if(offset(document.querySelectorAll(`:focus`)[0]).top>initWindowHeight/4){
             document.body.scrollTop=offset(document.querySelectorAll(`:focus`)[0]).top-initWindowHeight/4
           }
        }else if(window.innerHeight-initWindowHeight<20){
            document.body.scrollTop=0
        }
        
    };
}
function offset(element) {
    var offest = {
        top: 0,
        left: 0
    };
 
    var _position;
 
    getOffset(element, true);
 
    return offest;
 
    // 遞迴獲取 offset, 可以考慮使用 getBoundingClientRect
    function getOffset(node, init) {
        // 非Element 終止遞迴
        if (node.nodeType !== 1) {
            return;
        }
        _position = window.getComputedStyle(node)[`position`];
 
        // position=static: 繼續遞迴父節點
        if (typeof(init) === `undefined` && _position === `static`) {
            getOffset(node.parentNode);
            return;
        }
        offest.top = node.offsetTop + offest.top - node.scrollTop;
        offest.left = node.offsetLeft + offest.left - node.scrollLeft;
 
        // position = fixed: 獲取值後退出遞迴
        if (_position === `fixed`) {
            return;
        }
 
        getOffset(node.parentNode);
    }
}

export {pageInputScroll};
複製程式碼

  在react頁面中引入js並呼叫:

  import {pageInputScroll} from `../../util/pageInputScroll`
  ......
  componentDidMount(){
       pageInputScroll()
   }
複製程式碼

  如果只是想在安卓下使用,可以加一個判斷:

  if(/Android/i.test(navigator.userAgent)){
      pageInputScroll()
  }
複製程式碼

效果動圖

  我在pc端的谷歌瀏覽器模擬一下實現的效果:

react在安卓下輸入框被手機鍵盤遮擋問題

備註

offset()方法是使用js實現類似jquery的offset()的一個方法,參考自:原生js實現offset方法

  

  

  推薦一個可以掃描商品條碼進行商品評論的小程式

  歡迎掃碼體驗:

react在安卓下輸入框被手機鍵盤遮擋問題

  

  

相關文章