【小貼士】虛擬鍵盤與fixed帶給移動端的痛!

前言

今天來公司的主要目的就是研究虛擬鍵盤與fixed的問題,期間由於同事問起閉包與事件委託(阻止冒泡)相關問題,便穿插了一篇別的:css

【小貼士】工做中的」閉包「與事件委託的」阻止冒泡「,有興趣的朋友能夠去看看,由於首頁只能放一篇,這個就略去了html

如今回到主要研究點,首先在移動端咱們點擊文本框後會出現一個虛擬鍵盤, 虛擬鍵盤讓頁面可視區域獲得了充分利用,可是也帶來了一些問題node

問題源頭

移動端虛擬鍵盤出現的條件是:文本框(文本類)得到焦點閉包

可是文本框得到焦點未必會彈出鍵盤!!!app

收起虛擬鍵盤的條件是:文本框失焦dom

PS:總而言之,咱們認爲會出現或者消失虛擬鍵盤的時候均可能不工做ide

在移動設備上,若是文本框在上方,點擊不會有什麼問題:
在設備的最下面的話,就有所不一樣了,整個塊會上移,以將input區域顯示出來post

這個時候幾個棘手的問題就出現了:學習

① 虛擬鍵盤的出現對頁面來講是不可知的,這句話的理解是:沒有鍵盤出現事件,沒有辦法獲取鍵盤高度測試

② 鍵盤是「貼」在了viewport上,表面上不會對dom產生「任何」影響,可是這個時候一些定位元素的表現卻變得「怪異」

好比:

能夠看到,不管淘寶或者新浪,這個問題都存在,如今比較廣泛的解決方案都是:移動端不採用fixed屬性

因而咱們來看看是否有其它方案

iscroll是否能解決

其實這個方案在週四的時候我便測試過了,可是結果讓人很遺憾

 

 

做爲官方給出的例子,在虛擬鍵盤彈出來後,光標會亂跑,這個還能夠接受,可是:

① 頭部不見了

② 偶爾不能顯示得到焦點的input

這兩個問題就讓人難以接受了,因而,咱們須要找到其餘方案

解決方案

其實這個問題若是真要較真的話,我以爲須要深刻研究兩個知識點:

① viewport的原理

② 虛擬鍵盤的原理

就我手裏現有資源來講,兩個知識點一個都不深刻,因此只能先從應用層面解決問題

應用層面解決方案

咱們想到這麼一個場景,若是咱們能監控到鍵盤的行爲,若是能的話,咱們即可以

① 鍵盤彈出時候將fixed元素設置爲static

② 鍵盤消失時候將fixed元素設置爲fixed

那麼咱們能嗎???

雖然這個方案比較噁心,咱們還真能......答案是監控dom變化!

監控鍵盤

監控的方式其實篩選下來也不過兩種:

① 時鐘setInterval不停監控

② 系統級別的監控,好比鍵盤出現時候通知window一個事件,可是很遺憾如今尚未這個事件,可是這個事件等於

input類元素獲取焦點 == 彈出虛擬鍵盤

input類元素失去焦點 == 收起虛擬鍵盤

可是咱們前面已經說過,上面的原則不必定可靠,因此該種方案也未必可靠了

基於系統監控這點,咱們還能夠監控resize事件或者scroll事件,可是通過個人測試,setInterval表現比較好

因而,咱們簡單寫一段代碼,可靠是否知足需求:

window.alert = function (msg) {
  $('body').append('<div>' + msg + '</div>')
};
function fixedWatch(el) {
  if(document.activeElement.nodeName == 'INPUT'){
    el.css('position', 'static');
  } else {
    el.css('position', 'fixed');
  }
}

setInterval(function () {
  fixedWatch($('#headerview header'));
}, 500);

根據測試結果來講,是知足咱們的需求的,這裏的header不會出問題,可是footer因爲沒有處理仍然會錯位

 

因而這個問題彷佛被咱們修復了,可是你能夠接受嗎???這個方案有一個致命的噁心點!

不停的監控dom變化,浪費資源

那麼這個問題可優化麼?

彷佛是可優化的,可是依舊會帶來不少問題,優化的入口與出口即是input標籤的focus事件

至於其失焦相關的事件便不予關注了,由於可能由一個input跳到另外一個input

setTimeout(function () {
  $('#dl_app img').hide();
}, 100);

window.alert = function (msg) {
  $('body').append('<div>' + msg + '</div>')
};

window.res = null;
var i = 0;

function fixedWatch(el) {
  alert(i++);
  if(document.activeElement.nodeName == 'INPUT'){
    el.css('position', 'static');
  } else {
    el.css('position', 'fixed');
    if(window.res ) { clearInterval(window.res ); window.res  = null; }
  }
}

$('input').focus(function () {
  if(!window.res) {
    fixedWatch($('#headerview header'));
    window.res = setInterval(function () {
      fixedWatch($('#headerview header'));
    }, 500);
  }
});

這樣的話,貌似能讓代碼看上去舒服一點,可是其代價倒是全部input類標籤都會多一個得到焦點事件,依舊使人痛惜

結語

今天的學習暫時到此,對於虛擬鍵盤的出現其實可能還有其餘的問題,舉一個例子來講:

若是咱們點擊按鈕時候會出一個toast在中間,可是虛擬鍵盤恰好遮住了toast提示信息怎麼辦呢?這個問題與上述問題實際上是一致的

而後這個解決方案的可接受程度,以及其實際是否解決了問題又或者引發了其它問題就須要實際證實了

至於各位有什麼好的解決方案,或者想法,能夠討論討論哦!!!

好了,今天暫時到這裏,咱們下次繼續,若是有可能咱們會詳細學習下viewport以及虛擬鍵盤相關

相關文章
相關標籤/搜索