JavaScript touchend rapport sur dilemme

je travaille sur une interface JavaScript, et j'utilise beaucoup d'événements tactiles comme 'touchend' pour améliorer la réponse sur les appareils tactiles. Cependant, il y a quelques logiques de questions qui m'énerve ...

j'ai vu que beaucoup de développeurs mêlent 'touchend' et 'click' dans le même événement. Dans de nombreux cas, il ne fera pas de mal, mais essentiellement la fonction tirerait deux fois sur les dispositifs tactiles:

button.on('click touchend', function(event) {
  // this fires twice on touch devices
});

Il a été suggéré que l'on pouvait déceler possibilité de toucher, et régler l'événement de manière appropriée par exemple:

var myEvent = ('ontouchstart' in document.documentElement) ? 'touchend' : 'click';
button.on(myEvent, function(event) {
  // this fires only once regardless of device
});

le problème avec ce qui précède, c'est qu'il va casser sur les dispositifs qui supportent à la fois le toucher et la souris. Si l'utilisateur utilise actuellement la souris sur un périphérique à double entrée, le "clic" ne se déclenche pas car seul le "touchend" est assigné au bouton.

une autre solution consiste à détecter le dispositif (par exemple "iOS") et à assigner un événement basé sur ce qui suit:: cliquer événement appelé deux fois sur touchend de l'iPad . Bien sûr, la solution dans le lien ci-dessus est seulement pour iOS (Pas Android ou d'autres appareils), et semble plus comme un "hack" pour résoudre quelque chose tout à fait élémentaire.

une Autre solution serait de détecter la souris-mouvement, et les combiner avec des fonctionnalités tactiles de déterminer si l'utilisateur est sur la souris ou tactile. Problème bien sûr étant que l'utilisateur pourrait ne pas déplacer la souris à partir de quand vous voulez la détecter ...

le plus fiable la solution à laquelle je peux penser, est d'utiliser une fonction simple debounce pour simplement s'assurer que la fonction déclenche seulement une fois dans un court intervalle (par exemple 100ms):

button.on('click touchend', $.debounce(100, function(event) {
  // this fires only once on all devices
}));

ai-je raté quelque chose, ou quelqu'un a une meilleure suggestion?

Edit: j'ai trouvé ce lien après mon post, qui suggère une solution similaire à la ci-dessus: comment lier les événements' touchstart 'et' click' mais ne pas répondre à la fois?

37
demandé sur Community 2014-08-29 20:07:39

5 réponses

après une journée de recherche, j'ai pensé que la meilleure solution est de simplement s'en tenir à cliquez sur et utilisez https://github.com/ftlabs/fastclick pour supprimer le délai de contact. Je ne suis pas sûr à 100% que ce soit aussi efficace que touchend , mais pas loin d'au moins.

j'ai trouvé un moyen de désactiver les événements déclencheurs deux fois au contact en utilisant stopPropagation et preventDefault , mais c'est douteux car cela pourrait interférer avec d'autres gestes tactiles selon l'élément où il est appliqué:

button.on('touchend click', function(event) {
  event.stopPropagation();
  event.preventDefault();
  // this fires once on all devices
});

je cherchais en fait une solution pour combiner touchstart sur certains éléments D'UI, mais je ne vois pas comment cela peut être combiné avec click autre que la solution ci-dessus.

27
répondu suncat100 2017-05-19 01:27:56

cette question Est répondue mais peut-être doit-elle être mise à jour.

selon un avis de Google , il n'y aura plus de retard de 300-350ms si nous incluons la ligne ci-dessous dans l'élément <head> .

<meta name="viewport" content="width=device-width">

C'est ça! Et il n'y aura plus de différence entre l'événement click et touch!

5
répondu user3347402 2017-05-19 01:29:18

Oui désactiver le zoom double-clic (et donc le délai de clic) est généralement la meilleure option. Et nous avons enfin de bons conseils pour faire cela qui va bientôt travailler sur tous les navigateurs .

Si, pour une raison quelconque, vous ne voulez pas le faire. Vous pouvez également utiliser UIEvent.sourceCapabilities.firesTouchEvents pour ignorer explicitement le redondant click . Le polyfill pour ce fait quelque chose de similaire à votre code de dénonciation.

0
répondu Rick Byers 2016-01-04 17:02:44

Bonjour, vous pouvez mettre en œuvre la manière suivante.

function eventHandler(event, selector) {
    event.stopPropagation(); // Stop event bubbling.
    event.preventDefault(); // Prevent default behaviour
    if (event.type === 'touchend') selector.off('click'); // If event type was touch turn off clicks to prevent phantom clicks.
}

// Implement
$('.class').on('touchend click', function(event) {
    eventHandler(event, $(this)); // Handle the event.
    // Do somethings...
});
0
répondu David 2017-05-12 14:29:33

votre fonction debounce retarde le traitement de chaque clic pour 100 ms:

button.on('click touchend', $.debounce(100, function(event) {
  // this is delayed a minimum of 100 ms
}));

à la place, j'ai créé une fonction cancelDuplicates qui démarre tout de suite, mais tous les appels ultérieurs dans les 10 ms seront annulés:

function cancelDuplicates(fn, threshhold, scope) {
    if (typeof threshhold !== 'number') threshhold = 10;
    var last = 0;

    return function () {
        var now = +new Date;

        if (now >= last + threshhold) {
            last = now;
            fn.apply(scope || this, arguments);
        }
    };
}

Utilisation:

button.on('click touchend', cancelDuplicates(function(event) {
  // This fires right away, and calls within 10 ms after are cancelled.
}));
0
répondu Web_Designer 2017-05-19 03:03:30