2010-05-23 102 views
34

在使用交互式DOM元素执行单个页面JavaScript应用程序时我发现“mouseover-mousemove-mousedown-mouseup-click”顺序发生在之后touchstart-touchmove-touchend”事件序列。使用Javascript防止移动Safari/iPhone中的触摸事件产生鼠标仿真事件(即,单击)

我还发现,有可能防止由touchstart活动期间做一个“event.preventDefault()”发生的“mouse*-click”事件,但只有然后,而不是在touchmovetouchend。这是一个奇怪的设计,因为在touchstart期间不可能知道用户是否意图拖动或轻扫,或者只是点击/点击该项目。

我最终设置了一个与时间戳绑定的“ignore_next_click”标志,但这显然不是很干净。

有没有人知道这样做的更好方法,还是我们错过了什么?

注意的是,虽然“点击”可以被认定为“touchstart-touchend”序列(即没有“touchmove”),有一些事情,比如键盘输入焦点,可适当click事件时才会发生。

+0

我很感兴趣,iPad的Safari浏览器的触摸事件过于一部分,但它不是我清楚你想解决哪些具体问题。如果你仍然在处理这个问题,或者解决了这个问题,那么请细心阐述一下? – Tim 2010-08-01 13:04:10

+0

我希望能够处理某些事件,如拖放,并且还能够处理“点击”事件。我必须将“单击”事件作为适当的“单击”事件(而不是touchstart/touchend)来处理,因为某些事情(例如键盘输入焦点)可能只能在单击事件处理程序中激活。 – 2010-10-01 06:47:14

+0

这个问题非常讨厌,也影响到Android。 – 2011-04-26 18:06:30

回答

4

我遇到了类似的问题,使跨平台的HTML5/JS应用程序。对我来说唯一真正的答案是preventDefault关于触摸事件,并根据我的逻辑实际管理触摸状态和点击,拖动等事件。这听起来比实际上更令人生畏,但模仿的点击/鼠标事件在大多数移动浏览器上都能很好地工作。

点击和额外鼠标序列都在那里为您提供方便(和兼容性)。我的经验法则 - 如果它是为了您的方便,但它不方便,最好杀死它。

只要输入框,他们只需要touchend事件。我杀了点击/鼠标事件,并且仍然能够让移动浏览器正确地响应输入。如果它仍然给你的问题,你可以修改事件处理只在非输入剿事件:

function touchHandler(event) { 
    var shouldIgnore = event.target != null 
      && (event.target.tagName.toLowerCase() == "input" || event.target.tagName.toLowerCase() == "textarea"); 

    if(!shouldIgnore) e.preventDefault(); 
} 
+0

我在iOS5和Android 2.2.1上都测试了这个解决方案,问题是如果我在'touchstart'上防止默认,'click'不会触发,但我无法滚动页面。如果我在'touchend'上防止默认,它就会在iOS上工作(只在轻敲时),但在Android上触发'click'。你有没有注意到同样的问题?在这里测试:http://jsfiddle.net/3TBVc/ – 2012-04-10 13:49:59

+0

是的,我遇到了这个问题(表现在几个方面)。这似乎是Android iOS跨平台iOS <->更大的痛苦之一。这需要一些调整,但通过取消正确的事情,你通常可以得到想要的结果。 http://jsfiddle.net/3TBVc/9/似乎在Android上适合我。输入字段可能会吃一些'拖'事件(在Android上),但它的功能。 – 2012-04-10 20:55:07

+0

它仍然在我的Android设备上触发点击事件(并且还在iPhone上显示第一个按钮)。 – 2012-04-12 07:50:56

2

我做了一个解决方案我自己,因为我还没有找到足够的解决方案在别处:

var isTouch = ('ontouchstart' in window); 

    function kill(type){ 
    window.document.body.addEventListener(type, function(e){ 
     e.preventDefault(); 
     e.stopPropagation(); 
     return false; 
    }, true); 
    } 

    if(isTouch){ 
    kill('mousedown'); 
    kill('mouseup'); 
    kill('click'); 
    kill('mousemove'); 
    } 

isTouch的检查可让鼠标输入设备正常工作,但会杀死Safari/iOS上的仿真事件。诀窍是在addEventListener的调用中使用useCapture = true,这样我们就可以在页面中获取所有鼠标事件,而不会在整个Web应用程序中黑屏代码。请参阅该文档在这里的功能:https://developer.mozilla.org/en-US/docs/DOM/EventTarget.addEventListener?redirectlocale=en-US&redirectslug=DOM%2Felement.addEventListener

编辑:

现在处理这个问题库是更好的,你可以使用类似Fastclick作为替代(https://github.com/ftlabs/fastclick)。

+4

当您知道设备是触摸或鼠标输入时,这是一个很好的解决方案。但是当你拥有Windows 8笔记本电脑/平板电脑之类的东西时,你需要做其他事情。 – psayre23 2013-07-20 19:16:02

+0

我们的解决方案是监听click和touchstart/stop/move事件,并且只在'ontouchstart'不可用时注册点击事件。移动Safari浏览器同时注册触摸和点击事件,但该方法仅在该情况下注册触摸事件。另外,我们可以不考虑mousemove事件。 – 2014-03-03 23:38:22

+1

被拒绝,因为如果触摸事件可用,问题不是完全禁用鼠标事件... – iRaS 2014-10-26 15:47:19

2

如果您有支持它同时支持鼠标和触摸设备,另一种解决方案是使用捕获事件监听器停止触摸事件之后发生的任何

  • 延迟鼠标在整个事件
  • 在相同的位置相同的目标元件上的触摸事件
  • 作为触摸EV的触摸事件

的信息(时间,位置或目标元件) ent可以记录在另一个捕获事件侦听器中。

0

在Window.matchesMedia函数中包装鼠标唯一的代码是我找到的最干净的方法。

if (window.matchMedia('(hover: hover), (any-hover: hover), (-moz-touch-enabled: 0)').matches) { 
    el.addEventListener('mouseover', ev => { 
     // mouse handler, no simulated hover 
    } 
} 

这适用于防止模拟悬停,但也可能会阻止模拟点击。

请注意:启用-moz-触摸到Firefox的需要作为版本58