Предотвращение призрачного щелчка при привязке "touchstart" и 'click'

Я разрабатываю приложение, тестируя свой рабочий стол и мобильный. Я пытаюсь исправить эти медленные нажатия кнопок на мобильном устройстве и только что узнал о различии между touchstart и щелчком.

Итак, я связал свои кнопки с jquery, чтобы выполнить оба touchstart и щелкнуть так:

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

Теперь приложение работает немного лучше на телефоне. Тем не менее, он выполняет сенсорный щелчок, а затем обычный клик, то есть потенциально двойной клик, или когда приходит следующий слайд, он нажимает на что-то там. В моем случае появляется форма, и поле ввода, которое появляется в пространстве, где была нажата кнопка, выбрано. Призрачный клик.

Как я могу сказать своей функции, что если есть прикосновение, игнорируйте клик?

Или еще лучше, есть ли способ сказать jquery просто признать все "клики" как прикосновения?

Я бы удалил привязку 'click', но тогда я не могу точно протестировать в своей среде рабочего стола так легко.

Ответ 1

Если вы хотите делать конкретные вещи для разных типов событий, используйте 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.
    }
});

Ответ 2

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;
}

e.stopPropagation(); e.preventDefault(); return false; может быть излишним, но я использую его для множества различных элементов (<a>, <div>, <span>, <button>, & c.), и это соответствует моим обычным потребностям.

EDIT:. Более общий (лучший?) подход - создать нечто похожее на знакомое связующее событие .click():

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

Таким образом, к выбранному элементу (элементам) прикрепляется только соответствующее событие.

Я предполагаю, что более "правильное" имя будет .touchstartOrClick(), но поскольку это более или менее замена для .click(), я решил начать имя с click.

Это можно использовать так же, как .click(). Например, поставьте button внутри div и запустите:

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

В зависимости от того, как он запускается, отобразится "DIV click" или "BUTTON touchstart". Если это используется для ссылки, добавьте e.preventDefault(), если это необходимо в обработчик.

Ответ 3

Этот код от @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.
    }
});

Но этот должен работать, как первоначально предлагал @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() работал только для меня, а не .stopPropagation(). Мне тоже не нужно делать переполнения.

Ответ 4

Я использую 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...
    });
}

Ответ 5

В моих проектах я использую следующее:

$('.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);

});

Надеюсь, это поможет кому-то.

Ответ 7

Вы можете обнаружить щелчок и избежать текущего срабатывания функции, если предыдущий огонь не был кликом (т.е. был прикосновением или чем-то еще) - в 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..

}

Ответ 8

Это мое собственное домашнее решение, пожалуйста, критикуйте его! Спасибо!

    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($(evt.target).closest('.price-button'))
        return true
    }