先强烈吐槽一下,不知道 Android Wekbit 开发人员怎么想的,如此糟糕 bug 从 4.0 到当下的 4.4 仍然如故,好像没有像修复的意思?难道这是改进不是 bug?
问题是这样的,使用 touch* 事件时,在 Android 4.0 上面的浏览器手指在 a 元素(或者其他任何元素)上做滑动操作,然后手指离开,结果不会触发 touchend 事件。同样的操作在 Android 2.x / ios 却会会正常触发 touchend 事件。到 touchmove 事件之后就终止掉,简单说,就是 touchend 事件丢失。天呐~无疑这是一个非常严重的bug——因为这是一个极其基础的事件,不可或缺!~My God~
看官们不信的话请试试这个测试用例。
<div id="foo"></div> <script> var el = document.getElementById('foo'); el.ontouchstart = function(e){ el.innerHTML = "touch start"; }; el.ontouchend = function(e){ el.innerHTML = "touch end"; }; el.ontouchmove = function(e){ el.innerHTML = "touch moved"; }; </script>
已经有许多人把该问题 report 了,详见:
怎么破?在 touchmove 事件中 e.preventDetault() 居然就可以。
el.ontouchend = function(e){ e.preventDefault(); // 可触发了 el.innerHTML = "touch end"; };但是简单调用 e.preventDetault() 会导致另外一个问题,就是阻止了屏幕上下滚动的 scorll 事件。
这又怎么破?
最后,我在一位兄台的博客里找到思路《手机浏览器常用手势动作监听封装》,具体思路就是“兼容的解决办法是在 touchmove 时判断手势趋势大于预设值时(大于预设值证明有 move的动作趋势),停止默认的操作e.preventDefault()”。于是我的代码就是这样。
/** * touchend事件丢失 */ function fixTouchEndNotFire(e, a1, a2, a3, disX){ if(window.navigator.isAndroid_4){ if ( disX > 7 ) { e.preventDefault(); } } }
加入到 touchmove 事件中。
另外一个方法个人原创(但是也是受了几个前辈的启发),见下面代码:<script> var timerId; document.ontouchmove = function(e){ window.clearInterval(timerId); timerId = window.setTimeout(myTouchEnd, 200); // console.log('ddddddd'); // e.preventDefault(); } function myTouchEnd(){ alert('why not start!!?') } // document.ontouchend = myTouchEnd; </script> Test onTouchEnd Event if be fired.
在这里抛砖引玉了,如有更好的方法请告知。