1. 程式人生 > >移動端 Web 頁 input 控制軟鍵盤

移動端 Web 頁 input 控制軟鍵盤

utm 填寫信息 web前端 忽略 瀏覽器中 cnblogs click 折騰 quest

從交互層面上來講,完成一個功能(獲得想要的信息)的過程稱之為用戶路徑。用戶路徑越長,完成功能的復雜度就越高,用戶體驗也就越差。因此當打開一個需要用戶填寫信息的表單界面時,為了提高可用性,PC 端一般會將光標聚焦到對應輸入框(input),移動端也是同理,讓對應的 input 獲得 focus 狀態,喚起軟鍵盤,方便用戶直接輸入。
本文暫且不論 PC 端的場景,在移動端(iOS、Android)實現這個看似不起眼的效果其實是需要經過一番折騰,我們慢慢往下看以下三種常用場景。

一、當進入表單頁時,讓軟鍵盤自動打開

這個需求比較常見,但是也是最棘手的。講科學的話,我們可以直接在 JS 裏獲取 input ,給它 focus 下就搞定了。但是這在移動端瀏覽器裏是行不通的。。
另外,H5 提供了 autofocus 屬性,這個屬性的兼容性在 caniuse 上顯示並不支持 iOS Safari,Android 也是要到 4.4 才開始支持,因此我們可以忽略這個屬性,不過下文會再次提到這個屬性。


因此在 iOS 裏想要在頁面 load 完成後自動聚焦 input,打開鍵盤目前來講不是很現實。
最難過的是 Android 也不行,目前進行了簡單的測試系統瀏覽器和 App 內嵌 WebView,H5 中的 input 是聚焦狀態,但是無法喚起鍵盤,鍵盤,鍵盤。。。
場景一,暫時無解……(下文提到在 Hybrid App 中可以實現)

二、當點擊頁面中某個元素喚起軟鍵盤

這個相對於場景一,多了用戶交互這一步。那麽這樣是不是就可以使用 JS 在 iOS 上成功的喚起鍵盤了呢?答案是肯定的。

<!-- HTML -->

<input id="input" type="text" placeholder="this a input"/>

<button id="J-focus-btn" onclick="clickFocusBtn()">focus input</button>

// JS

function clickFocusBtn() {

document.getElementById("input").focus();

}

如果有使用 zepto 的童鞋,這邊需要註意下為了 iOS,你不能使用 tap 事件。

// JS zepto

$(‘#J-focus-btn‘).on(‘tap‘, function() {

$(‘#input‘).focus();

});

如上使用了 zepto tap 事件,它在 iOS 上並不能達到預期效果,這裏面就涉及到了 iOS WebView 的一種默認安全機制。在 UIWebView 中有一個屬性:

@property (nonatomic) BOOL keyboardDisplayRequiresUserAction NS_AVAILABLE_IOS(6_0); // default is YES

這個屬性默認是 YES,也就是說鍵盤的出現必須要用戶交互。那我們就知道原因了,zepto 內部觸發 tap 事件是在 setTimeout 內,也就是說執行 focus 時,執行環境並不是用戶觸發的,因此 focus 被攔截掉了。

// zepto

tapTimeout = setTimeout(function() {

// trigger event

}, 0)

如果我們是寫 Hybird App 的頁面,則可以讓 Native Coder 將 UIWebView 的 keyboardDisplayRequiresUserAction 屬性設置為 NO,則不必操心這個問題了。
不過 iOS 的 WKWebView 不支持這個屬性了,但是在 StackOverflow 上有方案,可以使用 runtime 的 method swizzling hack 掉,詳見此鏈接 stackoverflow.com/questions/3…
那麽場景一在自己的 Hybrid App 裏還是可以實現的,當然系統原生的 Safari 瀏覽器我們無能為力,能優化一點是一點吧。
同時測試了下 autofocus 屬性,在 keyboardDisplayRequiresUserAction 設置為 NO 的情況下,它也是能正常工作的。
在 Android 底下,也是可以實現用戶點擊之後 focus 指定 input 的效果,而且沒有 iOS 的那個機制。

三、表單頁多個 input 依次自動聚焦

這個場景其實是場景一、二的結合,綜合上面兩個場景的測試分析,在自己的 * iOS Hybrid App * 裏依賴 Native 的 WebView 是可以實現的,在 Android 和外部瀏覽器中可以實現除第一次聚焦外的自動聚焦。。
目前 iOS UIWebView 設置 keyboardDisplayRequiresUserAction = NO 的狀態下,需要在 blur 事件內延遲 focus 才能生效(具體原因暫時不明):

// Hybrid App 內

document.querySelector(‘#input1‘).focus();

document.querySelector(‘#input1‘).addEventListener(‘blur‘, function() {

setTimeout(function() { // 必須延遲

document.querySelector(‘#input2‘).focus();

}, 200);

});

在系統 Safari 內,則因為 keyboardDisplayRequiresUserAction 默認為 YES,因此不允許在用戶交互產生的執行環境之外調用 focus,因此不能延遲執行。

// 系統 Safari 內

document.querySelector(‘#input1‘).focus();

document.querySelector(‘#input1‘).addEventListener(‘blur‘, function() {

document.querySelector(‘#input2‘).focus();

});

而在安卓中,頁面加載完後自動聚焦仍舊只是出現光標,不彈出鍵盤。。。後續自動聚焦則沒問題,如下圖所示狀態。。。
技術分享
為了解決這個問題,在 Hybrid App 中可以通過 JSBridge 讓 Android 原生進行喚起,後續 blur 事件中再 focus 則不需要原生再進行處理。

// Android 喚起鍵盤

InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);

imm.showSoftInput(view, 0); // view 為當前 webview

小結

總結下:

  • 要實現頁面加載完成後自動聚焦到 input 並彈出鍵盤,依賴 iOS App 的 WebView 將 keyboardDisplayRequiresUserAction 設置為 NO,就可以支持。Android 底下只能依賴 JSBridge 調用 Android 原生方法喚起鍵盤 。

  • 點擊元素聚焦指定 input,iOS / Android 都支持,但是 iOS 中必須保證 focus 是在用戶操作事件的函數執行環境中直接調用(Zepto tap 的坑)。

  • 依次聚焦 input,iOS 中有點特殊,具體還是看上文場景三。。。

LINKS

    • https://stackoverflow.com/questions/6287478/mobile-safari-autofocus-text-field

    • https://stackoverflow.com/questions/32407185/wkwebview-cant-open-keyboard-for-input-field

    • 推薦↓↓↓ 

      技術分享

      web前端開發熱門新聞,每日 10:24 播報

移動端 Web 頁 input 控制軟鍵盤