当前位置:网站首页>H5软键盘问题
H5软键盘问题
2022-06-29 08:24:00 【CamilleZJ】
流程:输入框获取焦点,软键盘弹起
可能遇到问题:
在 Android 和 IOS 上,获知软键盘弹起和收起状态存在差异,且页面 webview 表现不同。
在IOS12 上,微信版本 v6.7.4 及以上,输入框获取焦点,键盘弹起,页面(webview)整体往上滚动,当键盘收起后,不回到原位,导致键盘原来所在位置是空白的。
在 IOS 上,使用第三方输入法,高度计算存在偏差,导致在有些输入法弹起,将输入框挡住一部分。
在有些浏览器上使用一些操作技巧,还是存在输入框被输入法遮挡。
获知软键盘弹起和收起状态
获知软键盘的弹起还是收起状态很重要,后面的兼容处理都要以此为前提。然而,H5 并没有直接监听软键盘的原生事件,只能通过软键盘弹起或收起,引发页面其他方面的表现间接监听,曲线救国。并且,在 IOS 和 Android 上的表现不尽相同。
- 在 IOS 上,输入框(input、textarea 或 富文本)获取焦点,键盘弹起,页面(webview)并没有被压缩,或者说高度(height)没有改变,只是页面(webview)整体往上滚了,且最大滚动高度(scrollTop)为软键盘高度。
- 在 Android 上,输入框获取焦点,键盘弹起,但是页面(webview)高度会发生改变,一般来说,高度为可视区高度(原高度减去软键盘高度),除了因为页面内容被撑开可以产生滚动,webview 本身不能滚动。
如下ios和Android软键盘弹起页面变动:
- IOS:触发软键盘上的“收起”按钮 或 点击输入框以外的页面区域,即输入框失去焦点,软键盘收起。
- Android:触发输入框以外的区域时,输入框失去焦点,软键盘收起。但是,触发键盘上的收起按钮键盘时,输入框并不会失去焦点,同样软键盘收起

监听软键盘的弹起和收回:
在 IOS 上,监听输入框的 focus 事件来获知软键盘弹起,监听输入框的 blur 事件获知软键盘收起。
在 Android 上,监听 webview 高度会变化,高度变小获知软键盘弹起,否则软键盘收起(软键盘收起和输入框获没获取焦点不直接关联)。
// 判断设备类型
var judgeDeviceType = function () {
var ua = navigator.userAgent.toLocaleLowerCase(),
isIOS = /iphone|ipad|ipod/.test(ua),
isAndroid = /android/.test(ua);
return {
isIOS: isIOS,
isAndroid: isAndroid
}
}()
// 监听输入框的软键盘弹起和收起事件
function listenKeybord($input) {
if (judgeDeviceType.isIOS) {
// IOS 键盘弹起:IOS 和 Android 输入框获取焦点键盘弹起
$input.addEventListener('focus', function () {
console.log('IOS 键盘弹起啦!');
// IOS 键盘弹起后操作
}, false)
// IOS 键盘收起:IOS 点击输入框以外区域或点击收起按钮,输入框都会失去焦点,键盘会收起
$input.addEventListener('blur', () => {
console.log('IOS 键盘收起啦!');
// IOS 键盘收起后操作
})
}
if (judgeDeviceType.isAndroid) {
// Andriod 键盘收起:Andriod 键盘弹起或收起页面高度会发生变化,以此为依据获知键盘收起
var originHeight = document.documentElement.clientHeight || document.body.clientHeight;
window.addEventListener('resize', function () {
var resizeHeight = document.documentElement.clientHeight || document.body.clientHeight;
if (originHeight < resizeHeight) {
console.log('Android 键盘收起啦!');
// Android 键盘收起后操作
} else {
console.log('Android 键盘弹起啦!');
// Android 键盘弹起后操作
}
originHeight = resizeHeight;
}, false)
}
}
var $inputs = document.querySelectorAll('.input');
for (var i = 0; i < $inputs.length; i++) {
listenKeybord($inputs[i]);
}弹起软键盘始终让输入框滚动到可视区
有时我们会做一个输入表单,有很多输入项,输入框获取焦点,弹起软键盘。当输入框位于页面下部位置时,在 IOS 上,会将 webview 整体往上滚一段距离,使得该获取焦点的输入框自动处于可视区,而在 Android 则不会这样,它只会改变页面高度,而不会去滚动到当前焦点元素到可视区。
解决:在 Android 键盘弹起后,将焦点元素滚动(scrollIntoView())到可视区。
Element 接口的scrollIntoView()方法会滚动元素的父容器,使被调用scrollIntoView()的元素对用户可见。
// 获取到焦点元素滚动到可视区
function activeElementScrollIntoView(activeElement, delay) {
var editable = activeElement.getAttribute('contenteditable')
// 输入框、textarea或富文本获取焦点后没有将该元素滚动到可视区
if (activeElement.tagName == 'INPUT' || activeElement.tagName == 'TEXTAREA' || editable === '' || editable) {
setTimeout(function () {
activeElement.scrollIntoView();
}, delay)
}
}
// Android 键盘弹起后操作
activeElementScrollIntoView($input, 1000);
唤起纯数字软键盘:
设置input的type为tel或number
兼容 IOS12 + V6.7.4+
如果你在用 IOS12 和 V6.7.4+版本的微信浏览器打开上面表单输入的 demo ,就会惊奇的发现键盘收起后,原本被滚动顶起的页面并没有回到底部位置,导致原来键盘弹起的位置“空”了。

这个bug会出现在所有的 Xcode10 打包的 IOS12 的设备上。微信官方已给出解决方案https://developers.weixin.qq.com/community/develop/doc/00044ae90742f8c82fb78fcae56800,只需在软键盘收起后,将页面(webview)滚回到窗口最底部位置(clientHeight位置)。修复后的https://wuwhs.github.io/demo/keyboard-compatible/input-fix-ios12-wx6.7.4.html
// IOS 键盘收起后操作
// 微信浏览器版本6.7.4+IOS12会出现键盘收起后,视图被顶上去了没有下来
var wechatInfo = navigator.userAgent.match(/MicroMessenger/([\d.]+)/i);
if (!wechatInfo) return;
var wechatVersion = wechatInfo[1];
var version = (navigator.appVersion).match(/OS (\d+)(\d+)?(\d+)?/);
if (+wechatVersion.replace(/./g, '') >= 674 && +version[1] >= 12) {
setTimeout(function () {
window.scrollTo(0, Math.max(document.body.clientHeight, document.documentElement.clientHeight));
})
}
兼容第三方输入法
案例:https://wuwhs.github.io/demo/keyboard-compatible/chat.html,主要结构如下:

<style>
/* 省略一些样式 */
.chat__content {
height: calc(100% - 40px);
margin-bottom: 40px;
overflow-y: auto;
overflow-x: hidden;
}
.input__content {
display: flex;
height: 40px;
position: absolute;
left: 0;
right: 0;
bottom: 0;
align-items: center;
}
/* 省略一些样式 */
</style>
<div class="chat__content">
<div>
<p>一些聊天内容1</p>
</div>
<div>
<p>一些聊天内容2</p>
</div>
</div>
<div class="input__content">
<div class="input" contenteditable="true"></div>
<button>发送</button>
</div>
大部分 Android 浏览器是没问题的,但是测试在 IOS 上,UC 浏览器配合原生输入法和第三方输入法(比如搜狗输入法),输入框都会被完全挡住;QQ 浏览器或微信浏览器,配合第三方输入法,输入框会被遮住一半;百度浏览器配合第三方输入法输入框也会被完全遮住。

在 UC 浏览器上,软键盘弹起后,浏览器上面的标题栏高度就有个高度变小延时动态效果,这样导致 webview 往下滚了一点,底部输入框滚到了非可视区。
而对于第三方输入法,猜测本身是由于输入法面板弹起后高度计算有误,导致 webview 初始滚动定位有误。其实这两点都是 webview 滚动不到位造成的。可以让软键盘弹起后,让焦点元素再次滚到可视区,强迫 webview 滚到位。
// Android 键盘弹起后操作
activeElementScrollIntoView($input, 1000);兼容 Android 小米浏览器的 Hack 方案
在 Android 的小米浏览器上,应用上面的方案,发现聊天输入框还是被遮挡得严严实实,scrollIntoView() 仍然纹丝不动。所以猜测,其实是滚到底了,软键盘弹起,页面实现高度大于可视区高度,这样只能在软键盘弹起后,强行增加页面高度,使输入框可以显示出来。
if (judgeDeviceType.isAndroid) {
// Andriod 键盘收起:Andriod 键盘弹起或收起页面高度会发生变化,以此为依据获知键盘收起
var originHeight = document.documentElement.clientHeight || document.body.clientHeight;
window.addEventListener('resize', function () {
var resizeHeight = document.documentElement.clientHeight || document.body.clientHeight;
if (originHeight < resizeHeight) {
console.log('Android 键盘收起啦!');
// Android 键盘收起后操作
// 修复小米浏览器下,输入框依旧被输入法遮挡问题
if (judgeDeviceType.isMiuiBrowser) {
document.body.style.marginBottom = '0px';
}
} else {
console.log('Android 键盘弹起啦!');
// Android 键盘弹起后操作
// 修复小米浏览器下,输入框依旧被输入法遮挡问题
if (judgeDeviceType.isMiuiBrowser) {
document.body.style.marginBottom = '40px';
}
activeElementScrollIntoView($input, 1000);
}
originHeight = resizeHeight;
}, false)
}input中type类型和弹出的软键盘显示有关,如下:
1.type=text ,ios和安卓都会弹出全键盘,右下角都为go按钮或者是前往
2.type=url , ios和安卓都会弹出带有“/”、“.com”之类的可以快速输入网址的软键盘
3.type=number,ios下会弹出包含数字和各种符号的软键盘,安卓下则会弹出一个类似于拨号键盘的纯数字加部分标点的键盘。
4.type=tel,这会使ios和安卓下都弹出类似于拨号时的数字键盘,所以在移动页面开发中,一般都使用type=tel而非type=number。
5.type=date、datetime、time、mouth。这些只在ios下会弹出ios原生的日期选择器。
6.type=email 这会使ios和安卓都弹出带有“@”键的软键盘。
7.type=search 这会使软键盘右下角的前往键变为一个搜索放大镜按钮,而且输入时输入框右边会有清空按钮。顺便一提,通过css input[type=search]可以修改这个按钮的样式哦!
ios 键盘换行变为搜索
input type="search"- input 外面套 form,必须要有 action,
action="javascript:return true" - 表单提交阻止默认提交事件
<form action="javascript:return true" @submit.prevent="formSubmit">
<input type="search" placeholder="请输入诉求名称" id="search" />
</form>
边栏推荐
- laravel 8 实现 订单表按月份水平分表
- Backpack Lecture 9 - detailed understanding and code implementation
- Development tips - Image Resource Management
- ThreadLocal thread variable
- 今年的网络安全“体检”你做了吗?
- Huawei equipment is configured with medium-sized network WLAN basic services
- Leetcode (142) - circular linked list II
- 闭关修炼(二十四)浅入了解跨域问题
- verilog 等价操作符
- 打印服务IP设置方案
猜你喜欢

uni-app获取当前页面路由url

Actual combat memoir starts from webshell to break through the border

华为设备配置中型网络WLAN基本业务

How to recover data loss of USB flash disk memory card

Carbon emission reduction of second-hand trading platform, with assessment standards

Heavyweight released "FISCO bcos application landing guide"

2022第六季完美童模 海口赛区 选拔赛圆满落幕

The final of the sixth season of 2022 perfect children's model Hefei division came to a successful conclusion

51单片机中断与定时器计数器,基于普中科技HC6800-ESV2.0

Oracle-子查询
随机推荐
Measure the level of various chess playing activities through ELO mechanism
io流的总结
Dialogue | prospects and challenges of privacy computing in the digital age
TypeScript 變量聲明 —— 類型斷言
Official reply on issues related to the change of children's names after parents' divorce
积分商城运营要如何做才能获取到利润
Uber前安全主管面临欺诈指控 曾隐瞒数据泄露事件
verilog 移位操作符
2022春夏系列 KOREANO ESSENTIAL重塑时装生命力
闭关修炼(二十)如何做好单元测试
观察者模式怎么实现
Matlab usage
sql server 用 administrator 权限运行吗?还是以普通用户运行呢?
今天让你知道PMP考试通过率达97%,可信不可信
Pointnet的网络学习
各種級數(調和、幾何)總結
Notes on key words in the original English work biography of jobs (VIII) [chapter six]
ES6 data type map & set
Differences between x86 and x64
P6776-[noi2020] surreal tree