wake-up-neo.net

behandeln sowohl Maus- als auch Touch-Ereignisse auf Touchscreens

Ich schreibe eine Webanwendung, die Maus- und Berührungsinteraktionen unterstützen sollte. Zum Testen verwende ich ein Touchscreen-Gerät mit Windows 7. Ich habe versucht, Berührungsereignisse in neuesten Firefox- und Chrome-Kanarien zu schnüffeln und erhielt die folgenden Ergebnisse :

Bei Berührung löst Firefox Berührung und entsprechendes Mausereignis aus. Chrome feuert touchstart/mousedown, touchend/mouseup Paare ab, aber mousemove wird auf sehr seltsame Weise ausgelöst: ein/zwei Mal während touchmove.

Alle Mausereignisse werden wie immer behandelt.

Gibt es eine Möglichkeit, auf modernen Touchscreens gleichzeitig mit Maus und Berührungsabgleich zu arbeiten? Wenn Firefox ein Paar Berührungs- und Mausereignisse auslöst, was passiert bei touchmove mit mousemove in Chrome? Soll ich alle Mausereignisse in Berührung übersetzen oder umgekehrt? Ich hoffe, einen richtigen Weg zu finden, um eine responsive Schnittstelle zu erstellen.

11
johnny

Sie sollten eher die Verfügbarkeit der Touch-Oberfläche prüfen und Ereignisse entsprechend binden.

Sie können so etwas tun:

(function () {
    if ('ontouchstart' in window) {
        window.Evt = {
            Push : 'touchstart',
            MOVE : 'touchmove',
            RELEASE : 'touchend'
        };
    } else {
        window.Evt = {
            Push : 'mousedown',
            MOVE : 'mousemove',
            RELEASE : 'mouseup'
        };
    }
}());

// and then...

document.getElementById('mydiv').addEventListener(Evt.Push, myStartDragHandler, false);

Wenn Sie beide Ereignisse gleichzeitig verarbeiten möchten und der Browser Touch-Ereignisse nicht in Mausereignisse umsetzt, können Sie Touch-Ereignisse abfangen und stoppen - dann sollte das entsprechende Mausereignis nicht vom Browser ausgelöst werden (Sie haben keine doppelten Ereignisse). und Sie können es selbst als Mausereignis auslösen oder einfach damit umgehen.

var mydiv = document.getElementsById('mydiv');
mydiv.addEventListener('mousemove', myMoveHandler, false);
mydiv.addEventListener('touchmove', function (e) {
    // stop touch event
    e.stopPropagation();
    e.preventDefault();

    // translate to mouse event
    var clkEvt = document.createEvent('MouseEvent');
    clkEvt.initMouseEvent('mousemove', true, true, window, e.detail, 
                 e.touches[0].screenX, e.touches[0].screenY, 
                 e.touches[0].clientX, e.touches[0].clientY, 
                 false, false, false, false, 
                 0, null);
    mydiv.dispatchEvent(clkEvt);

    // or just handle touch event
    myMoveHandler(e);
}, false);
6
lupatus

Sie können im Voraus nicht wirklich vorhersagen, auf welche Ereignisse Sie hören möchten (z. B. kann ein USB-Touchscreen nach dem Laden Ihrer Seite angeschlossen werden).

Stattdessen sollten Sie immer sowohl die Berührungsereignisse als auch die Mausereignisse abhören. Rufen Sie jedoch für die von Ihnen behandelten Berührungsereignisse den Befehl reflectDefault () auf, um zu verhindern, dass (jetzt redundante) Mausereignisse für sie ausgelöst werden. Siehe http://www.html5rocks.com/de/mobile/touchandmouse/ für Einzelheiten.

14
Rick Byers

MouseEvents und TouchEvents bieten technisch nicht exakt die gleiche Funktionalität, können jedoch für die meisten Zwecke austauschbar verwendet werden. Diese Lösung zieht keine Vorteile gegenüber, da der Benutzer sowohl eine Maus als auch einen Touchscreen besitzt. Stattdessen kann der Benutzer jedes beliebige Eingabegerät verwenden, solange er mindestens fünf Sekunden wartet, bevor er die Eingabe ändert. Diese Lösung ignoriert die Mauszeiger-Emulation auf Touchscreen-Geräten, wenn der Bildschirm berührt wird. 

var lastEvent = 3  ;
var MOUSE_EVENT = 1;
var TOUCH_EVENT = 2 ; 
 

element.addEventListener('touchstart', function(event)
		{
			 
			if (lastEvent === MOUSE_EVENT  )
			{
				var time =  Date.now() - eventTime  ;  
				if ( time > 5000 ) 
				{
					eventTime = Date.now() ;
					lastEvent = TOUCH_EVENT ;
					interactionStart(event) ;
				} 
			}
			else 
			{
				lastEvent = TOUCH_EVENT ; ;
				eventTime = Date.now() ;
				interactionStart(event)  ; 
			}
			 
		}) ;	

		element.addEventListener('mousedown',	function(event)
		{
			
			if (lastEvent === TOUCH_EVENT  )
			{
				var time =  Date.now() - eventTime  ;	
				if ( time > 5000 ) 
				{
					eventTime = Date.now() ;
					lastEvent = MOUSE_EVENT ;
					interactionStart(event) ;
				} 
			}
			else 
			{
				lastEvent=  MOUSE_EVENT ; 
				eventTime = Date.now() ;
				interactionStart(event)  ; 
			}
		}) ;  

function interactionStart(event) // handle interaction (touch or click ) here.
{...}

Dies ist keinesfalls eine Lösung, die ich gewinnen kann. Ich habe dies einige Male verwendet und habe keine Probleme damit gefunden, aber um fair zu sein, benutze ich sie normalerweise nur, um eine Animation zu starten, wenn eine Leinwand darauf klopft, oder um Logik zum Drehen bereitzustellen ein div in einen button. Ich überlasse es Ihnen allen, diesen Code zu verwenden, Verbesserungen zu finden und diesen Code zu verbessern (falls Sie keine bessere Lösung finden). 

1
FutureSci

Ich habe diesen Thread gefunden, weil ich ein ähnliches und komplexeres Problem habe:

angenommen, wir erstellen einen js-fähigen, scrollbaren Bereich mit Pfeilen NEXT/PREVIOUS, der nicht nur auf Berührungs- und Mausereignisse reagieren soll, sondern auch wiederholt ausgelöst werden soll, während der Benutzer weiterhin den Bildschirm drückt oder seine/ihre Maus gedrückt hält!

Eine Wiederholung von Ereignissen würde meinen nächsten Button dazu bringen, um 2 Positionen statt um eine vorzurücken!

Mit Hilfe von Verschlüssen scheint alles möglich:

(1) Erstellen Sie zuerst eine selbstaufrufende Funktion zur Variablenisolation:

 (function(myScroll, $, window, document, undefined){
 ...
 }(window.myScroll = window.myScroll || {}, jQuery, window, document));

(2) Fügen Sie dann Ihre privaten Variablen hinzu, die den internen Status von setTimeout() enthalten:

/*
 * Primary events for handlers that respond to more than one event and devices  
 * that produce more than one, like touch devices.
 * The first event in browser's queue hinders all subsequent for the specific 
 * key intended to be used by a handler.
 * Every key points to an object '{primary: <event type>}'.
 */
var eventLock = {};
// Process ids based on keys.
var pids = {};
// Some defaults
var defaults = {
   pressDelay: 100 // ms between successive calls for continuous press by mouse or touch
}

(3) Die Ereignissperre funktioniert:

function getEventLock(evt, key){
   if(typeof(eventLock[key]) == 'undefined'){
      eventLock[key] = {};
      eventLock[key].primary = evt.type;
      return true;
   }
   if(evt.type == eventLock[key].primary)
      return true;
   else
      return false;
}
function primaryEventLock(evt, key){
   eventLock[key].primary = evt.type;
}

(4) Fügen Sie Ihre Event-Handler hinzu:

function init(){
   $('sth').off('mousedown touchstart', previousStart).on('mousedown touchstart', previousStart);
   $('sth').off('mouseup touchend', previousEnd).on('mouseup touchend', previousEnd);
   // similar for 'next*' handlers
}

Das Auslösen von Ereignissen mousedown und touchstart führt zu doppelten Aufrufen für Handler auf Geräten, die beide unterstützen (wahrscheinlich Berührungsauslöser zuerst). Gleiches gilt für mouseup und touchend.

Wir wissen, dass Eingabegeräte (eigentlich ganze Grafikumgebungen) Ereignisse sequentiell erzeugen, so dass es uns egal ist, welches zuerst ausgelöst wird, wenn ein special key auf private eventLock.next.primary und eventLock.previous.primary für die ersten von den Handlern next*() und erfassten Ereignisse gesetzt wird previous*().

Der Schlüssel ist der Ereignistyp, so dass das zweite, dritte usw. Ereignis immer Verlierer sind. Sie erwerben die Sperre nicht mithilfe der Sperrfunktionen eventLock() und primaryEventLock().

(5) Das Obige ist bei der Definition der Event-Handler zu sehen:

function previousStart(evt){
   // 'race' condition/repetition between 'mousedown' and 'touchstart'
   if(!getEventLock(evt, 'previous'))
      return;

   // a. !!!you have to implement this!!!
   previous(evt.target);

   // b. emulate successive events of this type
   pids.previous = setTimeout(closure, defaults.pressDelay);

   // internal function repeats steps (a), (b)
   function closure(){
      previous(evt.target);
      primaryEventLock(evt, 'previous');
      pids.previous = setTimeout(closure, defaults.pressDelay);
   }
};
function previousEnd(evt){
      clearTimeout(pids.previous);
};

Ähnlich für nextStart und nextEnd.

Die Idee ist, dass derjenige, der nach dem ersten kommt (Berührung oder Maus), kein lock mit Hilfe von function eventLock(evt, key) erwirbt und dort stoppt.

Die einzige Möglichkeit, diese Sperre zu öffnen, ist das Auslösen der terminierung Ereignis-Handler *End() in Schritt (4): previousEnd und nextEnd.

Das Problem von Touch-Geräten, die mitten in der Sitzung angeschlossen sind, gehe ich auf eine sehr kluge Art und Weise an: Ich habe festgestellt, dass ein kontinuierliches Drücken länger als defaults.pressDelay aufeinanderfolgende Aufrufe der Rückruffunktion only für das primäre Ereignis an diesem Tag erzeugt Zeit (der Grund ist, dass kein Endereignishandler das Callabck beendet)!

touchstart event
closure
closure
....
touchend event

Ich definiere primary das Gerät, das der Benutzer verwendet, also müssen Sie nur länger drücken, und sofort wird Ihr Gerät primary mit Hilfe von primaryEventLock(evt, 'previous') in der Schließung!

Beachten Sie auch, dass die Ausführungszeit von previous(event.target) kleiner als defaults.pressDelay sein sollte.

(6) Zum Schluss machen wir init() den globalen Gültigkeitsbereich aus:

myScroll.init = init;

Sie sollten den Aufruf von previous(event.target) durch das vorliegende Problem ersetzen: Geige .

Beachten Sie auch, dass bei (5b) eine andere häufig gestellte Frage gelöst wird. Wie übergeben wir Argumente an eine Funktion, die von setTimeout() aufgerufen wird, d. H. setTimeout(previous, defaults.pressDelay) ein Mechanismus für die Argumentübergabe fehlt.

0
centurian

Ich habe diesen jQuery-Helfer verwendet, um sowohl Touch- als auch Click-Events zu binden.

(function ($) {
$.fn.tclick = function (onclick) {
    this.bind("touchstart", function (e) { onclick.call(this, e); e.stopPropagation(); e.preventDefault(); });
    this.bind("click", function (e) { onclick.call(this, e); });   //substitute mousedown event for exact same result as touchstart         
    return this;
  };
})(jQuery);
0
Joshua