解决IOS中微信浏览器软键盘弹出导致的若干Bug
问题 1 键盘弹起后会遮挡键盘上方的内容
在微信浏览器中,如果需要模拟一个类似微信聊天的窗口,那么一般情况下需要将输入框使用 fixed 定位放置在页面最下方。就像这样:
但是,在 IOS 中的虚拟键盘和 Android 里是不同的。在 IOS 中,虚拟键盘弹出以后,键盘上面的输入提示会比键盘弹出慢半拍,所以就会导致输入法的提示框将正常页面挡住的情况。
这时候,就需要在键盘弹出后,等待一段时间(几百毫秒),然后再将页面的滚动条进行调整,就可以让页面弹到键盘之上。
假设页面布局如下(使用了 Vue 框架),其中 Dialogues 组件是可以滚动的聊天内容,PageFooter 是使用 fixed 定位在页面底部的输入框:
1 | <div id="index"> |
然后,就可以在监听到软键盘打开事件(比如 dialogueContent 中 input 元素的 onclick 或者 onchange 事件)后,执行下面的语句,让 dialogContent 的滚动条向下滚动,这样里面的内容就不会被覆盖了。
1 | let dialogueContent = document.querySelector('#dialogueContent') |
至于为什么要触发两次呢,是因为 IOS 手机种类比较多,从五六年前 iPhone5s 到最新的 iPhoneXR 都有人在用,每种手机的响应速度也各不相同,有些手机可能在第一个 250ms 内还没有完成键盘弹出的工作,所以可以再加一个定时器来兼容旧的手机。
但问题也依旧存在,就是 fixed 定位的输入框在软键盘弹出以后就不会像 Android 一样固定在页面底部,而是可以上下滑动,类似于 absolute 定位。这时,可以将 body 设置为 absolute 定位,然后再将 MainPage 使用 absolute 定位于 body 底部。
问题 2 在虚拟键盘收起以后 body 定位的问题
紧接着,第二个问题就出现了。在点击虚拟键盘右上角的“完成按钮以后”,页面下方并没有回弹,而是定在了原来软键盘上方的位置,必须在页面上滑动两下才可以触发回弹。(特别是在大屏的 IOS 手机上)
大概是这样:
而在将 body 设置为 absolute 以后,情况更加离奇。页面 UI 是回弹了,但是触控事件响应的位置是没有回弹的,依旧是软键盘打开区域的上方。解决方法同样是必须在页面上方华东两下才能回弹。
大概是这样:
最开始的想法是去监听 resize 事件,如果软键盘收回,就强行调整 body 的高度,但是发现软键盘的弹出和收回并不会触发该事件,只得作罢。
最终,找到了一篇解决 类似问题的文章,才找到了解决方案。
大致思路就是在键盘收回以后,主动触发浏览器对页面的重绘操作。如何进行呢?只需要在监听到 onblur 事件以后,让页面滚动到原来的位置即可。
比如,组件模板中的 HTML 为
1 | <input type="text" placeholder="发送内容" v-model="content" @blur="resizeWindow"> |
然后可以在 JS 的 methods 中添加一个函数:
1 | resizeWindow() { |
这样,输入框在失去焦点以后会触发页面的重绘,刚刚的问题就随之而解了。