Wie kann man "Touchstart" - und "Klick" -Ereignisse binden, aber nicht auf beide reagieren?


198

Ich arbeite an einer mobilen Website, die auf einer Vielzahl von Geräten funktionieren muss. Die, die mir im Moment Kopfschmerzen bereiten, sind BlackBerry.

Wir müssen sowohl Tastaturklicks als auch Berührungsereignisse unterstützen.

Idealerweise würde ich nur verwenden:

$thing.click(function(){...})

Das Problem ist jedoch, dass einige dieser Blackberry-Geräte eine sehr ärgerliche Verzögerung vom Zeitpunkt der Berührung bis zum Auslösen eines Klicks aufweisen.

Das Mittel ist, stattdessen Touchstart zu verwenden:

$thing.bind('touchstart', function(event){...})

Aber wie gehe ich vor, um beide Ereignisse zu binden, aber nur eines auszulösen? Ich benötige das Klickereignis weiterhin für Tastaturgeräte, möchte aber natürlich nicht, dass das Klickereignis ausgelöst wird, wenn ich ein Touch-Gerät verwende.

Eine Bonusfrage: Gibt es überhaupt eine Möglichkeit, dies zu tun und zusätzlich Browser aufzunehmen, die nicht einmal ein Touchstart-Ereignis haben? Es sieht so aus, als ob BlackBerry OS5 Touchstart nicht unterstützt und sich daher auch auf Klickereignisse für diesen Browser verlassen muss.

NACHTRAG:

Vielleicht ist eine umfassendere Frage:

Ist es mit jQuery möglich / empfohlen, sowohl Berührungsinteraktionen als auch Mausinteraktionen mit denselben Bindungen zu behandeln?

Im Idealfall lautet die Antwort ja. Wenn nicht, habe ich einige Optionen:

1) Wir verwenden WURFL, um Geräteinformationen abzurufen und so unsere eigene Gerätematrix zu erstellen. Je nach Gerät verwenden wir Touchstart ODER Klicken.

2) Erkennen Sie die Touch-Unterstützung im Browser über JS (ich muss noch etwas darüber recherchieren, aber es scheint, dass dies machbar ist).

Damit bleibt jedoch noch ein Problem: Was ist mit Geräten, die BEIDE unterstützen? Einige der von uns unterstützten Telefone (nämlich Nokias und BlackBerries) verfügen sowohl über Touchscreens als auch über Tastaturen. Damit schließt sich der Kreis zurück zur ursprünglichen Frage ... gibt es eine Möglichkeit, beides irgendwie gleichzeitig zuzulassen?


2
Sie sind besser dran, sich an Touchstart und Touchend zu binden und Ihre eigene Klicklogik neben Ihre Touch-Logik zu schreiben. Der eingebaute Klick-Rückruf als keine Kenntnis von Berührungen.
Justin808

Ich bin mir nicht sicher, ob ich folge, Justin. Hätte ich nicht immer noch ein Touchstart- und ein Klickereignis daran gebunden?
DA.

@DA - nein, Sie würden sich überhaupt nicht an den .click () - Rückruf binden. Ich werde versuchen, eine Antwort in einen Sudo-Code zu schreiben. Ich habe kein Touch-Gerät zur
Hand

Ah, aber zur Klarstellung brauche ich noch Klickereignisse, da es Leute geben wird, die mit Nicht-Touch-Geräten auf diese Site zugreifen.
DA.

2
Verwenden .bind('touchstart mouseup')wird es lösen (basierend auf einem der Kommentare unten)
Oriadam

Antworten:


135

Update : Schauen Sie sich das jQuery Pointer Events Polyfill- Projekt an, mit dem Sie an "Zeiger" -Ereignisse binden können, anstatt zwischen Maus und Berührung zu wählen.


Binden Sie an beide, aber machen Sie ein Flag, damit die Funktion nur einmal pro 100 ms oder so ausgelöst wird.

var flag = false;
$thing.bind('touchstart click', function(){
  if (!flag) {
    flag = true;
    setTimeout(function(){ flag = false; }, 100);
    // do something
  }

  return false
});

7
hmm ... es fühlt sich hacky an, aber das könnte funktionieren. Der Haken ist, dass es bei einigen dieser Geräte eine merkliche Verzögerung gibt ... vielleicht fast eine Sekunde ..., die für andere auf einem schnelleren Gerät ärgerlich wäre.
DA.

15
Anstatt clickchange it to mousedown... zu verwenden, ist möglicherweise die lange Verzögerung der Unterschied zwischen mousedownund mouseupwie a clickbestimmt wird.
Mottie

7
Dies ist die Lösung, mit der ich mich entschieden habe. Vielen Dank! Ich kennzeichne ein Element, touchendindem ich eine Klasse von anwende touched. Dies wird ausgelöst, bevor das Klickereignis aufgerufen wird. Ich füge dann ein Klickereignis hinzu, das zuerst die Existenz dieser Klasse überprüft. Wenn es dort ist, nehmen wir an, dass die Berührungsereignisse ausgelöst wurden, und wir tun nichts anderes mit einem Klick, als den Klassennamen zu entfernen, um ihn für die nächste Interaktion zurückzusetzen. Wenn die Klasse nicht vorhanden ist, nehmen wir an, dass sie eine Tastatur verwendet haben, um auf das Element zu klicken und die Funktion von dort aus auszulösen.
DA.

7
Sie sollten sich bewusst sein, dass die meisten Telefonbrowser eine Verzögerung von 300 ms für das Klickereignis haben. Daher sollten Sie die Verzögerung auf mindestens 300 erhöhen. Weitere Informationen finden Sie in diesem Artikel zum Problem der Verzögerung von 300 ms . Dies dient im Wesentlichen dazu, die Funktion "Doppelklick zum Zoomen" zu aktivieren, die in den frühen iPhone-Tagen, als die meisten Websites für die Anzeige auf einem großen Desktop-Bildschirm konzipiert wurden, eine sehr wichtige Funktion war.
Ehrfurcht

12
Diese Frage wurde zu diesem Zeitpunkt fast 100.000 Mal angezeigt. Dies scheint ein außerordentlich häufiger Anwendungsfall / Problem zu sein. Diese und andere Antworten auf diese und ähnliche Fragen scheinen jedoch alle hackig zu sein. Die Google-Lösung ist zwar gründlicher durchdacht als die meisten anderen, scheint jedoch nur ein robusterer Hack zu sein. Für etwas so Einfaches wie einen Klick-Handler scheint die Lösung einfach zu sein. Hat niemand eine Non-Hack-Lösung für dieses Problem gefunden?
Jinglesthula

73

Dies ist das Update, das ich "erstelle" und das den GhostClick entfernt und den FastClick implementiert. Probieren Sie es selbst aus und lassen Sie uns wissen, ob es für Sie funktioniert hat.

$(document).on('touchstart click', '.myBtn', function(event){
        if(event.handled === false) return
        event.stopPropagation();
        event.preventDefault();
        event.handled = true;

        // Do your magic here

});

2
helgatheviking: jsbin.com/ijizat/25 Im JavaScript gibt es eine Funktion namens TouchClick, die die oben genannten Funktionen enthält.
Matt Parkins

5
Ich bevorzuge diese Methode aller Antworten auf diese Frage sehr, da sie a) nicht auf Gerätefunktionen testet und b) setTimeout nicht verwendet. Nach meiner Erfahrung funktionieren Lösungen für Probleme wie diese, die setTimeout verwenden, in den meisten Fällen, aber das Timing von Ereignissen ist ziemlich willkürlich und gerätespezifisch.
itsmequinn

7
Dies funktioniert nicht, da durch Übergeben von 'event' in der anonymen Funktion ein lokales Objekt innerhalb dieser Funktion wird, das event.handledbei undefinedjedem Auslösen des Ereignisses gleich ist. Hier ist eine Lösung: Setzen Sie das Flag 'behandelt' im Zielelement selbst mit jQuery.data().
Dooan

3
Sie haben event.stopPropagation();und event.preventDefault();nach meinem Verständnis (und Testen) kann das Ereignis nur einmal damit ausgelöst werden. Warum also überhaupt nachsehen if(event.handled !== true)? Für mich ist es nicht nötig oder vermisse ich etwas?
nbar

2
Sollte nicht event.handledauf den Wert überprüft werden true? Soweit ich das beurteilen kann, ist es nie false. Es beginnt als undefined, und dann möchten Sie feststellen, ob es eingestellt wurde true.
ACJ

49

Sie könnten so etwas versuchen:

var clickEventType=((document.ontouchstart!==null)?'click':'touchstart');
$("#mylink").bind(clickEventType, myClickHandler);

5
Ich denke, das Problem dabei ist, dass die Gerätefunktionen getestet werden und nicht, was der Benutzer tut, oder? Die Herausforderung besteht darin, Touch-Geräte zu unterstützen, die auch über Tastaturen verfügen (sodass beide verwendet werden können)
DA.

8
Dies ist keine gute Idee - wird das Ereignis für einen Benutzer mit einem Touchscreen und einer Maus bei Verwendung der Maus unterbrechen (Laptops mit Touchscreens werden immer häufiger verwendet).
Kristian J.

1
Ausgezeichneter Artikel zu diesem Thema
Luke Melia

Windows 8 verkabelt immer das 'touchstart'-Ereignis, wenn dies verwendet wird, da' ontouchstart 'für dieses Betriebssystem' true 'zurückgibt. Wahrscheinlich nicht die beste Antwort, es sei denn, Ihr Code wird nur auf echten Touchscreen-Geräten ausgeführt. Wenn dies jedoch der Fall ist, benötigen Sie die Überprüfung überhaupt nicht.
Neil Monroe

Auf Laptops mit Touchscreen kann der Benutzer mit diesem Code in Chrom (mindestens Chrom 46) auf nichts klicken. IE 11 scheint jedoch zu funktionieren.
David Sherret

42

Normalerweise funktioniert das auch:

$('#buttonId').on('touchstart click', function(e){
    e.stopPropagation(); e.preventDefault();
    //your code here

});

8
@ Jonathan falsch, wenn Sie neuere jQuery-Versionen verwenden. Live war in Version 1.7 veraltet.
Mike Barwick

Ich habe es auch mit e.stopPropagation () versucht (und ich habe es woanders gelesen - nicht meine Idee); e.preventDefault (); und es funktioniert (für mich) fast, aber ich habe später festgestellt, dass es tatsächlich 20 Mal wie vorhergesagt funktioniert, aber 1 Mal nicht, also ist es nicht kugelsicher. Schauen Sie hier: stackoverflow.com/questions/25671053/… Schätzen Sie Ihre Kommentare zu diesem Problem!
Garavani

@MikeBarwick Könnten Sie bitte Ihren Kommentar erläutern oder einen Link angeben, der ihn erklärt? Vielen Dank im Voraus.
Billal Begueradj

22

Nur das Hinzufügen return false;am Ende der on("click touchstart")Ereignisfunktion kann dieses Problem lösen.

$(this).on("click touchstart", function() {
  // Do things
  return false;
});

Aus der jQuery-Dokumentation zu .on ()

Wenn Sie falsevon einem Ereignishandler zurückkehren, wird automatisch event.stopPropagation()und aufgerufen event.preventDefault(). Ein falseWert kann auch für den Handler als Abkürzung für übergeben werden function(){ return false; }.


2
funktioniert super, feuert nur einmal auf Geräten mit beiden - dies scheint mir die sauberste, am wenigsten hackige Lösung zu sein
Adam Cooper

Hat am besten für mich funktioniert und tatsächlich Sinn gemacht, warum.
Amir5000

Irgendwelche Nachteile? Warum ist eine so einfache Lösung nicht allgemein bekannt?
ESR

10

Ich musste etwas Ähnliches tun. Hier ist eine vereinfachte Version dessen, was für mich funktioniert hat. Wenn ein Berührungsereignis erkannt wird, entfernen Sie die Klickbindung.

$thing.on('touchstart click', function(event){
  if (event.type == "touchstart")
    $(this).off('click');

  //your code here
});

In meinem Fall war das <a>Klickereignis an ein Element gebunden, sodass ich die Klickbindung entfernen und ein Klickereignis erneut binden musste, wodurch die Standardaktion für das <a>Element verhindert wurde.

$thing.on('touchstart click', function(event){
  if (event.type == "touchstart")
    $(this).off('click').on('click', function(e){ e.preventDefault(); });

  //your code here
});

Ich wünschte, das würde so funktionieren, aber es funktioniert nicht. $ (this) zeigt nicht auf das, was Sie denken.
Dave Lowerre

8

Es gelang mir auf folgende Weise.

Kinderleicht...

$(this).on('touchstart click', function(e){
  e.preventDefault();
  //do your stuff here
});

4
Wird das nicht zweimal auf Geräten ausgelöst, die sowohl einen Klick als auch einen Touchstart registrieren?
DA.

8
Entschuldigung, ich habe dich informiert. Ja, Sie haben Recht, eine Berührung erzeugt ein Touchstart-Ereignis und ein Klick-Ereignis. Dies wird als Ghost Click bezeichnet. Google hat dafür eine Lösung implementiert. Könnte nicht einfach sein, funktioniert aber perfekt. Hier ist der Link. code.google.com/mobile/articles/fast_buttons.html#ghost
Hasanavi

2
mag trivial sein, aber Sie vermissen den eParameter infunction()
ProblemsOfSumit

@ Hasanavi dies war eine großartige Lösung, aber ich fand bessere Ergebnisse mit .on
Neil

1
Danke @Neil. Ja, die Verwendung von .on ist eine bessere Idee, da sie möglicherweise in zukünftigen Versionen entfernt wird. Ich habe mein Beispiel von bind in on geändert.
Hasanavi

5

Ich glaube, die beste Vorgehensweise ist jetzt:

$('#object').on('touchend mouseup', function () { });

Touchend

Das Touchend-Ereignis wird ausgelöst, wenn ein Touchpoint von der Touch-Oberfläche entfernt wird.

Die touchend Veranstaltung wird nicht alle Mausereignisse ausgelöst werden .


mouseup

Das Mouseup-Ereignis wird an ein Element gesendet, wenn sich der Mauszeiger über dem Element befindet und die Maustaste losgelassen wird. Jedes HTML-Element kann dieses Ereignis empfangen.

Die mouseup Veranstaltung wird nicht alle Touch - Ereignisse auslösen.

BEISPIEL

$('#click').on('mouseup', function () { alert('Event detected'); });
$('#touch').on('touchend', function () { alert('Event detected'); });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1 id="click">Click me</h1>
<h1 id="touch">Touch me</h1>


BEARBEITEN (2017)

Ab 2017 können Browser, die mit Chrome beginnen und Schritte unternehmen, um das Klickereignis .on("click")für Maus und Berührung kompatibler zu machen, die Verzögerung beseitigen, die durch Tippereignisse bei Klickanforderungen entsteht.

Dies führt zu der Schlussfolgerung, dass die Rückkehr zur Verwendung nur des Klickereignisses die einfachste Lösung für die Zukunft wäre.

Ich habe noch keine Cross-Browser-Tests durchgeführt, um festzustellen, ob dies praktisch ist.


Das schien mir vielversprechend, also habe ich ein bisschen rumgespielt, aber letztendlich habe ich mouseupunvorhersehbare Ergebnisse erzielt, insbesondere wenn ich ein Trackpad anstelle einer herkömmlichen Maus verwendet habe.
Skybondsor

4

Im Allgemeinen möchten Sie die Standard-Touch- und Non-Touch-API (Klick) nicht mischen. Sobald Sie sich in der Welt der Berührung befinden, ist es einfacher, sich nur mit den berührungsbezogenen Funktionen zu befassen. Unten finden Sie einen Pseudocode, der genau das tut, was Sie möchten.

Wenn Sie im Touchmove-Ereignis eine Verbindung herstellen und die Positionen verfolgen, können Sie der doTouchLogic-Funktion weitere Elemente hinzufügen, um Gesten und so weiter zu erkennen.

var touchStartTime;
var touchStartLocation;
var touchEndTime;
var touchEndLocation;

$thing.bind('touchstart'), function() {
     var d = new Date();
     touchStartTime = d.getTime();
     touchStartLocation = mouse.location(x,y);
});

$thing.bind('touchend'), function() {
     var d = new Date();
     touchEndTime= d.getTime();
     touchEndLocation= mouse.location(x,y);
     doTouchLogic();
});

function doTouchLogic() {
     var distance = touchEndLocation - touchStartLocation;
     var duration = touchEndTime - touchStartTime;

     if (duration <= 100ms && distance <= 10px) {
          // Person tapped their finger (do click/tap stuff here)
     }
     if (duration > 100ms && distance <= 10px) {
          // Person pressed their finger (not a quick tap)
     }
     if (duration <= 100ms && distance > 10px) {
          // Person flicked their finger
     }
     if (duration > 100ms && distance > 10px) {
          // Person dragged their finger
     }
}

Ich nehme an, das ist der Kern der Frage: Ist es überhaupt sinnvoll, beide Modelle mit einer Codebasis zu unterstützen? Ich werde meine Frage mit einigen weiteren Szenarien aktualisieren.
DA.

1
"Im Allgemeinen möchten Sie die Standardberührung und die Nichtberührung nicht mischen", stimme ich zu. Das Problem ist, dass sie weiterhin Touch-Geräte mit Tastaturen herstellen, was uns Entwicklern Kopfschmerzen bereitet.
DA.

Ich bin damit einverstanden, dass es viel einfacher wäre, zu Beginn die endgültige Entscheidung zu treffen oder keine Berührung. Was für eine einfache Welt wäre das! Aber was ist das mit diesen verdammten Geräten, die vernünftig klicken und berühren? Lohnt es sich, all diese Kopfschmerzen wegen ihnen zu haben? Ist das die Zukunft, die ich mich frage?
Garavani

Ich mag die Idee nicht, mehrere Definitionen von Funktionen zu haben. Mein Unternehmen arbeitet derzeit an einem Projekt, bei dem ein iPad nicht speziell als mobiles Gerät behandelt wird und Sie das Touchend-Ereignis noch benötigen. Touchend funktioniert jedoch nicht auf normalen Desktop-Versionen. Die Lösung von @mottie ist also für dieses Szenario absolut in Ordnung.
Pete


3

Nun ... All dies ist super kompliziert.

Wenn Sie modernizr haben, ist es ein Kinderspiel.

ev = Modernizr.touch ? 'touchstart' : 'click';

$('#menu').on(ev, '[href="#open-menu"]', function(){
  //winning
});

2
Können Sie erklären, was das bedeutet? Ich glaube, es wird überprüft, ob das Gerät Touch unterstützt, und wenn nicht, wird Click verwendet. Der Haken ist (oder zumindest war , als ich die Frage schrieb) war , dass einige Geräte unterstützen beide. Und auf diesen Geräten muss ich immer noch beide Ereignisse behandeln, da der Auslöser entweder durch Berühren oder Klicken kommen kann.
DA.

2
Ich empfehle etwas mehr Erklärung.
Aaron Hall

2

Eine weitere Implementierung für eine bessere Wartung. Diese Technik führt jedoch auch event.stopPropagation () aus. Der Klick wird von keinem anderen Element erfasst, das 100 ms lang geklickt hat.

var clickObject = {
    flag: false,
    isAlreadyClicked: function () {
        var wasClicked = clickObject.flag;
        clickObject.flag = true;
        setTimeout(function () { clickObject.flag = false; }, 100);
        return wasClicked;
    }
};

$("#myButton").bind("click touchstart", function (event) {
   if (!clickObject.isAlreadyClicked()) {
      ...
   }
}

2

Nur zu Dokumentationszwecken habe ich Folgendes getan, um den schnellsten / reaktionsschnellsten Klick auf den Desktop / Tippen auf eine mobile Lösung zu erzielen, die mir einfällt:

Ich habe die Funktion von jQuery ondurch eine modifizierte ersetzt, die, wenn der Browser Berührungsereignisse unterstützt, alle meine Klickereignisse durch Berührungsstart ersetzte.

$.fn.extend({ _on: (function(){ return $.fn.on; })() });
$.fn.extend({
    on: (function(){
        var isTouchSupported = 'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch;
        return function( types, selector, data, fn, one ) {
            if (typeof types == 'string' && isTouchSupported && !(types.match(/touch/gi))) types = types.replace(/click/gi, 'touchstart');
            return this._on( types, selector, data, fn);
        };
    }()),
});

Verwendung als wäre genau die gleiche wie zuvor, wie:

$('#my-button').on('click', function(){ /* ... */ });

Aber es würde Touchstart verwenden, wenn verfügbar, klicken Sie, wenn nicht. Keine Verzögerungen jeglicher Art erforderlich: D.


1
Der Haken dabei wären Geräte, die sowohl Touch- als auch Tastaturen unterstützen, bei denen Sie sicherstellen müssen, dass beide Interaktionen möglich sind.
DA.

Gute Beobachtung @DA. Ich habe eine Prüfung hinzugefügt, um das Klickereignis nur zu ersetzen, wenn Sie kein Berührungsereignis in Kombination damit verwenden. Stil wird nicht für jedes Projekt eine Lösung sein, aber ich bin sicher, dass es für viele gut passt.
Gerson Goulart

2

Ich hatte gerade die Idee, mir zu merken, ob ontouchstartes jemals ausgelöst wurde. In diesem Fall befinden wir uns auf einem Gerät, das dies unterstützt, und möchten das onclickEreignis ignorieren . Da ontouchstartsollte immer vorher ausgelöst werden onclick, benutze ich dies:

<script> touchAvailable = false; </script>
<button ontouchstart="touchAvailable=true; myFunction();" onclick="if(!touchAvailable) myFunction();">Button</button>


1
Da Benutzer während desselben Seitenbesuchs möglicherweise Berührung und Maus verwenden, besteht das Problem bei diesem Snippet darin, dass das Flag touchAvailable einmal pro Ereignis registriert wird. Das jQuery-Plugin von stackoverflow.com/a/26145343/328272 macht dasselbe wie Ihr Code, kann jedoch für ein Mausereignis erkennen, ob es ereignisbasiert durch Berühren oder Maus ausgelöst wurde. Nicht nur dh. beim Klicken, aber auch beim Mausklick, der Sekunden (oder Minuten) nach dem Mouseenter ausgelöst werden kann (ideal für Flyout-Menüs, die beim Mouseover mit Mausgesten oder beim Klicken bei Berührung erweitert werden sollen).
lmeurs

2

Sie könnten es so versuchen:

var clickEvent = (('ontouchstart' in document.documentElement)?'touchstart':'click');
$("#mylink").on(clickEvent, myClickHandler);

Was ist mit Geräten, die Touch und Maus unterstützen
Walle Cyril

2

In meinem Fall hat das perfekt funktioniert:

jQuery(document).on('mouseup keydown touchend', function (event) {
var eventType = event.type;
if (eventType == 'touchend') {
    jQuery(this).off('mouseup');
}
});

Das Hauptproblem war, als ich stattdessen mit einem Mausklick versuchte, auf Touch-Geräten Klick und Touchend gleichzeitig auszulösen. Wenn ich den Klick-Off verwende, funktionierten einige Funktionen auf Mobilgeräten überhaupt nicht. Das Problem beim Klicken ist, dass es sich um ein globales Ereignis handelt, das den Rest des Ereignisses einschließlich Touchend auslöst.


1

Das hat bei mir funktioniert, Mobile hört auf beide, also verhindere das, was das Touch-Ereignis ist. Desktop nur Maus hören.

 $btnUp.bind('touchstart mousedown',function(e){
     e.preventDefault();

     if (e.type === 'touchstart') {
         return;
     }

     var val = _step( _options.arrowStep );
               _evt('Button', [val, true]);
  });

1

Da ich für mich die beste Antwort von Mottie bin, versuche ich nur, seinen Code wiederverwendbarer zu machen. Das ist also mein Beitrag:

bindBtn ("#loginbutton",loginAction);

function bindBtn(element,action){

var flag = false;
$(element).bind('touchstart click', function(e) {
    e.preventDefault();
    if (!flag) {
        flag = true;
        setTimeout(function() {
            flag = false;
        }, 100);
        // do something
        action();
    }
    return false;
});

0

Ich arbeite auch an einer Android / iPad-Web-App, und es scheint, dass die Verwendung von "touchmove" ausreicht, um "Komponenten zu verschieben" (kein Touchstart erforderlich). Durch Deaktivieren von Touchstart können Sie .click () verwenden. von jQuery. Es funktioniert tatsächlich, weil es nicht durch Touchstart überlastet wird.

Schließlich können Sie binb .live ("touchstart", Funktion (e) {e.stopPropagation ();}); Um das Touchstart-Ereignis zu bitten, die Ausbreitung zu stoppen, klicken Sie im Wohnzimmer auf (), um ausgelöst zu werden.

Es hat bei mir funktioniert.


Wie würden Sie deaktivieren touchstart?
Punkrockbuddyholly

Ich glaube, dass Sie so etwas "tun" könnten: jQuery ("# ​​my_element"). On ('touchstart', function (e) {e.preventDefault ()});
Nembleton

0

Bei der Lösung dieses Problems sind viele Dinge zu beachten. Die meisten Lösungen unterbrechen entweder das Scrollen oder behandeln Ghost-Click-Ereignisse nicht richtig.

Eine vollständige Lösung finden Sie unter https://developers.google.com/mobile/articles/fast_buttons

NB: Sie können Ghost-Click-Ereignisse nicht pro Element verarbeiten. Ein verzögerter Klick wird nach Bildschirmposition ausgelöst. Wenn Ihre Berührungsereignisse die Seite auf irgendeine Weise ändern, wird das Klickereignis an die neue Version der Seite gesendet.


0

Es kann effektiv sein, die Ereignisse zuzuordnen 'touchstart mousedown'oder 'touchend mouseup'unerwünschte Nebenwirkungen der Verwendung zu vermeiden click.


0

Unter Ausnutzung der Tatsache, dass ein Klick immer auf ein Berührungsereignis folgt, habe ich Folgendes getan, um den "Geisterklick" zu beseitigen, ohne Zeitüberschreitungen oder globale Flags verwenden zu müssen.

$('#buttonId').on('touchstart click', function(event){
    if ($(this).data("already")) {
        $(this).data("already", false);
        return false;
    } else if (event.type == "touchstart") {
        $(this).data("already", true);
    }
    //your code here
});

Grundsätzlich wird jedes Mal, wenn ein ontouchstartEreignis auf das Element ausgelöst wird, ein Flag gesetzt und anschließend entfernt (und ignoriert), wenn der Klick erfolgt.


0

Warum nicht die jQuery-Ereignis-API verwenden?

http://learn.jquery.com/events/event-extensions/

Ich habe dieses einfache Ereignis mit Erfolg genutzt. Es ist sauber, namenreich und flexibel genug, um es zu verbessern.

var isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent);
var eventType = isMobile ? "touchstart" : "click";

jQuery.event.special.touchclick = {
  bindType: eventType,
  delegateType: eventType
};

1
Es wird empfohlen, die Funktionserkennung über das Sniffing von Benutzeragenten zu verwenden.
Jinglesthula

Der Haken sind Geräte, die sowohl Berühren als auch Klicken unterstützen.
DA.

0

Wenn Sie jQuery verwenden, hat Folgendes für mich ziemlich gut funktioniert:

var callback; // Initialize this to the function which needs to be called

$(target).on("click touchstart", selector, (function (func){
    var timer = 0;
    return function(e){
        if ($.now() - timer < 500) return false;
        timer = $.now();
        func(e);
    }
})(callback));

Andere Lösungen sind ebenfalls gut, aber ich habe mehrere Ereignisse in einer Schleife gebunden und benötigte die selbstaufrufende Funktion, um einen geeigneten Abschluss zu erstellen. Außerdem wollte ich die Bindung nicht deaktivieren, da ich wollte, dass sie beim nächsten Klick / Touchstart aufgerufen werden kann.

Könnte jemandem in einer ähnlichen Situation helfen!


0

Für einfache Funktionen erkennen Sie einfach Berührung oder klicken Sie auf Ich verwende den folgenden Code:

var element = $("#element");

element.click(function(e)
{
  if(e.target.ontouchstart !== undefined)
  {
    console.log( "touch" );
    return;
  }
  console.log( "no touch" );
});

Dies gibt "touch" zurück, wenn das touchstart-Ereignis definiert ist, und "no touch", wenn nicht. Wie ich bereits sagte, ist dies ein einfacher Ansatz für Click / Tap-Ereignisse.


0

Ich versuche dies und bis jetzt funktioniert es (aber ich bin nur auf Android / Phonegap also Vorbehalt Emptor)

  function filterEvent( ob, ev ) {
      if (ev.type == "touchstart") {
          ob.off('click').on('click', function(e){ e.preventDefault(); });
      }
  }
  $('#keypad').on('touchstart click', '.number, .dot', function(event) {
      filterEvent( $('#keypad'), event );
      console.log( event.type );  // debugging only
           ... finish handling touch events...
  }

Ich mag die Tatsache nicht, dass ich Handler bei jeder Berührung neu binde, aber alles, was als Berührungen betrachtet wird, kommt nicht sehr oft vor (in der Computerzeit!)

Ich habe eine TONNE Handler wie den für '#keypad'. Eine einfache Funktion, mit der ich das Problem ohne zu viel Code lösen kann, ist der Grund, warum ich diesen Weg gegangen bin.



0

EDIT: Meine frühere Antwort (basierend auf den Antworten in diesem Thread) war nicht der richtige Weg für mich. Ich wollte, dass ein Untermenü beim Eingeben oder Klicken mit der Maus erweitert und beim Verlassen der Maus oder einem anderen Klick ausgeblendet wird. Da Mausereignisse normalerweise nach Berührungsereignissen ausgelöst werden, war es schwierig, Ereignis-Listener zu schreiben, die sowohl Touchscreen- als auch Mauseingaben gleichzeitig unterstützen.

jQuery-Plugin: Berühren oder Maus

Am Ende habe ich ein jQuery-Plugin namens " Touch Or Mouse " (897 Byte minimiert) geschrieben, das erkennen kann, ob ein Ereignis von einem Touchscreen oder einer Maus aufgerufen wurde (ohne auf Touch-Unterstützung zu testen!). Dies ermöglicht die Unterstützung von sowohl Touchscreen und Maus gleichzeitig und vollständig trennen ihre Veranstaltungen.

Auf diese Weise kann das OP Touch-Klicks und Klicks, die nur von einer Maus aufgerufen werden, verwenden touchstartoder touchendschnell darauf reagieren .click

Demonstration

Zuerst muss man also machen. das Körperelement verfolgt Berührungsereignisse:

$(document.body).touchOrMouse('init');

$body.touchOrMouse('get', e)Mausereignisse sind standardmäßig an Elemente gebunden. Durch Aufrufen können wir herausfinden, ob das Ereignis über einen Touchscreen oder eine Maus aufgerufen wurde.

$('.link').click(function(e) {
  var touchOrMouse = $(document.body).touchOrMouse('get', e);

  if (touchOrMouse === 'touch') {
    // Handle touch click.
  }
  else if (touchOrMouse === 'mouse') {
    // Handle mouse click.
  }
}

Siehe das Plugin bei der Arbeit unter http://jsfiddle.net/lmeurs/uo4069nh .

Erläuterung

  1. Dieses Plugin muss also aufgerufen werden. das Körperelement zu verfolgen touchstartund touchendEreignisse, auf diese Weise das touchendEreignis nicht auf dem Auslöseelement gebrannt werden muss (dh. ein Link oder eine Schaltfläche). Zwischen diesen beiden Berührungsereignissen betrachtet dieses Plugin jedes Mausereignis als durch Berühren aufgerufen.
  2. touchendMausereignisse werden erst ausgelöst , nachdem ein Mausereignis innerhalb der ghostEventDelayOption (Option 1000 ms standardmäßig) ausgelöst touchendwurde. Dieses Plugin betrachtet das Mausereignis als durch Berühren aufgerufen.
  3. Wenn Sie über einen Touchscreen auf ein Element klicken, erhält das Element den :activeStatus. Das mouseleaveEreignis wird erst ausgelöst, nachdem das Element diesen Zustand um dh verloren hat. Klicken Sie auf ein anderes Element. Da dies Sekunden (oder Minuten!) Nach dem mouseenterAuslösen des Ereignisses sein kann, verfolgt dieses Plugin das letzte mouseenterEreignis eines Elements : Wenn das letzte mouseenterEreignis durch Berühren aufgerufen wurde, gilt das folgende mouseleaveEreignis auch als durch Berühren aufgerufen.

0

Hier ist eine einfache Möglichkeit, dies zu tun:

// A very simple fast click implementation
$thing.on('click touchstart', function(e) {
  if (!$(document).data('trigger')) $(document).data('trigger', e.type);
  if (e.type===$(document).data('trigger')) {
    // Do your stuff here
  }
});

Grundsätzlich speichern Sie den ersten Ereignistyp, der ausgelöst wird, in der Eigenschaft 'trigger' im Datenobjekt von jQuery, das an das Stammdokument angehängt ist, und führen ihn nur aus, wenn der Ereignistyp dem Wert in 'trigger' entspricht. Auf Touch-Geräten lautet die Ereigniskette wahrscheinlich "Touchstart", gefolgt von "Klicken". Der 'click'-Handler wird jedoch nicht ausgeführt, da "click" nicht mit dem ursprünglichen Ereignistyp übereinstimmt, der in' trigger '("touchstart") gespeichert ist.

Die Annahme, und ich glaube, es ist sicher, ist, dass Ihr Smartphone nicht spontan von einem Touch-Gerät zu einem Mausgerät wechselt oder dass sich der Tipp niemals registriert, da der Ereignistyp "Auslöser" nur einmal pro gespeichert wird Seitenladen und "Klicken" würden niemals mit "Touchstart" übereinstimmen.

Hier ist ein Codepen, mit dem Sie herumspielen können (versuchen Sie, auf einem Touch-Gerät auf die Schaltfläche zu tippen - es sollte keine Klickverzögerung geben): http://codepen.io/thdoan/pen/xVVrOZ

Ich habe dies auch als einfaches jQuery-Plugin implementiert, das auch das Filtern von Nachkommen von jQuery durch Übergeben einer Auswahlzeichenfolge unterstützt:

// A very simple fast click plugin
// Syntax: .fastClick([selector,] handler)
$.fn.fastClick = function(arg1, arg2) {
  var selector, handler;
  switch (typeof arg1) {
    case 'function':
      selector = null;
      handler = arg1;
      break;
    case 'string':
      selector = arg1;
      if (typeof arg2==='function') handler = arg2;
      else return;
      break;
    default:
      return;
  }
  this.on('click touchstart', selector, function(e) {
    if (!$(document).data('trigger')) $(document).data('trigger', e.type);
    if (e.type===$(document).data('trigger')) handler.apply(this, arguments);
  });
};

Codepen: http://codepen.io/thdoan/pen/GZrBdo/


Warum haben Sie eine Dateneigenschaft für das Dokument verwendet, anstatt nur eine Variable zu verwenden?
Raphael Schweikert

@ RaphaelSchweikert Wahrscheinlich nur aus Gewohnheit. Es gibt keinen richtigen oder falschen Weg, aber ich verwende ihn gerne zum $.data()Speichern von Daten, auf die mehrere Funktionen zugreifen können, die jedoch nicht zum globalen Bereich gehören. Ein Plus ist, dass ich, da ich es in einem Element speichere, natürlich mehr Kontext habe.
Dooan

0

Die beste Methode, die ich gefunden habe, besteht darin, das Berührungsereignis zu schreiben und dieses Ereignis das normale Klickereignis programmgesteuert aufrufen zu lassen. Auf diese Weise haben Sie alle Ihre normalen Klickereignisse und müssen dann nur einen Ereignishandler für alle Berührungsereignisse hinzufügen. Fügen Sie für jeden Knoten, den Sie berührbar machen möchten, einfach die Klasse "berührbar" hinzu, um den Berührungshandler aufzurufen. Mit Jquery funktioniert es mit einer gewissen Logik, um sicherzustellen, dass es sich um ein echtes Berührungsereignis und nicht um ein falsches Positiv handelt.

$("body").on("touchstart", ".touchable", function() { //make touchable  items fire like a click event
var d1 = new Date();
var n1 = d1.getTime();
setTimeout(function() {
    $(".touchable").on("touchend", function(event) {
        var d2 = new Date();
        var n2 = d2.getTime();
        if (n2 - n1 <= 300) {
            $(event.target).trigger("click"); //dont do the action here just call real click handler
        }
    });
}, 50)}).on("click", "#myelement", function() {
//all the behavior i originally wanted
});
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.