it-swarm.com.de

JavaScript Touchend vs. Click-Dilemma

Ich arbeite an einer Javascript-Benutzeroberfläche und verwende viele Touch-Events wie 'touchend', um die Reaktion auf Touch-Geräten zu verbessern. Es gibt jedoch einige logische Probleme, die mich stören ...

Ich habe gesehen, dass viele Entwickler in derselben Veranstaltung "Touchend" und "Click" mischen. In vielen Fällen wird es nicht schaden, aber im Wesentlichen würde die Funktion auf Berührungsgeräten zweimal ausgelöst:

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

Es wurde vorgeschlagen, dass man die Berührungsfähigkeit erkennen und das Ereignis entsprechend einstellen kann, zum Beispiel:

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

Das Problem mit dem oben genannten ist, dass es auf Geräten kaputt geht, die sowohl Berührung als auch Maus unterstützen. Wenn der Benutzer derzeit auf einem Gerät mit zwei Eingängen die Maus verwendet, wird der "Klick" nicht ausgelöst, da der Schaltfläche nur "Touchend" zugewiesen ist.

Eine andere Lösung besteht darin, das Gerät (z. B. "iOS") zu erkennen und darauf basierend ein Ereignis zuzuordnen: Klicken Sie auf ein Ereignis, das zweimal am Touchend im iPad aufgerufen wird. . Die Lösung im obigen Link ist natürlich nur für iOS (nicht Android oder andere Geräte) und scheint eher ein "Hack" zu sein, um etwas ganz Grundsätzliches zu lösen.

Eine andere Lösung wäre, die Mausbewegung zu erkennen und diese mit der Touch-Fähigkeit zu kombinieren, um herauszufinden, ob sich der Benutzer mit der Maus oder Berührung befindet. Das Problem ist natürlich, dass der Benutzer die Maus möglicherweise nicht bewegt, wenn Sie sie erkennen möchten ...

Die zuverlässigste Lösung, die ich mir vorstellen kann, ist die Verwendung einer einfachen debounce - Funktion, um sicherzustellen, dass die Funktion nur einmal innerhalb eines kurzen Intervalls (z. B. 100 ms) ausgelöst wird:

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

Fehlt mir etwas oder hat jemand bessere Vorschläge?

Edit: Ich habe diesen Link nach meinem Beitrag gefunden, der eine ähnliche Lösung wie die oben aufgeführte vorschlägt: Wie binden Sie 'touchstart'- und' click'-Ereignisse, reagieren jedoch nicht auf beide?

40
suncat100

Nach einem Recherchetag dachte ich mir, die beste Lösung wäre, einfach bei click zu bleiben und https://github.com/ftlabs/fastclick zu verwenden, um die Berührungsverzögerung zu entfernen. Ich bin nicht zu 100% sicher, dass dies so effizient ist wie touchend, aber nicht weit davon entfernt.

Ich habe einen Weg gefunden, um das Auslösen von Ereignissen bei Berührung zweimal zu deaktivieren, indem stopPropagation und preventDefault verwendet werden. Dies ist jedoch zwielichtig, da andere Berührungsgesten je nach Element, auf das sie angewendet werden, beeinträchtigt werden können:

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

Ich habe tatsächlich nach einer Lösung gesucht, um touchstart für einige Elemente der Benutzeroberfläche zu kombinieren, aber ich kann nicht erkennen, wie diese Option mit click kombiniert werden kann.

29
suncat100

Diese Frage wurde beantwortet, muss aber möglicherweise aktualisiert werden.

Laut einer Mitteilung von Google wird es keine Verzögerung von 300-350 ms mehr geben, wenn wir die folgende Zeile in das <head>-Element einfügen.

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

Das ist es! Und es gibt keinen Unterschied mehr zwischen Klick- und Touch-Event!

5
user3347402

Ja, das Deaktivieren des Doppeltippen-Zooms (und damit der Klickverzögerung) ist normalerweise die beste Option. Und wir haben endlich einen guten Rat dazu, der bald auf allen Browsern funktioniert.

Wenn Sie aus irgendeinem Grund das nicht tun möchten. Sie können auch UIEvent.sourceCapabilities.firesTouchEvents verwenden, um die redundante click explizit zu ignorieren. Das Polyfill for this hat eine ähnliche Funktion wie Ihr Entprellcode.

0
Rick Byers

Ihre debounce-Funktion verzögert die Bearbeitung jedes Klicks um 100 ms:

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

Stattdessen habe ich eine cancelDuplicates-Funktion erstellt, die sofort ausgelöst wird. Nachfolgende Aufrufe innerhalb von 10 ms werden jedoch abgebrochen:

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

Verwendungszweck:

button.on('click touchend', cancelDuplicates(function(event) {
  // This fires right away, and calls within 10 ms after are cancelled.
}));
0
Web_Designer

Hallo, du kannst den folgenden Weg implementieren.

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
David