38

ios 最新系统bug与解决——微信公众号中弹出键盘再收起时,原虚拟键盘位点击

 6 years ago
source link: http://www.cocoachina.com/ios/20181225/25941.html?amp%3Butm_medium=referral
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.
neoserver,ios ssh client

最近ios发布新版本系统12.1,随着部分用户的系统更新,一些问题也渐渐暴露出来。。。

公司用户反映微信公众号出现了点击无效的bug!!测试调查发现,只有iphonex、iphone6,ihpone7等部分机型会出现该问题

我当时就是一惊,一般出现在事件上的问题都是疑难杂症。何况是跟键盘相关的。

我们都知道在H5端是没法监控键盘的弹出与收起的,resize事件触发的机型极其有限,何况我在ios中实测没有触发,安卓反而可以。因为安卓弹起键盘时会修改视窗的大小,但是ios并不会,如果你在ios上设置一个100%高度的body,弹起键盘后你会发现这个body是可以上下滚动的,即100%高度的body超出了视窗。

(PS: iphoneX的测试机被拿走了,这是安卓下模拟的ios表现,总之ios能滚成这样)

jYZ7ney.jpg!web

那么说问题(可以直接翻到文末看解决方案)

下图是一个问题描述,当我们弹起键盘,并且使用如下的布局时:

juAfIbR.jpg!web

body高度是100%,modal使用fixed定位,四个方向设置为0,预期的结果应该是两者都适应窗口大小,弹起键盘时自动适应。安卓上与预期相同,ios打开后出现整个modal和body可以滑动的情况。

ios上一直有个很的优化,弹出键盘时会自动把当前输入框滚动到可视区域,在安卓中会出现键盘遮挡输入框的问题,需要手动调整,ios扳回一城。我在项目中为了让安卓达到同样的效果也是死了不少脑细胞。

但是!!项目本身在稳定运行半年的情况下,这次开始出现问题了。。。

在ios 12.1 中,机型为iphoneX,当我们聚焦输入框弹出虚拟键盘,然后点击键盘收起。出现了如下的效果图,并且下半部分做点击事件无效。

B3qiUvz.jpg!web

从现象中找问题,在虚拟键盘被收起的情况下,可以看到modal框视图正常得弹回了,但是仔细看看透明区域下,body视图还处在键盘弹起时的状态。what fuck? 然后modal下面的可操作区域始终点击无效。。。。

Why?

推测是body没有正确重新渲染,导致点击事件不处于body内而无法触发。

(简陋推测图......)

EnqInan.jpg!web

How?

那么怎么解决呢,是不是只要把body‘推’会来就行了? 方向有了,现在是如何‘推’的问题。

上文有说过,ios下弹出/收起键盘是没有触发resize事件的,那么在什么节点触发‘推’的操作就成了问题。

这时候封装的好处就体现出来了,因为项目中所有的地方都是使用封装过的input框,所以只需要在封装中做改造就好了。ios中点击虚拟键盘的完成按钮会触发失焦事件,安卓却不会,正是我们需要的钩子。

在钩子中设置“推回”:

    onBlur = (e) => {
        const { onBlur } = this.props;
        document.body && (document.body.scrollTop = 0);
        onBlur && onBlur(e);
    }

问题初步解决,但是引发的新问题也很明显,任何onBlur事件都会做出 scrollTop = 0 的操作,严重影响体验。

继续通过现象思考问题,当我们使用滑动触摸事件的时候,body会“跳动”到正常位置,而不不是正常的滚动,这一点很重要!

这表明了浏览器做了一个错误的渲染,那我不禁想到,我们做的“推”的操作是否必须?在一个错误的渲染下,我们是否只需要在键盘收起后做一个触发“重绘”的操作。

solution!

问题解决了,最终解决方案就很明显:

    onBlur = (e) => {
        const { onBlur } = this.props;
        document.body && (document.body.scrollTop = document.body.scrollTop);
        onBlur && onBlur(e);
    }

在input输入框失去焦点的钩子中设置滚动到原有位置(document.body.scrollTop = document.body.scrollTop),触发浏览器的重绘,使的错误的渲染回复正常,滚动位置也不会有改变,没有影响体验。

是不是很简单?

解决方案的简单,是建立在深层的思考中的,如果这篇文章能对你有所触动,那我的写作就没有白费。

更新一下评论区出现的方法,感谢 @ibca 提供。

(绝望的是我出现bug时去搜索这个问题竟然没有找到可用答案)

/**
 * 处理iOS 微信客户端6.7.4 键盘收起页面未下移bug
 */
;(/iphone|ipod|ipad/i.test(navigator.appVersion)) && document.addEventListener('blur', (e) => {
    // 这里加了个类型判断,因为a等元素也会触发blur事件
    ['input', 'textarea'].includes(e.target.localName) && document.body.scrollIntoView(false)
}, true)

— The End

作者:ZoenLeo

链接:https://juejin.im/post/5c07442f51882528c4469769


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK