ios系统输入框光标错位问题

时间:2024-03-01 16:34:31

原文出自: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密码外),大都是新开一个页面让用户填写,看来产品还是要往用户习惯上靠~