移动端软键盘踩坑指南

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

每部分内容配有演示 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 事件。
相关推荐
星语卿30 分钟前
Vuetify:构建优雅Vue应用的Material Design组件库
前端·javascript·vue.js
wangbing112541 分钟前
界面规范11-对话框
javascript·vue.js·elementui
roman_日积跬步-终至千里1 小时前
【系统架构设计(25)】Web应用服务器与现代架构
前端·架构·系统架构
yshhuang1 小时前
在Windows上搭建开发环境
前端·后端
littleplayer1 小时前
Redux在iOS中的使用
前端
跟橙姐学代码1 小时前
Python里的“管家婆”:带你玩转os库的所有神操作
前端·python·ipython
jingling5551 小时前
uniapp | 快速上手ThorUI组件
前端·笔记·前端框架·uni-app
UrbanJazzerati1 小时前
可拖拽的进度条组件实战:实现思路与Demo
前端·面试
Cache技术分享1 小时前
188. Java 异常 - Java 异常处理规范
前端·后端