6

解决 IOS 中微信浏览器软键盘弹出导致的若干 Bug

 3 years ago
source link: https://blog.zhengzi.me/the_solution_of_bugs_on_wechat_in_ios/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

问题 1 键盘弹起后会遮挡键盘上方的内容

在微信浏览器中,如果需要模拟一个类似微信聊天的窗口,那么一般情况下需要将输入框使用 fixed 定位放置在页面最下方。就像这样:

但是,在 IOS 中的虚拟键盘和 Android 里是不同的。在 IOS 中,虚拟键盘弹出以后,键盘上面的输入提示会比键盘弹出慢半拍,所以就会导致输入法的提示框将正常页面挡住的情况。

这时候,就需要在键盘弹出后,等待一段时间(几百毫秒),然后再将页面的滚动条进行调整,就可以让页面弹到键盘之上。

假设页面布局如下(使用了 Vue 框架),其中 Dialogues 组件是可以滚动的聊天内容,PageFooter 是使用 fixed 定位在页面底部的输入框:

<div id="index">
<div id="mainPanel">
<div id="dialogueContent">
<Dialogues></Dialogues>
</div>
</div>
<footer>
<PageFooter></PageFooter>
</footer>
</div>

然后,就可以在监听到软键盘打开事件(比如 dialogueContent 中 input 元素的 onclick 或者 onchange 事件)后,执行下面的语句,让 dialogContent 的滚动条向下滚动,这样里面的内容就不会被覆盖了。

let dialogueContent = document.querySelector('#dialogueContent')
setTimeout(function() {
dialogueContent.scrollTop = dialogueContent.scrollHeight
setTimeout(function() {
dialogueContent.scrollTop = dialogueContent.scrollHeight
}, 250)
}, 250)

至于为什么要触发两次呢,是因为 IOS 手机种类比较多,从五六年前 iPhone5s 到最新的 iPhoneXR 都有人在用,每种手机的响应速度也各不相同,有些手机可能在第一个 250ms 内还没有完成键盘弹出的工作,所以可以再加一个定时器来兼容旧的手机。

但问题也依旧存在,就是 fixed 定位的输入框在软键盘弹出以后就不会像 Android 一样固定在页面底部,而是可以上下滑动,类似于 absolute 定位。这时,可以将 body 设置为 absolute 定位,然后再将 MainPage 使用 absolute 定位于 body 底部。

问题 2 在虚拟键盘收起以后 body 定位的问题

紧接着,第二个问题就出现了。在点击虚拟键盘右上角的 “完成按钮以后”,页面下方并没有回弹,而是定在了原来软键盘上方的位置,必须在页面上滑动两下才可以触发回弹。(特别是在大屏的 IOS 手机上)

大概是这样:

而在将 body 设置为 absolute 以后,情况更加离奇。页面 UI 是回弹了,但是触控事件响应的位置是没有回弹的,依旧是软键盘打开区域的上方。解决方法同样是必须在页面上方华东两下才能回弹。

大概是这样:

最开始的想法是去监听 resize 事件,如果软键盘收回,就强行调整 body 的高度,但是发现软键盘的弹出和收回并不会触发该事件,只得作罢。

最终,找到了一篇解决 类似问题的文章,才找到了解决方案。

大致思路就是在键盘收回以后,主动触发浏览器对页面的重绘操作。如何进行呢?只需要在监听到 onblur 事件以后,让页面滚动到原来的位置即可。

比如,组件模板中的 HTML 为

<input type="text" placeholder="发送内容" v-model="content" @blur="resizeWindow">

然后可以在 JS 的 methods 中添加一个函数:

resizeWindow() {
document.body.scrollTop = document.body.scrollTop
}

这样,输入框在失去焦点以后会触发页面的重绘,刚刚的问题就随之而解了。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK