移动端软键盘踩坑指南

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

每部分内容配有演示 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 事件。
相关推荐
apcipot_rain4 小时前
【应用密码学】实验五 公钥密码2——ECC
前端·数据库·python
油丶酸萝卜别吃4 小时前
OpenLayers 精确经过三个点的曲线绘制
javascript
ShallowLin4 小时前
vue3学习——组合式 API:生命周期钩子
前端·javascript·vue.js
Nejosi_念旧4 小时前
Vue API 、element-plus自动导入插件
前端·javascript·vue.js
互联网搬砖老肖4 小时前
Web 架构之攻击应急方案
前端·架构
pixle05 小时前
Vue3 Echarts 3D饼图(3D环形图)实现讲解附带源码
前端·3d·echarts
麻芝汤圆5 小时前
MapReduce 入门实战:WordCount 程序
大数据·前端·javascript·ajax·spark·mapreduce
juruiyuan1117 小时前
FFmpeg3.4 libavcodec协议框架增加新的decode协议
前端
Peter 谭8 小时前
React Hooks 实现原理深度解析:从基础到源码级理解
前端·javascript·react.js·前端框架·ecmascript
周胡杰8 小时前
鸿蒙接入flutter环境变量配置windows-命令行或者手动配置-到项目的创建-运行demo项目
javascript·windows·flutter·华为·harmonyos·鸿蒙·鸿蒙系统