微信环境下input[type=text]点击软键盘闪现问题

-- 记一次神奇的bug

在项目测试阶段,在页面刚加载完毕的时候(上方进度条消失)点击输入框,弹出软键盘。但是在大约1秒的时候后软键盘就会自动消失,输入框的焦点消失。

这种现在只会出现在ios下的微信浏览器内,safari不会出现这个问题。

这会造成了很不舒适的用户体验,用户需要点击两次输入框才能真正输入内容。

对于这种全局性质的模糊bug,最好就是采用排除法去定位。在本地服务器内对当前页面的依赖逐步的排除,最后发现是第三方统计脚本引起了这个bug。

以下是肇事代码(省略)

    $(window).on('load',function(){
      var a = document;
      __showjoyDSP.script = a.createElement('script');
      __showjoyDSP.script.type = 'text/javascript';
      __showjoyDSP.script.async = true;
      __showjoyDSP.script.src = "http://market.m.showjoy.com/it-is-cover-by-article.js;
      var s = a.getElementsByTagName('script')[0];
      s.parentNode.insertBefore(__showjoyDSP.script, s);
    });

这段脚本在load事件触发的时候执行,执行时间符合bug复现的时间,不由猜测1

  • 动态的创建script标签会触发dom tree的构建,会不会因此引起页面重新布局或者重新绘制,导致光标焦点消失和软键盘的消失?

为了构建渲染树,浏览器做了如下工作:
从dom树的根节点开始,遍历每个可见的点,但是某些点不会进入渲染树中:来源

  1. 不可见的点:比如script meta标签
  2. 隐藏的点: display:none

本例中的第三方统计脚本动态创建的是script标签,并不会引起render tree的绘制等操作。

事实证明我将动态创建的script标签的src进行更换,

__showjoyDSP.script.src = "change-a-url.js"

上述的bug也就不会复现了,另外我在本地也试验动态的创建dom元素,强制浏览器进行重绘重布局操作,软键盘也不会消失。

$(window).on('load', function () {
  function go () {
    var L = document;
    v = L.createElement("div");
    v.innerHTML = '<span>hello world!</span>'
    L.body.insertBefore(v.firstChild, L.body.firstChild);
  }
  setTimeout(go, 5000);
})

页面在软键盘存在的情况下,5秒过后动态创建dom,软键盘不消失。

本着刨根的精神,来看看原统计脚本返回的js都有哪些内容,

__showjoyDSP.script.src = "http://market.m.showjoy.com/it-is-cover-by-article.js;

猜测2

  • 返回的js脚本中有什么事件触发软键盘的消失?

首先一番google后,并没有找到可以触发软键盘打开消失的事件,只能依靠用户点击了输入框这一操作。

查看了返回的js内容,也是几段独立的函数,作用都是动态创建script标签。利用chalars代理将脚本代理到本地,就可以随意的修改js内容了。采用排除法很快就定位到了一段函数。

-function(d) {
    var s = d.createElement('script'),
    e = d.body.getElementsByTagName('script')[0]; e.parentNode.insertBefore(s, e),
    f = 'https:' == location.protocol;
    s.src = (f ? 'https' : 'http') + '://'+(f?'fm.ipinyou.com':'fm.p0y.cn')+'/j/adv.js';
}(document);

猜想3

  • 没有见过函数体前加-,是不是函数前面的-引起的异常导致出现的bug?

查阅资料显示对于自执行函数,函数表达式后添加()会将函数立即执行,而函数声明后添加()并不会生效。而在函数声明前添加+ - ()等运算符,解析器会将声明看成是表达式,使()自执行生效。来源

再继续追踪fm.p0y.cn域下的脚本,在脚本中发现了一个动态创建iframe的操作。

setTimeout(function() {
    var f=document;
    e = f.createElement('iframe');
    e.src='" + ("http:" != location.protocol ? "https://cm.ipinyou.com/cmas.html?a=" + _py.getLast("a") : "http://fm.p0y.cn/cm/cma.html?a=" + _py.getLast("a")) + "';
    f.body.insertBefore(e,f.body.firstChild);
    e.style.display='none';
    }, 1000)

继续使用charles代理到本地修改异步执行的时间为5000毫秒,测试:

  • load事件触发
  • 立即点击输入框弹出软键盘
  • 5秒。。。。
  • 软键盘消失

到这里已经找到了bug的源头,在ios的微信内置浏览器内,动态创建iframe并且其src值存在。会导致页面造成页面切换的效果,即页面的焦点跑到了新的iframe中的页面中去。从而导致原页面的输入框焦点丢失。

利用weinre调试页面的时候更加清晰的看出:

当刷新页面的时候本应该user.m.showjoy.com页面,但是1秒过后又自动跳到了fm.pOy.cn页面,这个页面就是动态创建出来的iframe。

这个bug只出自ios机型微信内置浏览器的,但是ios微信浏览器用的是ios内置safari,而safari又没有这个问题。所以bug应该还是出自微信。

原创文章!转载需谨慎

标签: none

添加新评论