微信环境下点击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树的根节点开始,遍历每个可见的点,但是某些点不会进入渲染树中:来源
不可见的点:比如script meta标签
隐藏的点: 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应该还是出自微信。
原创文章!转载需谨慎
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。