1. 程式人生 > >鍵盤優雅彈出與ios游標亂飄解決方案

鍵盤優雅彈出與ios游標亂飄解決方案

前言

在移動開發中,會遇到這樣的情況,比如說有一個輸入框在最底部的時候,我們彈起輸入框,輸入框不會在輸入鍵盤上。
說明白簡單點就是,輸入框被鍵盤擋住了。而且在原生中,輸入框應該正好在輸入鍵盤上,但是h5 沒有這種體驗,那麼我們需要自己實現。
再次用圖說明情況。
情況一:

鍵盤擋住了,輸入框。

情況二:

紅色代表有滾動條,輸入框,沒有正好卡在下面,使用者體驗不好,同樣輸入的時候不能滑動體驗也不好。

開工

正確情況:

要做的其實就是兩步:

第一步,動態改變可滑動的高度,就是在輸入的時候可以通過滑動看到下面藍色的部分:

第二部,需要修改滾動距離:

也就是需要滾動多少,輸入框才剛好在鍵盤下。那這個怎麼移動呢?我們該如何滾動才能完成呢?


計算滾動的距離,其實就是計算輸入框移動的距離。
這個問題就簡單了,分兩種情況,其實就一種哈。
假如輸入框在上面:

就是我們滑動塊的底部到頂部的距離-輸入框底部到頂部的距離

加入輸入框在鍵盤下面:

就不畫了,也是我們滑動塊的底部到頂部的距離-輸入框底部到頂部的距離,只不過我們得到的是負數,正好我們對應了我們滑動的方向。

好的,現在我們要做的就是實現這兩步。

如何修改鍵盤彈起的高度?

我們只要知道鍵盤的高度和螢幕的高度即可。

螢幕高度,我們不需要去知道,因為需要修改樣式,直接100vh-鍵盤高度即可。

鍵盤的高度如下:

window.addEventListener("keyboardWillShow", this.keyboardShowCallback);

在keyboardShowCallback有個引數是e:

public keyboardShowCallback = (e) => {
e.keyboardHeight;// 取得鍵盤的高度
})

在這裡,因為我的滑動塊是全屏的,那麼我可以這樣:

public keyboardShowCallback = (e) => {
//page 是我當前頁面的滑動塊,100vh就是螢幕高度
page.setAttribute('style', 'height:calc(100vh - ' + e.keyboardHeight + 'px) !important;z-index:150;');
})

那麼如何獲取當前正在輸入的輸入框,只要獲取當前焦點的位置 document.activeElement:

var rect = document.activeElement.getBoundingClientRect();

通過getBoundingClientRect 獲取到輸入框各個位置到螢幕的距離:

我們需要的是輸入框的底部,那麼就是: rect.bottom;

那麼我們計算滑動距離就是:

scrolldiv//表示可滑動的元素

var scrolldivrect = scrolldiv.getBoundingClientRect();

var addScrollTop = rect.bottom - scrolldivrect.bottom;

scrolldiv.scrollTop = scrolldiv.scrollTop + addScrollTop;

接下來就是鍵盤收起來的時候恢復:

// 監聽鍵盤隱藏
window.addEventListener("keyboardWillHide", this.keyboardHideCallback);
//恢復事件
page.setAttribute('style', 'height: 100vh !important;z-index:120;');

在這裡,其實就已經實現效果了,那麼這時候會在一些平臺上遇到一些問題。

遇到的問題

ios 游標亂飄

造成原因,是因為我們設定滑動了,在低版本如ipad mini3上會出現游標和輸入框不對應。

那麼這個時候,我繼續輸入,或者我點一下其他地方游標又正常了。

這時候給了我線索,我需要重繪這個input 就行。那麼如何重新繪製呢?我們無法操作啊。但是我們知道如果改變某些樣式是會觸發重繪過程,具體檢視標準。

code 如下:

var activeElement = document.activeElement; //取得focus的dom元素
setTimeout(function () {
if (activeElement) {
  if (activeElement.nodeName == "TEXTAREA" || activeElement.nodeName == 'INPUT') { //如果是input或textarea
    if ((Object)(activeElement).style.textShadow === '') {
      (Object)(activeElement).style.textShadow = 'rgba(0,0,0,0) 0 0 0'; //改變某個不可見樣式,觸發dom重繪
    } else {
      (Object)(activeElement).style.textShadow = '';
    }
  }
}
}, 0);

收起鍵盤出現白屏,在低版本上連續彈起鍵盤白屏無消失

這個問題得回到設計的根源上。

在我們收起鍵盤的時候,我們就會讓紅色部分為100%;
鍵盤收齊向下,然後紅色向下,如果鍵盤收起速度,大於紅色向下增大的速度,就會出現一點白,然後消失。

怎麼解決呢?

紅色部分是我們滾動的部分,藍色是content,這時候讓content設定為100%vh,這時候馬上可視區域就會馬上重繪。
在keyboardHideCallback 中

var num = Math.random() * 99;
ionContent.setAttribute('style', 'height: 100vh !important;z-index:' + num + '');

當然,然後要在keyboardShowCallback 中設定為100%,如何不設定回去,鍵盤彈起就會擋住輸入框:

var num = Math.random() * 99;
ionContent.setAttribute('style', 'height: 100% !important;z-index:' + num + '');

總結

如果要相容一些低版本,需要主動觸發去讓一些區域重新整理,這些可以解決大部分白屏問題,或者其他疑難雜症(如游標漂移)。