2010-05-23 2 views
34

einen einzelnen Seite Javascript App mit interaktiven DOM-Elementen Dabei habe ich festgestellt, dass der „mouseover-mousemove-mousedown-mouseup-click“ -Sequenz alle in einem Bündel geschieht nach die "touchstart-touchmove-touchend" Sequenz von Ereignissen. während des touchstart EreignissesVerhindern Mausemulation Ereignisse (zB Klick) von Touch-Ereignissen in Mobile Safari/iPhone mit Javascript

Ich habe auch festgestellt, dass es möglich ist, ein „event.preventDefault()“ die „mouse*-click“ Ereignisse zu verhindern, indem Sie tun, aber nur dann, und nicht während der touchmove und touchend. Dies ist ein seltsames Design, weil es nicht möglich ist, während der touchstart noch zu wissen, ob der Benutzer beabsichtigt, ziehen oder streichen oder einfach auf das Element tippen/klicken.

Ich landete eine "ignore_next_click" -Flag irgendwo an einen Zeitstempel gebunden, aber das ist offensichtlich nicht sehr sauber.

Kennt jemand einen besseren Weg, oder fehlt uns etwas?

Beachten Sie, dass, während ein „Klick“ kann als „touchstart-touchend“ -Sequenz (dh kein „touchmove“), gibt es bestimmte Dinge, wie zum Beispiel Tastatureingabefokus erkannt werden, die nur bei einem ordnungsgemäßen click Ereignisse passieren können.

+0

Ich interessiere mich für den iPad Safari Touch-Ereignisse auch, aber es ist mir nicht klar, welche konkreten Problem, das Sie versuchen zu lösen. Wenn Sie immer noch an diesem Problem arbeiten oder es gelöst haben, kümmern Sie sich darum, es auszuarbeiten. – Tim

+0

Ich möchte bestimmte Ereignisse wie Drag-and-Drop verarbeiten und auch "Klick" -Ereignisse verarbeiten können. Ich muss die "click" -Ereignisse als richtige "click" -Ereignisse behandeln (statt touchstart/touchend), da bestimmte Dinge wie der Tastatureingabefokus * nur * innerhalb eines Click-Event-Handlers aktiviert werden können. –

+0

Dieses Problem ist extrem ärgerlich und betrifft auch Android. –

Antwort

4

Ich habe ähnliche Probleme bei plattformübergreifenden HTML5/JS-Anwendungen festgestellt. Die einzige wirkliche Antwort für mich war preventDefault auf den Touch-Events, und tatsächlich verwalten die Touch-Zustände und Feuer klicken, zieht, etc. Ereignisse auf eigene Faust nach meiner Logik. Das hört sich viel entmutigender an, als es wirklich ist, aber die imitieren Click/Mouse-Ereignisse funktionieren perfekt auf den meisten mobilen Browsern.

Click und die zusätzliche Maus Sequenz sind alle da für Ihre Bequemlichkeit (und Kompatibilität). Meine Faustregel - wenn es für Ihre Bequemlichkeit ist, aber es ist unbequem, am besten töten Sie es.

Soweit die Eingabefelder, brauchen sie nur die Touchend-Ereignisse. Ich habe Klick-/Mausereignisse beendet und war immer noch in der Lage, mobile Browser korrekt auf Berührungen von Eingaben reagieren zu lassen. Wenn es immer noch hat man Probleme geben, können Sie die Ereignishandler nur supress Ereignisse auf Nicht-Eingänge ändern:

function touchHandler(event) { 
    var shouldIgnore = event.target != null 
      && (event.target.tagName.toLowerCase() == "input" || event.target.tagName.toLowerCase() == "textarea"); 

    if(!shouldIgnore) e.preventDefault(); 
} 
+0

Ich teste diese Lösung sowohl auf iOS5 als auch auf Android 2.2.1, und das Problem ist, dass, wenn ich Defect auf 'touchstart' verhindere, der' Klick' nicht ausgelöst wird, aber ich kann die Seite nicht scrollen. Wenn ichDefault auf 'touchend' verhindere, funktioniert es bei iOS (nur wenn der Tipp kurz ist) grat, aber feuert den' Klick' auf Android. Hast du das gleiche Problem bemerkt? Testen Sie es hier: http://jsfiddle.net/3TBVc/ –

+0

Ja, ich habe auf dieses Problem (manifestiert auf verschiedene Arten). Es scheint einer der größeren Schmerzen in iOS <-> Android Cross-Plattform zu sein. Es bedarf einiger Feinabstimmungen, aber durch das Aufheben der richtigen Dinge können Sie im Allgemeinen das gewünschte Ergebnis erzielen. http://jsfiddle.net/3TBVc/9/ Scheint gut für mich auf Android zu funktionieren. Die Eingabefelder können einige "Drag" -Ereignisse (auf Android) essen, aber es ist funktional. –

+0

Es klickt immer noch Klick-Ereignisse auf meinem Android-Gerät (und auch auf dem iPhone für die erste Schaltfläche). –

2

Ich habe eine Lösung selbst gemacht, da ich keine ausreichende Lösung an anderer Stelle gefunden haben:

var isTouch = ('ontouchstart' in window); 

    function kill(type){ 
    window.document.body.addEventListener(type, function(e){ 
     e.preventDefault(); 
     e.stopPropagation(); 
     return false; 
    }, true); 
    } 

    if(isTouch){ 
    kill('mousedown'); 
    kill('mouseup'); 
    kill('click'); 
    kill('mousemove'); 
    } 

Die Überprüfung von isTouch lässt Dinge wie normale Maus-Eingabegeräte arbeiten, aber die emulierten Ereignisse auf Safari/iOS. Der Trick besteht darin, useCapture = true in dem Aufruf anzu verwenden, so dass wir alle Mausereignisse auf der Seite abrufen, ohne den Code über die gesamte Webanwendung zu hacken. Lesen Sie die Dokumentation für die Funktion hier: https://developer.mozilla.org/en-US/docs/DOM/EventTarget.addEventListener?redirectlocale=en-US&redirectslug=DOM%2Felement.addEventListener

Edit:

Nun, da Bibliotheken zum Umgang mit diesem Problem besser sind, können Sie einfach so etwas wie Fastclick verwenden als Alternative (https://github.com/ftlabs/fastclick).

+4

Dies ist eine gute Lösung, wenn Sie wissen, dass es sich bei den Geräten um eine Touch- oder Mauseingabe handelt. Aber wenn Sie etwas wie ein Windows 8 Laptop/Tablet haben, müssen Sie etwas anderes tun. – psayre23

+0

Unsere Lösung bestand darin, sowohl auf Click- als auch auf Touchstart/Stop/Move-Ereignisse zu achten und das Klickereignis nur zu registrieren, wenn 'ontouchstart' nicht verfügbar war. Mobile Safari registriert sowohl Berührungs- als auch Klickereignisse, aber diese Methode registriert nur das Berührungsereignis in diesem Fall. Außerdem war es in Ordnung, ein mouse move-Ereignis zu ignorieren. –

+1

abgelehnt, weil die Frage Mausereignisse nicht vollständig deaktivieren sollte, wenn Berührungsereignisse verfügbar sind ... – iRaS

0

Creating Fast Buttons for Mobile Web Applications hat ihre Lösung für das Problem.

Beachten Sie auch, dass bei Verwendung von IE10 preventDefault() die Ghost/synthetischen/emulierten Mausereignisse nach einem MSPointerDown-Ereignis nicht stoppt, sodass eine echte Cross-Browser-Lösung schwieriger ist.

2

Wenn Sie Geräte zu unterstützen, die sowohl Maus und Touch-Unterstützung, eine andere Lösung ein Capture-Ereignis-Listener verwenden, die alle Mausereignisse hält, die entweder

  • innerhalb einer Verzögerung nach dem Berührungsereignis
  • auftreten
  • an der gleichen Position wie das Berührungsereignis
  • auf dem gleichen Zielelement wie das Berührungsereignis

die Informationen (Zeit, Position oder Zielelement) des Touch ev ent kann in einem anderen Capture-Ereignis-Listener aufgezeichnet werden.

0

Das Einpacken Ihres Mauscodes in eine Window.matchesMedia-Funktion ist die sauberste Methode, die ich gefunden habe.

if (window.matchMedia('(hover: hover), (any-hover: hover), (-moz-touch-enabled: 0)').matches) { 
    el.addEventListener('mouseover', ev => { 
     // mouse handler, no simulated hover 
    } 
} 

Dies funktioniert, um simulierte Schwebungen zu verhindern, wird aber wahrscheinlich auch simulierte Klicks verhindern.

Hinweis: -moz-Touch-fähigen Teil erforderlich auf Firefox ab Version 58.

Verwandte Themen