有关移动端软键盘的一切

2,153 阅读3分钟

背景

最近在工作中遇到移动端软键盘的问题,导致项目线上出了bug,所以专门写一篇文章,收集所有有关软键盘的问题和解决方案。

ios、安卓软键盘弹出规则

所有的解决方案都是基于:获知软键盘弹起和收起状态。然而,H5 并没有直接监听软键盘的原生事件,只能通过软键盘弹起或收起,引发页面其他方面的表现间接监听,曲线救国。并且,在IOS 和 Android 上的表现不尽相同。

IOS 软键盘弹起表现

在 IOS 上,输入框(input、textarea 或 富文本)获取焦点,键盘弹起,页面(webview)并没有被压缩,或者说高度(height)没有改变,只是页面(webview)整体往上滚了,且最大滚动高度(scrollTop)为软键盘高度。

Android 软键盘弹起表现

同样,在 Android 上,输入框获取焦点,键盘弹起,但是页面(webview)高度会发生改变,一般来说,高度为可视区高度(原高度减去软键盘高度),除了因为页面内容被撑开可以产生滚动,webview本身不能滚动。

IOS 软键盘收起表现

触发软键盘上的“收起”按钮键盘或者输入框以外的页面区域时,输入框失去焦点,软键盘收起。(如果通过下滑收起键盘,此时点击页面任意位置会再次触发focus事件,但input并没有获取焦点,这是ios的一个bug)。

Android 软键盘收起表现

触发输入框以外的区域时,输入框失去焦点,软键盘收起。但是,触发键盘上的收起按钮键盘时,输入框并不会失去焦点,同样软键盘收起。

监听软键盘弹起和收起

综合上面键盘弹起和收起在 IOS 和 Android 上的不同表现,我们可以分开进行如下处理来监听软键盘的弹起和收起:

  1. 在 IOS 上,监听输入框的 focus 事件来获知软键盘弹起,监听输入框的 blur 事件获知软键盘收起,目前ios存在两个问题:
    • 通过下滑收起键盘,此时点击页面任意位置会再次触发focus事件,但input并没有获取焦点,键盘也不会弹起,这个问题可以通过用focusin替代focus来解决。
    • 不能通过点击其他元素来触发input的focus事件。因为ios重交互,只能手动点击input才能触发focus。
  2. 在 Android 上,监听 webview 高度会变化,高度变小获知软键盘弹起,否则软键盘收起。

一些问题场景

数字键盘

// 纯数字带#和*
<input type="tel">
//纯数字
<input type="number" pattern="\d*">

部分机型软键盘弹起挡住原来的视图

解决方法:可以通过监听移动端软键盘弹起 Element.scrollIntoView() 方法让当前的元素滚动到浏览器窗口的可视区域内。参数如下。

  • true,表示元素的顶部与当前区域的可见部分的顶部对齐
  • false,表示元素的底部与当前区域的可见部分的尾部对齐 Element.scrollIntoViewIfNeeded()方法也是用来将不在浏览器窗口的可见区域内的元素滚动到浏览器窗口的可见区域。但如果该元素已经在浏览器窗口的可见区域内,则不会发生滚动。此方法是标准的Element.scrollIntoView()方法的专有变体。
window.addEventListener('resize', function() {
  if (document.activeElement.tagName === 'INPUT' || document.activeElement.tagName === 'TEXTAREA') {
    window.setTimeout(function() {
      if ('scrollIntoView' in document.activeElement) {
        document.activeElement.scrollIntoView(false)
      } else {
        document.activeElement.scrollIntoViewIfNeeded(false)
      }
    }, 0)
  }
})

ios 键盘收起时页面没有回落,底部会留白

部分苹果手机填写表单的时候的,输入内容后关闭软键盘,底部会留一块空白。这种情况可以通过监听键盘回落时间滚动到原来的位置。

window.addEventListener('focusout', function() {
  window.scrollTo(0, 0)
})
//input输入框弹起软键盘的解决方案。
var bfscrolltop = document.body.scrollTop
$('input')
  .focus(function() {
    document.body.scrollTop = document.body.scrollHeight
  })
  .blur(function() {
    document.body.scrollTop = bfscrolltop
  })

ios 键盘换行变为搜索

  1. input type="search"
  2. input 外面套 form,必须要有 action,action="javascript:return true"
  3. 表单提交阻止默认提交事件
<form action="javascript:return true" @submit.prevent="formSubmit">
  <input type="search" placeholder="请输入诉求名称" id="search" />
</form>