如何绑定'touchstart'和'click'事件而不同时响应这两个事件?

时间:2022-11-26 23:55:26

I'm working on a mobile web site that has to work on a variety of devices. The one's giving me a headache at the moment are BlackBerry.

我正在为一个移动网站工作,这个网站必须在各种设备上运行。现在让我头疼的是黑莓。

We need to support both keyboard clicks as well as touch events.

我们需要同时支持键盘点击和触摸事件。

Ideally I'd just use:

理想情况下我只是使用:

$thing.click(function(){...})

but the issue we're running into is that some of these blackberry devices have an very annoying delay from the time of the touch to it triggering a click.

但我们现在遇到的问题是,有些黑莓手机从触屏到点击都有一个非常恼人的延迟。

The remedy is to instead use touchstart:

补救方法是使用touchstart:

$thing.bind('touchstart', function(event){...})

But how do I go about binding both events, but only firing one? I still need the click event for keyboard devices, but of course, don't want the click event firing if I'm using a touch device.

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

A bonus question: Is there anyway to do this and additionally accommodate browsers that don't even have a touchstart event? In researching this, it looks like BlackBerry OS5 doesn't support touchstart so will also need to rely on click events for that browser.

还有一个额外的问题:有什么办法可以做到这一点吗?在研究这个问题时,看起来黑莓OS5不支持touchstart,因此也需要依赖于该浏览器的点击事件。

ADDENDUM:

附录:

Perhaps a more comprehensive question is:

也许更全面的问题是:

With jQuery, is it possible/recommended to handle both touch interactions and mouse interactions with the same bindings?

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

Ideally, the answer is yes. If not, I do have some options:

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

1) We use WURFL to get device info so could create our own matrix of devices. Depending on the device, we'll use touchstart OR click.

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

2) Detect for touch support in the browser via JS (I need to do some more research on that, but it seems like that is doable).

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

However, that still leaves one issue: what about devices that support BOTH. Some of the phones we support (namely the Nokias and BlackBerries) have both touch screens and keyboards. So that kind of takes me full circle back to the original question...is there a way to allow for both at once somehow?

然而,这仍然留下了一个问题:支持两者的设备又如何呢?我们支持的一些手机(比如Nokias和黑莓)都有触摸屏和键盘。这让我回到了原来的问题……有没有一种方法可以同时兼顾这两方面?

35 个解决方案

#1


126  

Update: Check out the jQuery Pointer Events Polyfill project which allows you to bind to "pointer" events instead of choosing between mouse & touch.

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


Bind to both, but make a flag so the function only fires once per 100ms or so.

绑定到两者,但是创建一个标志,以便函数每100ms左右只触发一次。

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

  return false
});

#2


72  

This is the fix that I "create" and it take out the GhostClick and implements the FastClick. Try on your own and let us know if it worked for you.

这是我“创建”的修复,它取出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

});

#3


45  

You could try something like this:

你可以试试这样的方法:

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

#4


41  

Usually this works as well:

通常这也同样有效:

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

});

#5


14  

Just adding return false; at the end of the on("click touchstart") event function can solve this problem.

只是添加返回false;在on(单击touchstart)事件函数的末尾可以解决这个问题。

$(this).on("click touchstart", function() {
  // Do things
  return false;
});

From the jQuery documentation on .on()

从jQuery文档中,.on()

Returning false from an event handler will automatically call event.stopPropagation() and event.preventDefault(). A false value can also be passed for the handler as a shorthand for function(){ return false; }.

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

#6


10  

I had to do something similar. Here is a simplified version of what worked for me. If a touch event is detected, remove the click binding.

我必须做一些类似的事情。这里有一个对我有用的简化版本。如果检测到触摸事件,则删除单击绑定。

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

  //your code here
});

In my case the click event was bound to an <a> element so I had to remove the click binding and rebind a click event which prevented the default action for the <a> element.

在我的例子中,单击事件被绑定到元素,因此我必须删除单击绑定并重新绑定一个单击事件,该事件阻止了元素的默认操作。

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

  //your code here
});

#7


7  

I succeeded by the following way.

我以以下方式成功了。

Easy Peasy...

容易Peasy……

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

#8


4  

Generally you don't want to mix the default touch and non-touch (click) api. Once you move into the world of touch it easier to deal only with the touch related functions. Below is some pseudo code that would do what you want it to.

通常,您不希望混合默认的触摸和非触摸(单击)api。一旦你进入了触摸的世界,只处理与触摸相关的功能就更容易了。下面是一些伪代码,可以做您想做的事情。

If you connect in the touchmove event and track the locations you can add more items in the doTouchLogic function to detect gestures and whatnot.

如果您在touchmove事件中连接并跟踪位置,您可以在doTouchLogic函数中添加更多的项来检测手势和其他东西。

var touchStartTime;
var touchStartLocation;
var touchEndTime;
var touchEndLocation;

$thing.bind('touchstart'), function() {
     var d = new Date();
     touchStartTime = d.getTime();
     touchStartLocation = mouse.location(x,y);
});

$thing.bind('touchend'), function() {
     var d = new Date();
     touchEndTime= d.getTime();
     touchEndLocation= mouse.location(x,y);
     doTouchLogic();
});

function doTouchLogic() {
     var distance = touchEndLocation - touchStartLocation;
     var duration = touchEndTime - touchStartTime;

     if (duration <= 100ms && distance <= 10px) {
          // Person tapped their finger (do click/tap stuff here)
     }
     if (duration > 100ms && distance <= 10px) {
          // Person pressed their finger (not a quick tap)
     }
     if (duration <= 100ms && distance > 10px) {
          // Person flicked their finger
     }
     if (duration > 100ms && distance > 10px) {
          // Person dragged their finger
     }
}

#9


4  

I believe the best practice is now to use:

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

$('#object').on('touchend mouseup', function () { });

touchend

touchend

The touchend event is fired when a touch point is removed from the touch surface.

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

The touchend event will not trigger any mouse events.

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


mouseup

mouseup

The mouseup event is sent to an element when the mouse pointer is over the element, and the mouse button is released. Any HTML element can receive this event.

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

The mouseup event will not trigger any touch events.

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

EXAMPLE

例子

$('#click').on('mouseup', function () { alert('Event detected'); });
$('#touch').on('touchend', function () { alert('Event detected'); });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1 id="click">Click me</h1>
<h1 id="touch">Touch me</h1>


EDIT (2017)

编辑(2017)

As of 2017, browsers starting with Chrome and making steps towards making the click event .on("click") more compatible for both mouse and touch by eliminating the delay generated by tap events on click requests.

从2017年开始,浏览器将从Chrome开始,通过消除点击请求时点击事件产生的延迟,使点击事件.on(“单击”)对鼠标和触摸更加兼容。

This leads to the conclusion that reverting back to using just the click event would be the simplest solution moving forward.

这就得出这样的结论:返回到使用单击事件将是向前推进的最简单的解决方案。

I have not yet done any cross browser testing to see if this is practical.

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

#10


3  

check fast buttons and chost clicks from google https://developers.google.com/mobile/articles/fast_buttons

检查快速按钮和选择点击从谷歌https://developers.google.com/mobile/articles/fast_buttons

#11


3  

Well... All of these are super complicated.

嗯…所有这些都非常复杂。

If you have modernizr, it's a no-brainer.

如果你有现代感,这是显而易见的。

ev = Modernizr.touch ? 'touchstart' : 'click';

$('#menu').on(ev, '[href="#open-menu"]', function(){
  //winning
});

#12


2  

Another implementation for better maintenance. However, this technique will also do event.stopPropagation (). The click is not caught on any other element that clicked for 100ms.

更好维护的另一个实现。然而,这种技术也会处理事件。stopPropagation()。单击按钮不会被捕捉到单击100ms的任何其他元素。

var clickObject = {
    flag: false,
    isAlreadyClicked: function () {
        var wasClicked = clickObject.flag;
        clickObject.flag = true;
        setTimeout(function () { clickObject.flag = false; }, 100);
        return wasClicked;
    }
};

$("#myButton").bind("click touchstart", function (event) {
   if (!clickObject.isAlreadyClicked()) {
      ...
   }
}

#13


2  

Just for documentation purposes, here's what I've done for the fastest/most responsive click on desktop/tap on mobile solution that I could think of:

为了便于文档说明,以下是我在桌面/移动解决方案上最快/响应最快的单击/单击所做的工作:

I replaced jQuery's on function with a modified one that, whenever the browser supports touch events, replaced all my click events with touchstart.

我用一个修改过的jQuery on函数替换了jQuery的on函数,只要浏览器支持触摸事件,它就会用touchstart替换我所有的单击事件。

$.fn.extend({ _on: (function(){ return $.fn.on; })() });
$.fn.extend({
    on: (function(){
        var isTouchSupported = 'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch;
        return function( types, selector, data, fn, one ) {
            if (typeof types == 'string' && isTouchSupported && !(types.match(/touch/gi))) types = types.replace(/click/gi, 'touchstart');
            return this._on( types, selector, data, fn);
        };
    }()),
});

Usage than would be the exact same as before, like:

用法与以前完全相同,如:

$('#my-button').on('click', function(){ /* ... */ });

But it would use touchstart when available, click when not. No delays of any kind needed :D

但它会在可用时使用touchstart,不在可用时单击。不需要任何延迟:D

#14


2  

I just came up with the idea to memorize if ontouchstart was ever triggered. In this case we are on a device which supports it and want to ignore the onclick event. Since ontouchstart should always be triggered before onclick, I'm using this:

我刚想到了记忆ontouchstart是否被触发的想法。在本例中,我们在一个支持它的设备上,并希望忽略onclick事件。在onclick之前,ontouchstart应该总是被触发,我使用这个:

<script> touchAvailable = false; </script>
<button ontouchstart="touchAvailable=true; myFunction();" onclick="if(!touchAvailable) myFunction();">Button</button>

#15


1  

You could try like this:

你可以这样尝试:

var clickEvent = (('ontouchstart' in document.documentElement)?'touchstart':'click');
$("#mylink").on(clickEvent, myClickHandler);

#16


1  

This worked for me, mobile listens to both, so prevent the one, which is the touch event. desktop only listen to mouse.

这对我来说是可行的,手机会同时听两种声音,所以要防止触控事件。桌面只听鼠标。

 $btnUp.bind('touchstart mousedown',function(e){
     e.preventDefault();

     if (e.type === 'touchstart') {
         return;
     }

     var val = _step( _options.arrowStep );
               _evt('Button', [val, true]);
  });

#17


1  

In my case this worked perfectly:

在我的例子中,这非常有效:

jQuery(document).on('mouseup keydown touchend', function (event) {
var eventType = event.type;
if (eventType == 'touchend') {
    jQuery(this).off('mouseup');
}
});

The main problem was when instead mouseup I tried with click, on touch devices triggered click and touchend at the same time, if i use the click off, some functionality didn't worked at all on mobile devices. The problem with click is that is a global event that fire the rest of the event including touchend.

主要的问题是,当鼠标向上移动时,我尝试了点击,在触控设备上同时触发点击和触头,如果我使用点击关闭,一些功能在移动设备上根本就不能工作。单击的问题是,这是一个全局事件,将触发事件的其余部分,包括touchend。

#18


0  

I am also working on an Android/iPad web app, and it seems that if only using "touchmove" is enough to "move components" ( no need touchstart ). By disabling touchstart, you can use .click(); from jQuery. It's actually working because it hasn't be overloaded by touchstart.

我还在开发一个Android/iPad web应用程序,如果仅仅使用“touchmove”就足以“移动组件”(不需要touchstart)。通过禁用touchstart,您可以使用.click();从jQuery。它实际上是工作的,因为它没有被touchstart重载。

Finally, you can binb .live("touchstart", function(e) { e.stopPropagation(); }); to ask the touchstart event to stop propagating, living room to click() to get triggered.

最后,您可以binb .live(“touchstart”,函数(e) {e.stopPropagation();});若要请求touchstart事件停止传播,请单击()以触发客厅。

It worked for me.

它为我工作。

#19


0  

There are many things to consider when trying to solve this issue. Most solutions either break scrolling or don't handle ghost click events properly.

在试图解决这个问题时,有很多事情要考虑。大多数解决方案要么中断滚动,要么不正确地处理幽灵单击事件。

For a full solution see https://developers.google.com/mobile/articles/fast_buttons

有关完整的解决方案,请参见https://developers.google.com/mobile/articles/fast_buttons

NB: You cannot handle ghost click events on a per-element basis. A delayed click is fired by screen location, so if your touch events modify the page in some way, the click event will be sent to the new version of the page.

NB:您不能在每个元素的基础上处理幽灵单击事件。延迟单击由屏幕位置触发,因此如果您的触摸事件以某种方式修改页面,单击事件将被发送到页面的新版本。

#20


0  

It may be effective to assign to the events 'touchstart mousedown' or 'touchend mouseup' to avoid undesired side-effects of using click.

将其分配到事件的touchstart mousedown或touchend mouseup可能是有效的,以避免使用click带来的不希望的副作用。

#21


0  

Taking advantage of the fact that a click will always follow a touch event, here is what I did to get rid of the "ghost click" without having to use timeouts or global flags.

利用点击总是跟随触摸事件的这一事实,以下是我在不使用超时或全局标志的情况下删除“ghost click”的方法。

$('#buttonId').on('touchstart click', function(event){
    if ($(this).data("already")) {
        $(this).data("already", false);
        return false;
    } else if (event.type == "touchstart") {
        $(this).data("already", true);
    }
    //your code here
});

Basically whenever an ontouchstart event fires on the element, a flag a set and then subsequently removed (and ignored), when the click comes.

基本上,只要ontouchstart事件在元素上触发,就会标记一个集合,然后在单击时删除(并忽略)。

#22


0  

Why not use the jQuery Event API?

为什么不使用jQuery事件API呢?

http://learn.jquery.com/events/event-extensions/

http://learn.jquery.com/events/event-extensions/

I've used this simple event with success. It's clean, namespaceable and flexible enough to improve upon.

我成功地利用了这个简单的事件。它干净、有命名空间、灵活,足以改进。

var isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent);
var eventType = isMobile ? "touchstart" : "click";

jQuery.event.special.touchclick = {
  bindType: eventType,
  delegateType: eventType
};

#23


0  

If you are using jQuery the following worked pretty well for me:

如果您正在使用jQuery,下面的方法对我来说非常有用:

var callback; // Initialize this to the function which needs to be called

$(target).on("click touchstart", selector, (function (func){
    var timer = 0;
    return function(e){
        if ($.now() - timer < 500) return false;
        timer = $.now();
        func(e);
    }
})(callback));

Other solutions are also good but I was binding multiple events in a loop and needed the self calling function to create an appropriate closure. Also, I did not want to disable the binding since I wanted it to be invoke-able on next click/touchstart.

其他的解决方案也不错,但是我在一个循环中绑定了多个事件,需要self调用函数来创建一个合适的闭包。另外,我不想禁用绑定,因为我希望它可以在下一次点击/touchstart时进行开发。

Might help someone in similar situation!

可能会帮助类似的人!

#24


0  

For simple features, just recognize touch or click I use the following code:

对于简单的功能,只需识别触摸或点击我使用以下代码:

var element = $("#element");

element.click(function(e)
{
  if(e.target.ontouchstart !== undefined)
  {
    console.log( "touch" );
    return;
  }
  console.log( "no touch" );
});

This will return "touch" if the touchstart event is defined and "no touch" if not. Like I said this is a simple approach for click/tap events just that.

这将返回“touch”,如果touchstart事件被定义并且“没有触摸”,如果没有。就像我说的,这是一个简单的点击/点击事件的方法。

#25


0  

I am trying this and so far it works (but I am only on Android/Phonegap so caveat emptor)

我正在尝试这个功能,到目前为止它还能工作(但我只在Android/Phonegap上工作,所以买者请小心)

  function filterEvent( ob, ev ) {
      if (ev.type == "touchstart") {
          ob.off('click').on('click', function(e){ e.preventDefault(); });
      }
  }
  $('#keypad').on('touchstart click', '.number, .dot', function(event) {
      filterEvent( $('#keypad'), event );
      console.log( event.type );  // debugging only
           ... finish handling touch events...
  }

I don't like the fact that I am re-binding handlers on every touch, but all things considered touches don't happen very often (in computer time!)

我不喜欢在每次触摸时都重新绑定处理程序,但是所有被考虑到的触摸都不会经常发生(在计算机时代!)

I have a TON of handlers like the one for '#keypad' so having a simple function that lets me deal with the problem without too much code is why I went this way.

我有很多处理程序,比如“#keypad”,所以有一个简单的函数可以让我在不需要太多代码的情况下处理问题,这就是我为什么要这样做的原因。

#26


0  

Being for me the best answer the one given by Mottie, I'm just trying to do his code more reusable, so it's my contribution:

对我来说,最好的答案是,我只是想让他的代码更可重复使用,这是我的贡献:

bindBtn ("#loginbutton",loginAction);

function bindBtn(element,action){

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

#27


0  

Try to use Virtual Mouse (vmouse) Bindings from jQuery Mobile. It's virtual event especially for your case:

尝试使用来自jQuery Mobile的虚拟鼠标(vmouse)绑定。这是虚拟的事件,特别是对于你的情况:

$thing.on('vclick', function(event){ ... });

http://api.jquerymobile.com/vclick/

http://api.jquerymobile.com/vclick/

Browser support list: http://jquerymobile.com/browser-support/1.4/

浏览器支持列表:http://jquerymobile.com/browser-support/1.4/

#28


0  

EDIT: My former answer (based on answers in this thread) was not the way to go for me. I wanted a sub-menu to expand on mouse enter or touch click and to collapse on mouse leave or another touch click. Since mouse events normally are being fired after touch events, it was kind of tricky to write event listeners that support both touchscreen and mouse input at the same time.

编辑:我以前的答案(基于这个帖子的答案)对我来说不太合适。我想要一个子菜单来扩展鼠标的输入或触摸点击并在鼠标离开或另一个触摸点击时崩溃。由于鼠标事件通常是在触摸事件之后触发的,因此编写同时支持触摸屏和鼠标输入的事件监听器有点棘手。

jQuery plugin: Touch Or Mouse

I ended up writing a jQuery plugin called "Touch Or Mouse" (897 bytes minified) that can detect whether an event was invoked by a touchscreen or mouse (without testing for touch support!). This enables the support of both touchscreen and mouse at the same time and completely separate their events.

我最后编写了一个名为“Touch Or Mouse”的jQuery插件(897字节缩小),它可以检测一个事件是被触摸屏还是鼠标调用(不需要测试触摸支持!)这可以同时支持触摸屏和鼠标,并完全分离它们的事件。

This way the OP can use touchstart or touchend for quickly responding to touch clicks and click for clicks invoked only by a mouse.

这样,OP可以使用touchstart或touchend快速响应触摸单击,并单击仅由鼠标调用的单击。

Demonstration

First one has to make ie. the body element track touch events:

首先要做ie。body元素跟踪触摸事件:

$(document.body).touchOrMouse('init');

Mouse events our bound to elements in the default way and by calling $body.touchOrMouse('get', e) we can find out whether the event was invoked by a touchscreen or mouse.

鼠标以默认方式并通过调用$body来事件我们对元素的绑定。touchOrMouse('get', e)我们可以发现事件是由触摸屏还是鼠标调用的。

$('.link').click(function(e) {
  var touchOrMouse = $(document.body).touchOrMouse('get', e);

  if (touchOrMouse === 'touch') {
    // Handle touch click.
  }
  else if (touchOrMouse === 'mouse') {
    // Handle mouse click.
  }
}

See the plugin at work at http://jsfiddle.net/lmeurs/uo4069nh.

请参见http://jsfiddle.net/lmeurs/uo4069nh的插件。

Explanation

  1. This plugin needs to be called on ie. the body element to track touchstart and touchend events, this way the touchend event does not have to be fired on the trigger element (ie. a link or button). Between these two touch events this plugin considers any mouse event to be invoked by touch.
  2. 这个插件需要在ie上调用。跟踪touchstart和touchend事件的body元素,这样touchend事件就不必在触发器元素(即触发器)上触发。一个链接或按钮)。在这两个触摸事件之间,这个插件考虑任何鼠标事件被触摸调用。
  3. Mouse events are fired only after touchend, when a mouse event is being fired within the ghostEventDelay (option, 1000ms by default) after touchend, this plugin considers the mouse event to be invoked by touch.
  4. 鼠标事件是在touchend之后才被触发的,当一个鼠标事件被触发后,在ghostEventDelay(默认值是1000ms)中被触发后,这个插件会考虑通过触摸来调用鼠标事件。
  5. When clicking on an element using a touchscreen, the element gains the :active state. The mouseleave event is only fired after the element loses this state by ie. clicking on another element. Since this could be seconds (or minutes!) after the mouseenter event has been fired, this plugin keeps track of an element's last mouseenter event: if the last mouseenter event was invoked by touch, the following mouseleave event is also considered to be invoked by touch.
  6. 当使用触摸屏单击元素时,元素将获得:active状态。mouseleave事件只有在元素失去ie的状态后才被触发。点击另一个元素。由于这可能是在触发mouseenter事件之后的几秒钟(或者几分钟!),所以这个插件跟踪一个元素的最后一个mouseenter事件:如果最后一个mouseenter事件是通过touch调用的,那么下面的mouseleave事件也被认为是通过touch调用的。

#29


0  

Here's a simple way to do it:

这里有一个简单的方法:

// A very simple fast click implementation
$thing.on('click touchstart', function(e) {
  if (!$(document).data('trigger')) $(document).data('trigger', e.type);
  if (e.type===$(document).data('trigger')) {
    // Do your stuff here
  }
});

You basically save the first event type that is triggered to the 'trigger' property in jQuery's data object that is attached to the root document, and only execute when the event type is equal to the value in 'trigger'. On touch devices, the event chain would likely be 'touchstart' followed by 'click'; however, the 'click' handler won't be executed because "click" doesn't match the initial event type saved in 'trigger' ("touchstart").

基本上,您将第一个事件类型保存在jQuery数据对象中的“触发器”属性中,该属性附加到根文档,并且只在事件类型等于“触发器”中的值时执行。在触控设备上,事件链可能是“touchstart”,然后是“click”;但是,“单击”处理程序不会执行,因为“单击”与保存在“触发器”(“touchstart”)中的初始事件类型不匹配。

The assumption, and I do believe it's a safe one, is that your smartphone won't spontaneously change from a touch device to a mouse device or else the tap won't ever register because the 'trigger' event type is only saved once per page load and "click" would never match "touchstart".

我认为这是一个安全的假设,因为你的智能手机不会自动从触控设备变成鼠标设备,或者是不会自动注册,因为“触发”事件类型只会在每次页面加载时保存一次,而“点击”永远不会匹配“touchstart”。

Here's a codepen you can play around with (try tapping on the button on a touch device -- there should be no click delay): http://codepen.io/thdoan/pen/xVVrOZ

这是一个你可以玩的codepen(试着点击触摸设备上的按钮——不应该有点击延迟):http://codepen.io/thdoan/pen/xVVrOZ。

I also implemented this as a simple jQuery plugin that also supports jQuery's descendants filtering by passing a selector string:

我还实现了一个简单的jQuery插件,它通过传递一个选择器字符串来支持jQuery的后代过滤:

// A very simple fast click plugin
// Syntax: .fastClick([selector,] handler)
$.fn.fastClick = function(arg1, arg2) {
  var selector, handler;
  switch (typeof arg1) {
    case 'function':
      selector = null;
      handler = arg1;
      break;
    case 'string':
      selector = arg1;
      if (typeof arg2==='function') handler = arg2;
      else return;
      break;
    default:
      return;
  }
  this.on('click touchstart', selector, function(e) {
    if (!$(document).data('trigger')) $(document).data('trigger', e.type);
    if (e.type===$(document).data('trigger')) handler.apply(this, arguments);
  });
};

Codepen: http://codepen.io/thdoan/pen/GZrBdo/

Codepen:http://codepen.io/thdoan/pen/GZrBdo/

#30


0  

The best method I have found is to write the touch event and have that event call the normal click event programatically. This way you have all your normal click events and then you need to add just one event handler for all touch events. For every node you want to make touchable, just add the "touchable" class to it to invoke the touch handler. With Jquery it works like so with some logic to make sure its a real touch event and not a false positive.

我发现的最好的方法是编写触摸事件,并让该事件按程序调用常规单击事件。这样,您就有了所有的常规单击事件,然后需要为所有的touch事件添加一个事件处理程序。对于每个想要创建touchable的节点,只需向其添加“touchable”类来调用touch处理程序。使用Jquery,它的工作原理是这样的,并带有一些逻辑,以确保它是一个真正的触摸事件,而不是一个错误的正数。

$("body").on("touchstart", ".touchable", function() { //make touchable  items fire like a click event
var d1 = new Date();
var n1 = d1.getTime();
setTimeout(function() {
    $(".touchable").on("touchend", function(event) {
        var d2 = new Date();
        var n2 = d2.getTime();
        if (n2 - n1 <= 300) {
            $(event.target).trigger("click"); //dont do the action here just call real click handler
        }
    });
}, 50)}).on("click", "#myelement", function() {
//all the behavior i originally wanted
});

#1


126  

Update: Check out the jQuery Pointer Events Polyfill project which allows you to bind to "pointer" events instead of choosing between mouse & touch.

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


Bind to both, but make a flag so the function only fires once per 100ms or so.

绑定到两者,但是创建一个标志,以便函数每100ms左右只触发一次。

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

  return false
});

#2


72  

This is the fix that I "create" and it take out the GhostClick and implements the FastClick. Try on your own and let us know if it worked for you.

这是我“创建”的修复,它取出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

});

#3


45  

You could try something like this:

你可以试试这样的方法:

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

#4


41  

Usually this works as well:

通常这也同样有效:

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

});

#5


14  

Just adding return false; at the end of the on("click touchstart") event function can solve this problem.

只是添加返回false;在on(单击touchstart)事件函数的末尾可以解决这个问题。

$(this).on("click touchstart", function() {
  // Do things
  return false;
});

From the jQuery documentation on .on()

从jQuery文档中,.on()

Returning false from an event handler will automatically call event.stopPropagation() and event.preventDefault(). A false value can also be passed for the handler as a shorthand for function(){ return false; }.

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

#6


10  

I had to do something similar. Here is a simplified version of what worked for me. If a touch event is detected, remove the click binding.

我必须做一些类似的事情。这里有一个对我有用的简化版本。如果检测到触摸事件,则删除单击绑定。

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

  //your code here
});

In my case the click event was bound to an <a> element so I had to remove the click binding and rebind a click event which prevented the default action for the <a> element.

在我的例子中,单击事件被绑定到元素,因此我必须删除单击绑定并重新绑定一个单击事件,该事件阻止了元素的默认操作。

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

  //your code here
});

#7


7  

I succeeded by the following way.

我以以下方式成功了。

Easy Peasy...

容易Peasy……

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

#8


4  

Generally you don't want to mix the default touch and non-touch (click) api. Once you move into the world of touch it easier to deal only with the touch related functions. Below is some pseudo code that would do what you want it to.

通常,您不希望混合默认的触摸和非触摸(单击)api。一旦你进入了触摸的世界,只处理与触摸相关的功能就更容易了。下面是一些伪代码,可以做您想做的事情。

If you connect in the touchmove event and track the locations you can add more items in the doTouchLogic function to detect gestures and whatnot.

如果您在touchmove事件中连接并跟踪位置,您可以在doTouchLogic函数中添加更多的项来检测手势和其他东西。

var touchStartTime;
var touchStartLocation;
var touchEndTime;
var touchEndLocation;

$thing.bind('touchstart'), function() {
     var d = new Date();
     touchStartTime = d.getTime();
     touchStartLocation = mouse.location(x,y);
});

$thing.bind('touchend'), function() {
     var d = new Date();
     touchEndTime= d.getTime();
     touchEndLocation= mouse.location(x,y);
     doTouchLogic();
});

function doTouchLogic() {
     var distance = touchEndLocation - touchStartLocation;
     var duration = touchEndTime - touchStartTime;

     if (duration <= 100ms && distance <= 10px) {
          // Person tapped their finger (do click/tap stuff here)
     }
     if (duration > 100ms && distance <= 10px) {
          // Person pressed their finger (not a quick tap)
     }
     if (duration <= 100ms && distance > 10px) {
          // Person flicked their finger
     }
     if (duration > 100ms && distance > 10px) {
          // Person dragged their finger
     }
}

#9


4  

I believe the best practice is now to use:

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

$('#object').on('touchend mouseup', function () { });

touchend

touchend

The touchend event is fired when a touch point is removed from the touch surface.

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

The touchend event will not trigger any mouse events.

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


mouseup

mouseup

The mouseup event is sent to an element when the mouse pointer is over the element, and the mouse button is released. Any HTML element can receive this event.

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

The mouseup event will not trigger any touch events.

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

EXAMPLE

例子

$('#click').on('mouseup', function () { alert('Event detected'); });
$('#touch').on('touchend', function () { alert('Event detected'); });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1 id="click">Click me</h1>
<h1 id="touch">Touch me</h1>


EDIT (2017)

编辑(2017)

As of 2017, browsers starting with Chrome and making steps towards making the click event .on("click") more compatible for both mouse and touch by eliminating the delay generated by tap events on click requests.

从2017年开始,浏览器将从Chrome开始,通过消除点击请求时点击事件产生的延迟,使点击事件.on(“单击”)对鼠标和触摸更加兼容。

This leads to the conclusion that reverting back to using just the click event would be the simplest solution moving forward.

这就得出这样的结论:返回到使用单击事件将是向前推进的最简单的解决方案。

I have not yet done any cross browser testing to see if this is practical.

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

#10


3  

check fast buttons and chost clicks from google https://developers.google.com/mobile/articles/fast_buttons

检查快速按钮和选择点击从谷歌https://developers.google.com/mobile/articles/fast_buttons

#11


3  

Well... All of these are super complicated.

嗯…所有这些都非常复杂。

If you have modernizr, it's a no-brainer.

如果你有现代感,这是显而易见的。

ev = Modernizr.touch ? 'touchstart' : 'click';

$('#menu').on(ev, '[href="#open-menu"]', function(){
  //winning
});

#12


2  

Another implementation for better maintenance. However, this technique will also do event.stopPropagation (). The click is not caught on any other element that clicked for 100ms.

更好维护的另一个实现。然而,这种技术也会处理事件。stopPropagation()。单击按钮不会被捕捉到单击100ms的任何其他元素。

var clickObject = {
    flag: false,
    isAlreadyClicked: function () {
        var wasClicked = clickObject.flag;
        clickObject.flag = true;
        setTimeout(function () { clickObject.flag = false; }, 100);
        return wasClicked;
    }
};

$("#myButton").bind("click touchstart", function (event) {
   if (!clickObject.isAlreadyClicked()) {
      ...
   }
}

#13


2  

Just for documentation purposes, here's what I've done for the fastest/most responsive click on desktop/tap on mobile solution that I could think of:

为了便于文档说明,以下是我在桌面/移动解决方案上最快/响应最快的单击/单击所做的工作:

I replaced jQuery's on function with a modified one that, whenever the browser supports touch events, replaced all my click events with touchstart.

我用一个修改过的jQuery on函数替换了jQuery的on函数,只要浏览器支持触摸事件,它就会用touchstart替换我所有的单击事件。

$.fn.extend({ _on: (function(){ return $.fn.on; })() });
$.fn.extend({
    on: (function(){
        var isTouchSupported = 'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch;
        return function( types, selector, data, fn, one ) {
            if (typeof types == 'string' && isTouchSupported && !(types.match(/touch/gi))) types = types.replace(/click/gi, 'touchstart');
            return this._on( types, selector, data, fn);
        };
    }()),
});

Usage than would be the exact same as before, like:

用法与以前完全相同,如:

$('#my-button').on('click', function(){ /* ... */ });

But it would use touchstart when available, click when not. No delays of any kind needed :D

但它会在可用时使用touchstart,不在可用时单击。不需要任何延迟:D

#14


2  

I just came up with the idea to memorize if ontouchstart was ever triggered. In this case we are on a device which supports it and want to ignore the onclick event. Since ontouchstart should always be triggered before onclick, I'm using this:

我刚想到了记忆ontouchstart是否被触发的想法。在本例中,我们在一个支持它的设备上,并希望忽略onclick事件。在onclick之前,ontouchstart应该总是被触发,我使用这个:

<script> touchAvailable = false; </script>
<button ontouchstart="touchAvailable=true; myFunction();" onclick="if(!touchAvailable) myFunction();">Button</button>

#15


1  

You could try like this:

你可以这样尝试:

var clickEvent = (('ontouchstart' in document.documentElement)?'touchstart':'click');
$("#mylink").on(clickEvent, myClickHandler);

#16


1  

This worked for me, mobile listens to both, so prevent the one, which is the touch event. desktop only listen to mouse.

这对我来说是可行的,手机会同时听两种声音,所以要防止触控事件。桌面只听鼠标。

 $btnUp.bind('touchstart mousedown',function(e){
     e.preventDefault();

     if (e.type === 'touchstart') {
         return;
     }

     var val = _step( _options.arrowStep );
               _evt('Button', [val, true]);
  });

#17


1  

In my case this worked perfectly:

在我的例子中,这非常有效:

jQuery(document).on('mouseup keydown touchend', function (event) {
var eventType = event.type;
if (eventType == 'touchend') {
    jQuery(this).off('mouseup');
}
});

The main problem was when instead mouseup I tried with click, on touch devices triggered click and touchend at the same time, if i use the click off, some functionality didn't worked at all on mobile devices. The problem with click is that is a global event that fire the rest of the event including touchend.

主要的问题是,当鼠标向上移动时,我尝试了点击,在触控设备上同时触发点击和触头,如果我使用点击关闭,一些功能在移动设备上根本就不能工作。单击的问题是,这是一个全局事件,将触发事件的其余部分,包括touchend。

#18


0  

I am also working on an Android/iPad web app, and it seems that if only using "touchmove" is enough to "move components" ( no need touchstart ). By disabling touchstart, you can use .click(); from jQuery. It's actually working because it hasn't be overloaded by touchstart.

我还在开发一个Android/iPad web应用程序,如果仅仅使用“touchmove”就足以“移动组件”(不需要touchstart)。通过禁用touchstart,您可以使用.click();从jQuery。它实际上是工作的,因为它没有被touchstart重载。

Finally, you can binb .live("touchstart", function(e) { e.stopPropagation(); }); to ask the touchstart event to stop propagating, living room to click() to get triggered.

最后,您可以binb .live(“touchstart”,函数(e) {e.stopPropagation();});若要请求touchstart事件停止传播,请单击()以触发客厅。

It worked for me.

它为我工作。

#19


0  

There are many things to consider when trying to solve this issue. Most solutions either break scrolling or don't handle ghost click events properly.

在试图解决这个问题时,有很多事情要考虑。大多数解决方案要么中断滚动,要么不正确地处理幽灵单击事件。

For a full solution see https://developers.google.com/mobile/articles/fast_buttons

有关完整的解决方案,请参见https://developers.google.com/mobile/articles/fast_buttons

NB: You cannot handle ghost click events on a per-element basis. A delayed click is fired by screen location, so if your touch events modify the page in some way, the click event will be sent to the new version of the page.

NB:您不能在每个元素的基础上处理幽灵单击事件。延迟单击由屏幕位置触发,因此如果您的触摸事件以某种方式修改页面,单击事件将被发送到页面的新版本。

#20


0  

It may be effective to assign to the events 'touchstart mousedown' or 'touchend mouseup' to avoid undesired side-effects of using click.

将其分配到事件的touchstart mousedown或touchend mouseup可能是有效的,以避免使用click带来的不希望的副作用。

#21


0  

Taking advantage of the fact that a click will always follow a touch event, here is what I did to get rid of the "ghost click" without having to use timeouts or global flags.

利用点击总是跟随触摸事件的这一事实,以下是我在不使用超时或全局标志的情况下删除“ghost click”的方法。

$('#buttonId').on('touchstart click', function(event){
    if ($(this).data("already")) {
        $(this).data("already", false);
        return false;
    } else if (event.type == "touchstart") {
        $(this).data("already", true);
    }
    //your code here
});

Basically whenever an ontouchstart event fires on the element, a flag a set and then subsequently removed (and ignored), when the click comes.

基本上,只要ontouchstart事件在元素上触发,就会标记一个集合,然后在单击时删除(并忽略)。

#22


0  

Why not use the jQuery Event API?

为什么不使用jQuery事件API呢?

http://learn.jquery.com/events/event-extensions/

http://learn.jquery.com/events/event-extensions/

I've used this simple event with success. It's clean, namespaceable and flexible enough to improve upon.

我成功地利用了这个简单的事件。它干净、有命名空间、灵活,足以改进。

var isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent);
var eventType = isMobile ? "touchstart" : "click";

jQuery.event.special.touchclick = {
  bindType: eventType,
  delegateType: eventType
};

#23


0  

If you are using jQuery the following worked pretty well for me:

如果您正在使用jQuery,下面的方法对我来说非常有用:

var callback; // Initialize this to the function which needs to be called

$(target).on("click touchstart", selector, (function (func){
    var timer = 0;
    return function(e){
        if ($.now() - timer < 500) return false;
        timer = $.now();
        func(e);
    }
})(callback));

Other solutions are also good but I was binding multiple events in a loop and needed the self calling function to create an appropriate closure. Also, I did not want to disable the binding since I wanted it to be invoke-able on next click/touchstart.

其他的解决方案也不错,但是我在一个循环中绑定了多个事件,需要self调用函数来创建一个合适的闭包。另外,我不想禁用绑定,因为我希望它可以在下一次点击/touchstart时进行开发。

Might help someone in similar situation!

可能会帮助类似的人!

#24


0  

For simple features, just recognize touch or click I use the following code:

对于简单的功能,只需识别触摸或点击我使用以下代码:

var element = $("#element");

element.click(function(e)
{
  if(e.target.ontouchstart !== undefined)
  {
    console.log( "touch" );
    return;
  }
  console.log( "no touch" );
});

This will return "touch" if the touchstart event is defined and "no touch" if not. Like I said this is a simple approach for click/tap events just that.

这将返回“touch”,如果touchstart事件被定义并且“没有触摸”,如果没有。就像我说的,这是一个简单的点击/点击事件的方法。

#25


0  

I am trying this and so far it works (but I am only on Android/Phonegap so caveat emptor)

我正在尝试这个功能,到目前为止它还能工作(但我只在Android/Phonegap上工作,所以买者请小心)

  function filterEvent( ob, ev ) {
      if (ev.type == "touchstart") {
          ob.off('click').on('click', function(e){ e.preventDefault(); });
      }
  }
  $('#keypad').on('touchstart click', '.number, .dot', function(event) {
      filterEvent( $('#keypad'), event );
      console.log( event.type );  // debugging only
           ... finish handling touch events...
  }

I don't like the fact that I am re-binding handlers on every touch, but all things considered touches don't happen very often (in computer time!)

我不喜欢在每次触摸时都重新绑定处理程序,但是所有被考虑到的触摸都不会经常发生(在计算机时代!)

I have a TON of handlers like the one for '#keypad' so having a simple function that lets me deal with the problem without too much code is why I went this way.

我有很多处理程序,比如“#keypad”,所以有一个简单的函数可以让我在不需要太多代码的情况下处理问题,这就是我为什么要这样做的原因。

#26


0  

Being for me the best answer the one given by Mottie, I'm just trying to do his code more reusable, so it's my contribution:

对我来说,最好的答案是,我只是想让他的代码更可重复使用,这是我的贡献:

bindBtn ("#loginbutton",loginAction);

function bindBtn(element,action){

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

#27


0  

Try to use Virtual Mouse (vmouse) Bindings from jQuery Mobile. It's virtual event especially for your case:

尝试使用来自jQuery Mobile的虚拟鼠标(vmouse)绑定。这是虚拟的事件,特别是对于你的情况:

$thing.on('vclick', function(event){ ... });

http://api.jquerymobile.com/vclick/

http://api.jquerymobile.com/vclick/

Browser support list: http://jquerymobile.com/browser-support/1.4/

浏览器支持列表:http://jquerymobile.com/browser-support/1.4/

#28


0  

EDIT: My former answer (based on answers in this thread) was not the way to go for me. I wanted a sub-menu to expand on mouse enter or touch click and to collapse on mouse leave or another touch click. Since mouse events normally are being fired after touch events, it was kind of tricky to write event listeners that support both touchscreen and mouse input at the same time.

编辑:我以前的答案(基于这个帖子的答案)对我来说不太合适。我想要一个子菜单来扩展鼠标的输入或触摸点击并在鼠标离开或另一个触摸点击时崩溃。由于鼠标事件通常是在触摸事件之后触发的,因此编写同时支持触摸屏和鼠标输入的事件监听器有点棘手。

jQuery plugin: Touch Or Mouse

I ended up writing a jQuery plugin called "Touch Or Mouse" (897 bytes minified) that can detect whether an event was invoked by a touchscreen or mouse (without testing for touch support!). This enables the support of both touchscreen and mouse at the same time and completely separate their events.

我最后编写了一个名为“Touch Or Mouse”的jQuery插件(897字节缩小),它可以检测一个事件是被触摸屏还是鼠标调用(不需要测试触摸支持!)这可以同时支持触摸屏和鼠标,并完全分离它们的事件。

This way the OP can use touchstart or touchend for quickly responding to touch clicks and click for clicks invoked only by a mouse.

这样,OP可以使用touchstart或touchend快速响应触摸单击,并单击仅由鼠标调用的单击。

Demonstration

First one has to make ie. the body element track touch events:

首先要做ie。body元素跟踪触摸事件:

$(document.body).touchOrMouse('init');

Mouse events our bound to elements in the default way and by calling $body.touchOrMouse('get', e) we can find out whether the event was invoked by a touchscreen or mouse.

鼠标以默认方式并通过调用$body来事件我们对元素的绑定。touchOrMouse('get', e)我们可以发现事件是由触摸屏还是鼠标调用的。

$('.link').click(function(e) {
  var touchOrMouse = $(document.body).touchOrMouse('get', e);

  if (touchOrMouse === 'touch') {
    // Handle touch click.
  }
  else if (touchOrMouse === 'mouse') {
    // Handle mouse click.
  }
}

See the plugin at work at http://jsfiddle.net/lmeurs/uo4069nh.

请参见http://jsfiddle.net/lmeurs/uo4069nh的插件。

Explanation

  1. This plugin needs to be called on ie. the body element to track touchstart and touchend events, this way the touchend event does not have to be fired on the trigger element (ie. a link or button). Between these two touch events this plugin considers any mouse event to be invoked by touch.
  2. 这个插件需要在ie上调用。跟踪touchstart和touchend事件的body元素,这样touchend事件就不必在触发器元素(即触发器)上触发。一个链接或按钮)。在这两个触摸事件之间,这个插件考虑任何鼠标事件被触摸调用。
  3. Mouse events are fired only after touchend, when a mouse event is being fired within the ghostEventDelay (option, 1000ms by default) after touchend, this plugin considers the mouse event to be invoked by touch.
  4. 鼠标事件是在touchend之后才被触发的,当一个鼠标事件被触发后,在ghostEventDelay(默认值是1000ms)中被触发后,这个插件会考虑通过触摸来调用鼠标事件。
  5. When clicking on an element using a touchscreen, the element gains the :active state. The mouseleave event is only fired after the element loses this state by ie. clicking on another element. Since this could be seconds (or minutes!) after the mouseenter event has been fired, this plugin keeps track of an element's last mouseenter event: if the last mouseenter event was invoked by touch, the following mouseleave event is also considered to be invoked by touch.
  6. 当使用触摸屏单击元素时,元素将获得:active状态。mouseleave事件只有在元素失去ie的状态后才被触发。点击另一个元素。由于这可能是在触发mouseenter事件之后的几秒钟(或者几分钟!),所以这个插件跟踪一个元素的最后一个mouseenter事件:如果最后一个mouseenter事件是通过touch调用的,那么下面的mouseleave事件也被认为是通过touch调用的。

#29


0  

Here's a simple way to do it:

这里有一个简单的方法:

// A very simple fast click implementation
$thing.on('click touchstart', function(e) {
  if (!$(document).data('trigger')) $(document).data('trigger', e.type);
  if (e.type===$(document).data('trigger')) {
    // Do your stuff here
  }
});

You basically save the first event type that is triggered to the 'trigger' property in jQuery's data object that is attached to the root document, and only execute when the event type is equal to the value in 'trigger'. On touch devices, the event chain would likely be 'touchstart' followed by 'click'; however, the 'click' handler won't be executed because "click" doesn't match the initial event type saved in 'trigger' ("touchstart").

基本上,您将第一个事件类型保存在jQuery数据对象中的“触发器”属性中,该属性附加到根文档,并且只在事件类型等于“触发器”中的值时执行。在触控设备上,事件链可能是“touchstart”,然后是“click”;但是,“单击”处理程序不会执行,因为“单击”与保存在“触发器”(“touchstart”)中的初始事件类型不匹配。

The assumption, and I do believe it's a safe one, is that your smartphone won't spontaneously change from a touch device to a mouse device or else the tap won't ever register because the 'trigger' event type is only saved once per page load and "click" would never match "touchstart".

我认为这是一个安全的假设,因为你的智能手机不会自动从触控设备变成鼠标设备,或者是不会自动注册,因为“触发”事件类型只会在每次页面加载时保存一次,而“点击”永远不会匹配“touchstart”。

Here's a codepen you can play around with (try tapping on the button on a touch device -- there should be no click delay): http://codepen.io/thdoan/pen/xVVrOZ

这是一个你可以玩的codepen(试着点击触摸设备上的按钮——不应该有点击延迟):http://codepen.io/thdoan/pen/xVVrOZ。

I also implemented this as a simple jQuery plugin that also supports jQuery's descendants filtering by passing a selector string:

我还实现了一个简单的jQuery插件,它通过传递一个选择器字符串来支持jQuery的后代过滤:

// A very simple fast click plugin
// Syntax: .fastClick([selector,] handler)
$.fn.fastClick = function(arg1, arg2) {
  var selector, handler;
  switch (typeof arg1) {
    case 'function':
      selector = null;
      handler = arg1;
      break;
    case 'string':
      selector = arg1;
      if (typeof arg2==='function') handler = arg2;
      else return;
      break;
    default:
      return;
  }
  this.on('click touchstart', selector, function(e) {
    if (!$(document).data('trigger')) $(document).data('trigger', e.type);
    if (e.type===$(document).data('trigger')) handler.apply(this, arguments);
  });
};

Codepen: http://codepen.io/thdoan/pen/GZrBdo/

Codepen:http://codepen.io/thdoan/pen/GZrBdo/

#30


0  

The best method I have found is to write the touch event and have that event call the normal click event programatically. This way you have all your normal click events and then you need to add just one event handler for all touch events. For every node you want to make touchable, just add the "touchable" class to it to invoke the touch handler. With Jquery it works like so with some logic to make sure its a real touch event and not a false positive.

我发现的最好的方法是编写触摸事件,并让该事件按程序调用常规单击事件。这样,您就有了所有的常规单击事件,然后需要为所有的touch事件添加一个事件处理程序。对于每个想要创建touchable的节点,只需向其添加“touchable”类来调用touch处理程序。使用Jquery,它的工作原理是这样的,并带有一些逻辑,以确保它是一个真正的触摸事件,而不是一个错误的正数。

$("body").on("touchstart", ".touchable", function() { //make touchable  items fire like a click event
var d1 = new Date();
var n1 = d1.getTime();
setTimeout(function() {
    $(".touchable").on("touchend", function(event) {
        var d2 = new Date();
        var n2 = d2.getTime();
        if (n2 - n1 <= 300) {
            $(event.target).trigger("click"); //dont do the action here just call real click handler
        }
    });
}, 50)}).on("click", "#myelement", function() {
//all the behavior i originally wanted
});