如何绑定'touchstart'和'click'事件但不回复两者?

DA.*_*DA. 193 jquery click touchstart

我正在开发一个必须在各种设备上运行的移动网站.黑莓手机让我头疼的是黑莓.

我们需要支持键盘点击和触摸事件.

理想情况下,我只是使用:

$thing.click(function(){...})
Run Code Online (Sandbox Code Playgroud)

但我们遇到的问题是,这些黑莓设备中的一些从触摸到触发点击时会有非常烦人的延迟.

解决方法是改为使用touchstart:

$thing.bind('touchstart', function(event){...})
Run Code Online (Sandbox Code Playgroud)

但是,如何绑定这两个事件,但只触发一个?我仍然需要键盘设备的click事件,但当然,如果我使用触摸设备,则不希望点击事件触发.

一个额外的问题:是否有这样做,另外还适用于甚至没有touchstart事件的浏览器?在研究这个问题时,看起来BlackBerry OS5不支持touchstart,因此还需要依赖该浏览器的点击事件.

附录:

也许更全面的问题是:

使用jQuery,是否可以/建议使用相同的绑定处理触摸交互和鼠标交互?

理想情况下,答案是肯定的.如果没有,我有一些选择:

1)我们使用WURFL获取设备信息,因此可以创建我们自己的设备矩阵.根据设备的不同,我们将使用touchstart或点击.

2)通过JS检测浏览器中的触摸支持(我需要对此进行更多的研究,但似乎这是可行的).

但是,这仍然存在一个问题:支持BOTH的设备如何.我们支持的一些手机(即Nokias和黑莓手机)同时具有触摸屏键盘.所以这种方式让我完全回到原来的问题......是否有办法允许两者同时以某种方式?

Mot*_*tie 132

更新:查看jQuery 指针事件Polyfill项目,该项目允许您绑定到"指针"事件,而不是在鼠标和触摸之间进行选择.


绑定到两者,但制作一个标志,以便该功能每100ms左右才会触发一次.

var flag = false;
$thing.bind('touchstart click', function(){
  if (!flag) {
    flag = true;
    setTimeout(function(){ flag = false; }, 100);
    // do something
  }

  return false
});
Run Code Online (Sandbox Code Playgroud)

  • 而不是使用`click`将其更改为`mousedown` ...也许长时间延迟是`mousedown`和`mouseup`之间的区别,这就是确定`click`的方式. (15认同)
  • 此时此问题已接近10万次.这似乎是一个非常常见的用例/问题.然而,这个和类似问题的答案和其他人似乎都很苛刻.谷歌解决方案,虽然比大多数人更彻底的思考,似乎只是一个更强大的黑客.对于像点击处理程序这样简单的事情,似乎解决方案应该很简单.没有人发现这个问题的非黑客解决方案? (12认同)
  • 嗯......感觉很讨厌,但这可行.问题在于,在某些设备上,这是一个明显的滞后......也许差不多一秒......这对于其他设备上的其他设备来说会很烦人. (7认同)
  • 这是我采用的解决方案.谢谢!我所做的是通过应用"触摸"类来标记"touchend"上的项目.这会在调用click事件之前触发.然后我添加一个click事件,首先检查该类是否存在.如果它在那里,我们假设触发事件已触发,除了删除类名称以"重置"它以进行下一次交互之外,我们不会执行任何操作.如果该类不存在,那么我们假设他们使用键盘单击该项,并从那里触发该功能. (7认同)
  • 您应该知道大多数手机浏览器在点击事件上有300毫秒的延迟,因此您应该将删除率增加到至少300,请参阅[关于300毫秒延迟问题的这篇文章](http://www.icenium.com/blog /icenium-team-blog/2013/11/21/what-exactly-is.....-the-300ms-click-delay).这基本上是为了启用"双击缩放"功能,这是iPhone早期的一个非常重要的功能,当时大多数网站都设计为在大型桌面屏幕上查看. (7认同)
  • 虽然这可能是撰写本文时最好的解决方案,但我强烈建议您查看下面罗伊的解决方案,该解决方案既简单又不那么麻烦:/sf/answers/2551669921/ (3认同)
  • 依赖于"touchend"存在问题.触摸后不会触发,然后将手指拖离元素.我最终做的是绑定到`touchend`,`touchmove`和`touchcancel`来表示触摸事件已经结束 - 所以,在你的情况下,当任何这些事件发生时,添加"触摸"类. (2认同)
  • 注意:您无法按元素处理鬼点击事件,它们由屏幕位置触发.如果触摸事件以某种方式更改页面,则延迟点击将触发页面更改后该位置中的任何元素. (2认同)
  • 很高兴使这个像'touchclick'这样的一般事件或者在整个站点中可以使用的东西,而不是每次都手动添加它...或者让计算机自动搜索点击事件然后更改它们...... (2认同)
  • 并不是说这是所有情况**的最佳解决方案**,但它绝对是一个相当不错的方法.话虽如此,为什么使用`setTimeout`,因为这依赖于jQuery?看看`$ .throttle`和/或`$ .debounce`(http://benalman.com/code/projects/jquery-throttle-debounce/docs/files/jquery-ba-throttle-debounce-js.html) (2认同)

Raf*_*oso 72

这是我"创建"的修复程序,它取出了GhostClick并实现了FastClick.尝试自己,让我们知道它是否适合您.

$(document).on('touchstart click', '.myBtn', function(event){
        if(event.handled === false) return
        event.stopPropagation();
        event.preventDefault();
        event.handled = true;

        // Do your magic here

});
Run Code Online (Sandbox Code Playgroud)

  • 这不起作用,因为通过在匿名函数中传递'event',它成为该函数中的本地对象,因此每次触发事件时`event.handled`将等于`undefined`.这是一个解决方案:使用`jQuery.data()`在目标元素本身中设置'processed'标志. (7认同)
  • 我非常喜欢这个问题的所有答案的方法,因为它是a)不测试设备功能和b)不使用setTimeout.根据我的经验,使用setTimeout的问题的解决方案可能适用于大多数情况,但事件的时间相当随意且特定于设备. (4认同)
  • 你有`event.stopPropagation();`和`event.preventDefault();`从我的理解(和测试)中,事件只能用这个触发一次.那么为什么要检查`if(event.handled!== true)`?对我来说没有必要或者我错过了什么? (3认同)
  • helgatheviking:http://jsbin.com/ijizat/25在JavaScript中有一个名为TouchClick的功能,它包含了上述功能. (2认同)
  • 不应该检查 `event.handled` 的值为 `true` 吗?据我所知,它永远不会是“假的”。它以 `undefined` 开头,然后你想知道它是否被设置为 `true`。 (2认同)

小智 49

你可以尝试这样的事情:

var clickEventType=((document.ontouchstart!==null)?'click':'touchstart');
$("#mylink").bind(clickEventType, myClickHandler);
Run Code Online (Sandbox Code Playgroud)

  • 这不是一个好主意 - 在使用鼠标时(具有触摸屏的笔记本电脑变得非常普遍),将为具有触摸屏和鼠标的用户打破事件. (8认同)
  • 我认为问题在于它是测试设备功能而不是用户正在做什么,对吧?挑战是我们需要支持也具有键盘的触摸设备(因此他们可以同时使用两者) (5认同)

Jon*_*han 42

通常这也适用:

$('#buttonId').on('touchstart click', function(e){
    e.stopPropagation(); e.preventDefault();
    //your code here

});
Run Code Online (Sandbox Code Playgroud)

  • @Jonathan错了,如果你使用的是更新的jQuery版本.Live已在1.7版中弃用. (8认同)

Roy*_*Roy 19

只需return false;on("click touchstart")事件结束时添加功能即可解决此问题.

$(this).on("click touchstart", function() {
  // Do things
  return false;
});
Run Code Online (Sandbox Code Playgroud)

来自.on()上的jQuery文档

false从事件处理程序返回将自动调用event.stopPropagation()event.preventDefault().false也可以为处理程序传递一个值作为简写function(){ return false; }.

  • 效果很好,在两者的设备上只触发一次 - 这对我来说似乎是最干净的解决方案 (3认同)

小智 10

我不得不做类似的事情.这是对我有用的简化版本.如果检测到触摸事件,请删除单击绑定.

$thing.on('touchstart click', function(event){
  if (event.type == "touchstart")
    $(this).off('click');

  //your code here
});
Run Code Online (Sandbox Code Playgroud)

在我的例子中,click事件被绑定到一个<a>元素,所以我不得不删除click绑定并重新绑定一个click事件,该事件阻止了该<a>元素的默认操作.

$thing.on('touchstart click', function(event){
  if (event.type == "touchstart")
    $(this).off('click').on('click', function(e){ e.preventDefault(); });

  //your code here
});
Run Code Online (Sandbox Code Playgroud)


Has*_*avi 7

我通过以下方式取得了成功.

十分简单...

$(this).on('touchstart click', function(e){
  e.preventDefault();
  //do your stuff here
});
Run Code Online (Sandbox Code Playgroud)

  • 对不起,我告诉你了.是的,你是正确的触摸将产生touchstart事件和点击事件.这称为鬼点击.谷歌已经为此实施了一个解决方案.可能不是直截了当但功能完美.链接在这里.http://code.google.com/mobile/articles/fast_buttons.html#ghost (8认同)
  • 在注册点击和触摸开始的设备上,它不会发生两次火灾吗? (4认同)
  • 可能是微不足道的,但你错过了`function()`中的`e`参数 (2认同)

Dre*_*TeK 6

我相信最好的做法是现在使用:

$('#object').on('touchend mouseup', function () { });
Run Code Online (Sandbox Code Playgroud)

触摸端

当触摸点从触摸表面上移除时会触发 touchend 事件。

touchend 事件不会触发任何鼠标事件。


鼠标向上

当鼠标指针悬停在元素上并释放鼠标按钮时,mouseup 事件被发送到元素。任何 HTML 元素都可以接收此事件。

mouseup 事件不会触发任何触摸事件。

例子

$('#object').on('touchend mouseup', function () { });
Run Code Online (Sandbox Code Playgroud)
$('#click').on('mouseup', function () { alert('Event detected'); });
$('#touch').on('touchend', function () { alert('Event detected'); });
Run Code Online (Sandbox Code Playgroud)


编辑 (2017)

截至 2017 年,从 Chrome 开始的浏览器正在采取措施,.on("click")通过消除点击请求上的点击事件产生的延迟,使点击事件对鼠标和触摸更兼容。

这得出的结论是,恢复到仅使用点击事件将是最简单的解决方案。

我还没有做过任何跨浏览器测试,看看这是否可行。