本文为在工作中遇到的有关移动端软键盘的问题总结,可能随着移动端系统更新有所变化,请结合实际情况食用本文。
每部分内容配有演示 demo,可通过浏览器 devTool 查看源代码。
前端开发的一大痛苦源泉是需要适配不同的设备。好比在写 css 的时候,在深呼吸写下第一行样式代码的时候,你需要先从别的什么地方拷贝下来一下叫 reset.css 或者 normalize.css 来抹平一些差异。
不幸的是,不是所有的问题都能像 css 这样方便的抹平,像键盘输入这种常见的需求,也可能一不留神掉进坑里 🤯。
希望你在掉进坑里时,无奈地在互联网上搜索"如何解决移动端键盘输入XXX问题时"找到本文,能对你有所帮助,我们开始吧!
软键盘弹起后怎么内容区域变了?
iOS 和 android 的软键盘弹起表现是有差异的!
iOS:


android:


很多文章解释过这个问题,这里总结如下:
- iOS:软件盘弹起后页面高度不变 。页面向上滚动,滚动高度为软键盘高度;
- android:页面高度减小,减小高度为软键盘高度。
有没有办法抹平这个问题呢?
我们在工作中选用的方式是将 android 设备同 iOS 一样保持高度不变,可以在页面初始化时设置 viewport 实现,代码如下:
js
if (/Android/.test(navigator.userAgent)) {
const viewportMeta = document.querySelector('meta[name=viewport]')
const resetViewportHeight = () => {
let content = (viewportMeta.getAttribute('content') ?? '')
.split(',')
.map((str) => str.trim())
.filter((str) => str.length)
.map((str) => str.split('=').map((str) => str.trim()))
.filter(([name]) => name !== 'height')
.map((pair) => pair.join('='))
.join(',')
content += `,height=${window.innerHeight}px`
viewportMeta.setAttribute('content', content)
}
resetViewportHeight()
如何获取软件盘高度?
window.visualViewport.height 可以拿到拿到可视区域大小,比如在 iphone 14 plus 手机上,未触发键盘时 window.visualViewport.height 是746,触发了软键盘时是466。
但是在 iOS 手机上有个坑,在触发软键盘的瞬间获取的 window.visualViewport.height 是不确定的,可能是 746 也可能是 466,解决办法是通过 resize 事件来监听变化:
javascript
window.visualViewport.addEventListener("resize", resizeHandler)
获取到软件盘高度可以实现如下图这种输入效果:

回车键的文字可以修改吗?
enterkeyhint 属性可以定义虚拟键盘上的回车键文案,用手机测试了一番,测试如下:
input(iOS) | textarea(iOS) | input(Android) | textarea(Android) | |
---|---|---|---|---|
-- | 换行(return) | 换行(return) | Go | 回车符号 |
enter | 换行(return) | 换行(return) | 回车符号 | 回车符号 |
done | 完成(done) | 完成(done) | Done | Done |
search | 搜索(search) | 搜索(search) | 搜索符号 | 搜索符号 |
括号内是英文系统下的文案
测试发现 iOS 和安卓表现并不一致,input 和 textarea 也不一致。更奇怪的是,iOS 中文输入法中,input 默认当回车键文字是换行,但是 input 其实并不能换行。
结论:目前并无可靠的办法修改回车键文案。
如何让内容撑开 textarea?
用到多行文本时,需要使用 textarea。
textarea 存在一个问题是:textarea 高度无法由内容撑开,一旦内容超过 textarea 高度,会变成内部滚动。如果需要由内容撑开 textarea 高度。可以通过添加一个隐藏的 div 节点,由节点高度撑开。具体实现看demo:
中文输入法计算长度有个坑
当需要限制文字长度时,中文输入可能会存在一个问题:

如图所示,在打字过程中,input.value.length 会记录当前拼音和空格的总长度,如果 input 框限制输入 4 个字的场景下,用 input.value.length 来判断长度就会出现字打到一半就不能再输入的问题。
可以通过 composition 事件判断是否处于输入法中。效果如下:


长按事件表现不一致
记录一个 iOS 和 Android 长按输入框的差异:
- iOS 长按后不会触发 focus 事件;
- Android 长按后不会触发 focus 事件。