H5 移动端 键盘遮挡焦点元素解决方案
前言
最近在做 webapp,遇到了很多移动端兼容的问题,其中一个问题就是:输入框触发 focus 后,键盘弹出,然后遮住了输入框。
然后在android
和ios
上,这个问题的表现形式不一样,而原生键盘和第三方键盘也不一样,但引起的问题都是一样的:输入框被遮住了。
需要的效果
在键盘弹出时,获得焦点的输入框要在可视区域内,效果如下图:
键盘弹出、收起的表现
-
ios:
输入框获取焦点,键盘弹出,
webview
高度不会改变,但webview
会往上滚,且最大滚动高度scrolltop
为键盘高度。点击键盘上的收起按钮,或者输入框以外的页面区域时,输入框失去焦点,键盘收起。
-
android:
输入框获取焦点,键盘弹出,但是
webview
高度会发生改变,高度为原高度减去软键盘高度。点击输入框以外的区域时,输入框失去焦点,软键盘收起。而点击键盘上的收起按钮时,键盘收起 ,但输入框并不会失去焦点,坑。
解决方案
当输入框被挡住,在ios
中,webview
会往上滚一段距离,使得获取焦点的输入框自动处于可视区,而在android
里,只会改变webview
高度,而不会发生焦点元素滚动到可视区的事情。
所以ios
可以不用管,而android
需要在键盘弹出的时候,将输入框滚动到可视区。
获取设备类型
首先是要获取设备类型,通过navigator.useragent
获取即可。
const judgedevicetype = (() => { let devicetype = null; return () => { if (!devicetype) { const ua = window.navigator.useragent.tolocalelowercase(); const isios = /iphone|ipad|ipod/.test(ua); const isandroid = /android/.test(ua); const ismiuibrowser = /miuibrowser/.test(ua); devicetype = { isios: isios, isandroid: isandroid, ismiuibrowser: ismiuibrowser }; } return devicetype; }; })();
监听事件
ios 可以通过focus
和blur
事件监听键盘弹出、收起,但 android 不行,但因为webview
高度会变,所以通过监听resize
事件解决。
export function listenandroidkeybord() { const { isandroid } = judgedevicetype(); if (isandroid) { const androidresize = function() { // 将当前焦点元素滚动到可视区 activeelementscrollintoview(); }; // android 键盘弹出、收起,可视区高度会发生变化 window.addeventlistener('resize', androidresize, false); return () => { window.removeeventlistener('resize', androidresize, false); }; } }
将元素滚动到可视区
要将元素滚动到可视区,主要有两个方法:scrollintoview
和scrollintoviewifneeded
,兼容性在移动端都很不错。
function activeelementscrollintoview() { const activeel = document.activeelement; if ( activeel.tagname === 'input' || activeel.tagname === 'textarea' ) { window.settimeout(() => { if ('scrollintoview' in activeel) { activeelt.scrollintoview(); } else { activeel.scrollintoviewifneeded(); } }, 100); } }
miuibrowser
以上代码可以说解决了大部分浏览器键盘遮挡问题了,但我用自己的小米手机自带的小米浏览器测试时,出了问题,键盘弹出,页面纹丝不动,手动去拖,有时行,有时不行。
搞了很久,发现了两个问题,我这手机上自带的小米浏览器,useragent 上没有带android
标识,但有miuibrowser
标识,坑。然后,页面有时能拖动,有时不能拖动,我猜应该是webview
的可视区高度变化有问题,或者是我的代码监听resize
导致有问题。
解决方案
-
增加设备类型判断
const ua = window.navigator.useragent.tolocalelowercase(); const ismiuibrowser = /miuibrowser/.test(ua);
-
通过监听
focus
和blur
事件来监听键盘弹出、收起,然后给body
加高度body, html { height: 100%; }
function listenmiuibrowserkeybord() { const { ismiuibrowser } = judgedevicetype(); if (ismiuibrowser) { const inputfocus = function() { document.body.style.marginbottom = '50px'; activeelementscrollintoview(); }; const inputblur = function() { document.body.style.marginbottom = '0px'; activeelementscrollintoview(); }; let $inputs = document.getelementsbytagname('input'); for (let i = 0; i < $inputs.length; i++) { $inputs[i].addeventlistener('focus', inputfocus, false); $inputs[i].addeventlistener('blur', inputblur, false); } return () => { for (let i = 0; i < $inputs.length; i++) { $inputs[i].removeeventlistener('focus', inputfocus, false); $inputs[i].removeeventlistener('blur', inputblur, false); } }; } }
坑点:这种方案虽然解决了弹出问题,但点击键盘收起按钮,android 下输入框并不会失去焦点,需要失去焦点才能让 body 增加的高度变为 0。
备注
解决方案并不完善,踩坑路漫漫。
上一篇: django之模板层
下一篇: Python—实现钉钉后台开发