jQuery 绑定“touchstart”和“click”时防止幽灵点击

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20225153/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 01:03:18  来源:igfitidea点击:

Preventing ghost click when binding 'touchstart' and 'click'

jquerymobile

提问by willdanceforfun

I'm developing an app, testing on my desktop and mobile. I am trying to fix these slow button presses on the mobile, and just learned about the difference between touchstart and click.

我正在开发一个应用程序,在我的桌面和移动设备上进行测试。我正在尝试修复移动设备上这些缓慢的按钮按下问题,并且刚刚了解了 touchstart 和 click 之间的区别。

So I bound my buttons with jquery to perform both touchstart and click like so:

所以我用 jquery 绑定了我的按钮来执行 touchstart 和 click 像这样:

$('.button').on('touchstart click', function(){
});

Now the app is performing slightly better on the phone. However, it is performing a touch click, and then a regular click, ie potentially double clicks, or when the next slide comes in, it clicks on something there. In my case a form is appearing, and the input field that appears in the space where the button clicked was, is selected. Ghost click.

现在该应用程序在手机上的表现稍好一些。但是,它正在执行触摸点击,然后是常规点击,即可能的双击,或者当下一张幻灯片出现时,它点击那里的某些东西。在我的情况下,出现了一个表单,并且选择了出现在单击按钮的空间中的输入字段。幽灵点击。

How can I tell my function that if there is a touch, ignore the click?

我如何告诉我的函数,如果有触摸,忽略点击?

Or better yet, is there a way to tell jquery to just acknowledge all 'clicks' as touches?

或者更好的是,有没有办法告诉 jquery 将所有“点击”确认为触摸?

I would remove the 'click' binding, but then I can't exactly test in my desktop environment so easily.

我会删除“点击”绑定,但是我无法在我的桌面环境中如此轻松地进行测试。

回答by Krishna

If you want to do specific stuff for different event types use e.type

如果你想为不同的事件类型做特定的事情,请使用 e.type

$('.button').on('touchstart click', function(e) {    
    e.preventDefault(); //prevent default behavior
    if(e.type == "touchstart") {
        // Handle touchstart event.
    } else if(e.type == "click") {
        // Handle click event.
    }
});

回答by Slashback

Touchstart should happen before click, so I remove the click handler if the event is of type touchstart. This seems to be working nicely for my purposes:

Touchstart 应该在点击之前发生,所以如果事件是 touchstart 类型,我会删除点击处理程序。这似乎对我的目的很有效:

$('.do-popdown').on('click touchstart', handlePopdown);
function handlePopdown(e){
    if(e.type == 'touchstart') {
        $('.do-popdown').off('click', handlePopdown).click(function(e){
            // do nothing
            e.stopPropagation();
            e.preventDefault();
            return false;
        });
    }
    // do my handling...
    // and nothing else:
    e.stopPropagation();
    e.preventDefault();
    return false;
}

The e.stopPropagation(); e.preventDefault(); return false;may be overkill, but I use this on a variety of different elements (<a>, <div>, <span>, <button>, &c.) and this meets my usual needs.

e.stopPropagation(); e.preventDefault(); return false;可能有点矫枉过正,但我​​在各种不同的元素(<a>, <div>, <span>, <button>, &c.)上使用它,这满足了我通常的需求。

EDIT:A more general (better?) approach is to create something similar to the familiar .click()event binder:

编辑:更通用(更好?)的方法是创建类似于熟悉的.click()事件绑定器的东西:

jQuery.fn.extend({
    clickOrTouch: function(handler) {
        return this.each(function() {
            var event = ('ontouchstart' in document) ? 'touchstart' : 'click';
            $(this).on(event, handler);
        });
    }
});

This way, only the appropriate event is attached to the selected element(s).

这样,只有适当的事件会附加到所选元素。

I suppose a more "proper" name would be .touchstartOrClick()but since it is more or less a replacement for .click()I decided to start the name with click.

我想一个更“合适”的名字会是,.touchstartOrClick()但因为它或多或少是.click()我决定以click.

This can be used just like .click(). For example, put a buttoninside of a divand run:

这可以像.click(). 例如,在 abutton里面放一个div并运行:

$('button').clickOrTouch(doSomething);
$('div').clickOrTouch(doSomething);
function doSomething(e) {
    $('body').append(this.tagName + ' ' + e.type + '<br>');
    e.stopPropagation();
}

This will show "DIV click" or "BUTTON touchstart" depending on how it is triggered. If this is used on a link, add e.preventDefault()if needed in your handler.

这将根据触发方式显示“DIV click”或“BUTTON touchstart”。如果在链接上使用它,请e.preventDefault()在处理程序中根据需要添加。

回答by reigngel

This code from @Krishna doesn't work for me:

来自@Krishna 的这段代码对我不起作用:

$('.button').on('touchstart click', function(e) {    
    e.stopPropagation(); //stops propagation
    if(e.type == "touchstart") {
        // Handle touchstart event.
    } else if(e.type == "click") {
        // Handle click event.
    }
});

But this one should work, as @Slashback originally suggested.

但正如@Slashback 最初建议的那样,这个应该有效。

$('.button').on('touchstart click', function(e) {    
    e.preventDefault();

    if(e.type == "touchstart") {
        // Handle touchstart event.
    } else if(e.type == "click") {
        // Handle click event.
    }
});

.preventDefault() alone worked for me instead of .stopPropagation(). I din't have to do the overkill as well.

.preventDefault() 单独为我工作,而不是 .stopPropagation()。我也不必做矫枉过正。

回答by sunflower zhang

I'm using PhoneGap. This maybe helpful:

我正在使用PhoneGap。这可能有帮助:

function longTapEvent(id, longTapFun) {
    $(id).click(function() {
        longTapFun();
        return;
    })

    $(id).unbind("touchstart");
    $(id).bind("touchstart", function() {
        //do sth...
    });
    $(id).unbind("touchend");
    $(id).bind("touchend", function() {
        //do sth...
    });
}

回答by CheeseFrog

You can detect click and escape the current firing of the function if the previous fire was not a click (i.e. was a touch or something else) - in vanilla js:

如果前一次触发不是点击(即触摸或其他东西),您可以检测点击并退出函数的当前触发 - 在 vanilla js 中:

buttonx.addEventListener('touchend',clicktap);
buttonx.addEventListener('click',clicktap);

function clicktap(e) {
var c = e.type.includes("click"); // or "mouse" if using "mousedown"
if (c && (this.wastouched)) return this.wastouched = 0;
this.wastouched = !c;

// ..run things..

}

回答by decoder7283

This is my own home brewed solution, please critique the hell out of it! thanks!

这是我自己自制的解决方案,请批评它!谢谢!

Basically, if you click the price button, the item is immediately added to cart.

基本上,如果您单击价格按钮,该商品会立即添加到购物车中。

If you tap/touchpress the button, it shows the price. Tap/touchpress it the second time, item is added to cart.

如果您点击/触摸按钮,它会显示价格。第二次点击/触摸它,项目被添加到购物车。

See it in action here: https://www.indospace.io/studio-city/urban-treez

在这里查看它的实际效果:https: //www.indospace.io/studio-city/urban-treez

    var price_button = $(evt.target).closest('.price-button')
    if(price_button.length) {
        price_button.on('mouseleave', function() {
            $(this).removeAttr('data-touched')
        })
        if(evt.type == 'touchstart') {
            jQuery.touch_start = true
            if(!price_button.attr('data-touched')) {
                price_button.attr('data-touched', 1)
                return
            }
            price_button.attr('data-touched', 2)
        }
        if(evt.type == 'click') {
            if(price_button.attr('data-touched'))
                return
        }
        bag.add(price_button)
        return true
    }

回答by Roumelis George

I use the following in my projects:

我在我的项目中使用以下内容:

$('.button').on('touchstart', function() {

   var thisButton = $(this); 
   if(!thisButton.hasClass('disabled')) {
     thisButton.addClass('disabled'); //add class disabled to prevent double execution

     ............rest of code

     window.setTimeout(function () {
        thisButton.removeClass('disabled'); //remove class disalbed after 300ms
     }, 300);

});

I hope this will help someone.

我希望这会帮助某人。

回答by Ananda Naphade

Use of data-tap-disabled="true" on element solve my problem.

在元素上使用 data-tap-disabled="true" 解决了我的问题。

http://ionicframework.com/docs/api/page/tap/

http://ionicframework.com/docs/api/page/tap/