移动端软键盘踩坑指南

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

每部分内容配有演示 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 事件。
相关推荐
.生产的驴9 分钟前
SpringBoot 消息队列RabbitMQ 消息确认机制确保消息发送成功和失败 生产者确认
java·javascript·spring boot·后端·rabbitmq·负载均衡·java-rabbitmq
布瑞泽的童话23 分钟前
无需切换平台?TuneFree如何搜罗所有你爱的音乐
前端·vue.js·后端·开源
白鹭凡35 分钟前
react 甘特图之旅
前端·react.js·甘特图
2401_8628867840 分钟前
蓝禾,汤臣倍健,三七互娱,得物,顺丰,快手,游卡,oppo,康冠科技,途游游戏,埃科光电25秋招内推
前端·c++·python·算法·游戏
书中自有妍如玉1 小时前
layui时间选择器选择周 日月季度年
前端·javascript·layui
Riesenzahn1 小时前
canvas生成图片有没有跨域问题?如果有如何解决?
前端·javascript
f8979070701 小时前
layui 可以使点击图片放大
前端·javascript·layui
小贵子的博客1 小时前
ElementUI 用span-method实现循环el-table组件的合并行功能
javascript·vue.js·elementui
明似水1 小时前
掌握 Flutter 中的 `Overlay` 和 `OverlayEntry`:弹窗管理的艺术
javascript·flutter