触屏RIA开发之为zepto升级,模拟用户行为
首先,老习惯,先介绍背景:
在开发html5的音乐播放RIA时,在Ios的safari里本小姐发现了一个诡异的问题:
1 //代码前提是引用了zepto.js 2 var audio = $("audio")[0]; 3 audio.src="test.mp3"; 4 audio.bind("tap",function(e){ 5 audio.play(); 6 })
zepto的tap居然失效了!!!怎么回事呢?加了很多断点后,发现tap事件并没有失效,而是在tap的回调函数里的audio.play()失效了,android的chrome啊,uc啊,还有PC端都是没有问题的,唯独safari,T^T,郁闷啊。。。。仔细研究了zepto的源码,发现zepto中所有事件,都运用了跳出线程的setTimeout函数。那么,就有了如下猜测:
由于有setTimeout的关系,浏览器将这个事件的触发看做了js代码行为,而不是用户行为,而对于HTML5的媒体标签(<audio><video>)safari有诡异的安全限制:不是用户的直接行为环境下,不能调用媒体标签的API。如果这个假设成立,那么直接绑定touchend事件,audio.play()应该可以执行。
接下来的验证,证明了本小姐的推测~那么,怎么解决这个问题呢。
那就是,为zepto升级,模拟用户行为:
大概思路就是,当用户触发一个事件的时候,我们创建一个dom对象,并为他绑定个事件,并模拟用户的方式触发这个事件。
铛铛铛铛~~~~代码如下:
1 function simuEvent(callback) { 2 var a = document.createElement('A'); 3 a.on('click',function handler(e) { 4 this.off('click', handler); 5 callback(); 6 }, false); 7 var e = document.createEvent('MouseEvent'); 8 e.initMouseEvent('click', true, true, this, 0, 0, 0, 0, 0, false, false, false, false, 0, null); 9 a.dispatchEvent(e); 10 }
那么如何使用呢?
如果需要绑定和媒体标签的API有关的事件,在绑定事件时,回调函数中使用就可以了,最初的代码修改如下:
1 //代码前提是引用了zepto.js 2 var audio = $("audio")[0]; 3 audio.src="test.mp3"; 4 audio.bind("tap",function(e){ 5 simuEvent(function(e2){ 6 audio.play(); 7 }); 8 })
这下,就可以绕过safari诡异的安全机制了,欺骗了傻乎乎的浏览器,哈哈。