移动端 Web 页 input 控制软键盘

2017-10-21 09:24:00 4386 4 编辑:深正互联 来源:互联网

从交互层面上来讲,完成一个功能(获得想要的信息)的过程称之为用户路径。用户路径越长,完成功能的复杂度就越高,用户体验也就越差。因此当打开一个需要用户填写信息的表单界面时,为了提高可用性,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 中有点特殊,具体还是看上文场景三。


本站文章均为深正网站建设摘自权威资料,书籍,或网络原创文章,如有版权纠纷或者违规问题,请即刻联系我们删除,我们欢迎您分享,引用和转载,但谢绝直接搬砖和抄袭!感谢...
关注深正互联

15

技术从业经验

多一份方案,会有收获...

联系深正互联,免费获得专属《策划方案》及报价

在线咨询
微信交谈
拒绝骚扰,我们只想为给您带来一些惊喜...
多一份免费策划方案,总有益处。

请直接添加技术总监微信联系咨询

深正互联微信
扫描即可沟通