原文出自:http://www.cnblogs.com/zml-mary/p/7816495.html
qa测试手机升级以后弹框输入光标出现错位现象,前两天由于时间紧迫,一直没有找到好的解决方案,今天一天都在解决这个bug问题,临近下班终于算比较好的解决这个问题,觉得有必要理理~
引起原因:弹框的定位采取position:fixed,而ios(safari)对定位属性position:fixed的解析不一致导致。
解决方案:
方案一
一开始上网找解决方案,找到如下处理方式。但存在当页面出现滚动条时,弹框弹出后,页面回滚至顶部。在不改变原有弹框代码的情况下,有效地解决光标错位问题,但严重影响用户使用,只能忍痛舍去~
//弹框弹出后执行如下代码 $(\'body\').css({\'position\': \'fixed\', \'width\': \'100%\'}); //弹框关闭后执行如下代码 $(\'body\').css({\'position\': \'relative\'});
方案二
尝试多种方式后,只能从源头解决,不使用position:fixed。重写弹框定位,但问题是,这个弹框涉及所有页面,后台开发用这弹框做了很多操作,弹框中间内容由于可以自定义,所以是牵一发而动全身,不敢轻易改,就连上传图片的进度条显示都是用这个弹框做的(就是为了套用弹框的一个遮罩效果)
解决思路:
1.弹框(#pop )采用position:absolute定位,遮罩(#shadow)采用fixed定位(原先采用absolute定位的,由于有些页面内容是根据用户滚动进行动态加载,导致原先的遮罩不能完全遮住所有内容,当然也可以对某些元素定高进行加载内容,避免此类问题出现,但这次的修改要考虑通用性,后台开发有时候根本不管你这些,关键目前系统很多页面都已经出现这问题了)
2.弹框采用absolute定位后,关键是top值的确定(ios10.3 Safari 输入键盘弹出时,若页面底部被挤压上去,则关闭弹框会复原到页面滚动到底部时的状态,若底部没被挤压上去,每弹出一次键盘,页面都会上去一定距离,且不复原)
var initTopH = function() { var tempH = $(\'#pop\').height(); //弹框高度 var screenH = $(window).height();//手机屏幕高度 var scrollH = $(document).scrollTop();//文档内容滚动高度 var topH = scrollH + (screenH - tempH) / 2;//top值高度
//解决当输入键盘未手动关闭时,弹窗的定位问题
if ($(document).height() - scrollH < screenH) {
topH = $(document).height() - screenH + (screenH - tempH) / 2;
}
return topH; };
3.以为这样就可以解决问题,但新的问题出现,当输入框获得焦点时,移动端会弹出键盘挤压弹框上移,关闭键盘后,弹框不会恢复原位,所以需要对弹框失焦后在进行重新定位执行initTopH()
$("#pop input,textarea").off(\'blur\').on(\'blur\', function() { //这里只是对input和textarea处理 $(\'#pop\').css({\'top\':initTopH()}); });
4. 要成功解决一个问题,就会引发更多的问题需要解决,成功操作1-3的操作后,当弹框弹出后,若页面存在滚动条,此时滚动页面,弹框是不会跟着页面下移的,因为top是写死的。想当然是监听页面滚动(scroll)事件,实时改变top值,但问题是效果太差,抖动、弹跳太明显,qa肯定会提bug的~
另一途径就是弹出弹框后禁止页面滚动,以为设置body页面overflow:hidden就好了,然而pc端模拟测试有效果,真实环境仍然不起作用。以为没有给body定高,就都设置html,body标签的高度为100%;但然并卵,反而出现 $(document).scrollTop() 取值有问题(用$(\'body\').scrollTop()替换仍没用,关键pc端模拟都有效果,一到真实环境就出问题),影响前面弹框定位。烦~烦~烦~,反复测试,都没有实质性的进展~
前面一直纠结于给body定高,但想想还是不妥,很多页面开发者给各自页面都会重新定义样式,我这么暴力地修改,担心影响其他页面布局,所以果断放弃这条路子~
如何在不影响大局的情况下重新布局呢?突然想到了阻止默认事件 e.preventDefault() ,但是新问题又来了,使用这个可以很好的解决页面滚动问题,但也会阻止弹框里内容滚动。纠结ing~
5.左思右想,采取整体除去局部的思想来监听touchmove事件,方法如下,当触摸对象不是弹框时,阻止默认事件,当触摸对象是弹框时,虽然滚动弹框里的内容出现底部页面也滚动的情况,但触摸结束以后恢复原始的滚动高度,经测试效果还不错,也不觉得突兀~
$(\'#pop\').show(); var sh;//记录初始滚动高度 $(document).off(\'touchstart\').on(\'touchstart\', function(e) { sh = $(document).scrollTop(); }); $(document).off(\'touchmove\').on(\'touchmove\', function(e) { if (e.target.id === "shadow") {//除去#pop e.preventDefault(); } }); $(document).off(\'touchend\').on(\'touchend\', function(e) { $(document).scrollTop(sh); });
总结:虽然可能会有更好的解决方案,但这是我目前觉得比较好的处理方式,每个人所处的开发环境不一样,考虑的东西也不同,所以此方法并不一定都适应,可以借鉴参考。一天都在解决这个bug问题,找资料,尝试各种方法,虽然问题已解决,但还是想好好理顺下思路,故写下这篇随笔~啦~啦~啦~啦,下班啦~
ps:领导说可以看下其他应用的弹框是否有此类问题,看下人家是怎么解决的,但我和小伙伴看了所有app,都没找到类似弹出需要输入文字的弹框(除iphone手机弹出用户输入id密码外),大都是新开一个页面让用户填写,看来产品还是要往用户习惯上靠~