天天看點

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

前言

今天來公司的主要目的就是研究虛拟鍵盤與fixed的問題,期間因為同僚問起閉包與事件委托(阻止冒泡)相關問題,便穿插了一篇别的:

【小貼士】工作中的”閉包“與事件委托的”阻止冒泡“,有興趣的朋友可以去看看,因為首頁隻能放一篇,這個就略去了

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

問題源頭

移動端虛拟鍵盤出現的條件是:文本框(文本類)獲得焦點

但是文本框獲得焦點未必會彈出鍵盤!!!

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

PS:總而言之,我們認為會出現或者消失虛拟鍵盤的時候都可能不工作

在移動裝置上,如果文本框在上方,點選不會有什麼問題:

在裝置的最下面的話,就有所不同了,整個塊會上移,以将input區域顯示出來

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

① 虛拟鍵盤的出現對頁面來說是不可知的,這句話的了解是:沒有鍵盤出現事件,沒有辦法擷取鍵盤高度

② 鍵盤是“貼”在了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.res = null;

var i = 0;

  alert(i++);

    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以及虛拟鍵盤相關

本文轉自葉小钗部落格園部落格,原文連結http://www.cnblogs.com/yexiaochai/p/3561939.html,如需轉載請自行聯系原作者

繼續閱讀