移动端软键盘踩坑指南

本文为在工作中遇到的有关移动端软键盘的问题总结,可能随着移动端系统更新有所变化,请结合实际情况食用本文。

每部分内容配有演示 demo,可通过浏览器 devTool 查看源代码。

前端开发的一大痛苦源泉是需要适配不同的设备。好比在写 css 的时候,在深呼吸写下第一行样式代码的时候,你需要先从别的什么地方拷贝下来一下叫 reset.css 或者 normalize.css 来抹平一些差异。

不幸的是,不是所有的问题都能像 css 这样方便的抹平,像键盘输入这种常见的需求,也可能一不留神掉进坑里 🤯。

希望你在掉进坑里时,无奈地在互联网上搜索"如何解决移动端键盘输入XXX问题时"找到本文,能对你有所帮助,我们开始吧!

软键盘弹起后怎么内容区域变了?

iOS 和 android 的软键盘弹起表现是有差异的!

iOS:

android:

很多文章解释过这个问题,这里总结如下:

  • iOS:软件盘弹起后页面高度不变 。页面向上滚动,滚动高度为软键盘高度;
  • android:页面高度减小,减小高度为软键盘高度。

👉 戳我查看 demo 使用手机浏览器食用更佳🍬

有没有办法抹平这个问题呢?

我们在工作中选用的方式是将 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)

获取到软件盘高度可以实现如下图这种输入效果:

👉 戳我查看 demo 使用手机浏览器食用更佳🍬

回车键的文字可以修改吗?

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:

👉 戳我查看 demo 使用手机浏览器食用更佳🍬

中文输入法计算长度有个坑

当需要限制文字长度时,中文输入可能会存在一个问题:

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

可以通过 composition 事件判断是否处于输入法中。效果如下:

👉 戳我查看 demo 使用手机浏览器食用更佳🍬

长按事件表现不一致

记录一个 iOS 和 Android 长按输入框的差异:

  • iOS 长按后不会触发 focus 事件;
  • Android 长按后不会触发 focus 事件。
相关推荐
落霞的思绪25 分钟前
CSS复习
前端·css
咖啡の猫2 小时前
Shell脚本-for循环应用案例
前端·chrome
百万蹄蹄向前冲5 小时前
Trae分析Phaser.js游戏《洋葱头捡星星》
前端·游戏开发·trae
朝阳5815 小时前
在浏览器端使用 xml2js 遇到的报错及解决方法
前端
GIS之路5 小时前
GeoTools 读取影像元数据
前端
ssshooter6 小时前
VSCode 自带的 TS 版本可能跟项目TS 版本不一样
前端·面试·typescript
你的人类朋友6 小时前
【Node.js】什么是Node.js
javascript·后端·node.js
Jerry7 小时前
Jetpack Compose 中的状态
前端
dae bal7 小时前
关于RSA和AES加密
前端·vue.js
柳杉8 小时前
使用three.js搭建3d隧道监测-2
前端·javascript·数据可视化