06.072015

Beim Scrollen über Elemente Touch-Events verhindern

Möchte man interaktive Elemente auf einem Smartphone oder anderen Touch-Devices benutzerfreundlich machen, so bietet es sich an diese so umzusetzen, dass die User die komplette Fläche des Elements für eine Interaktion touchen können, statt nur ein kleines Icon oder Text. Problematisch wird es, wenn solch ein Element die komplette Breite des Screens einnimmt und der User beim darüber  scrollen mit dem Finger versehentlich eine Interaktion auslöst. Dies kann zum Beispiel schnell bei einen klassischen Listing passieren. Ein guter Zeitpunkt dies mit einigen Zeilen jQuery JavaScript zu verbessern.

touchOnScroll

Die relevanten Events für mein Script

  • touchstart - Der Finger hat das Element berührt (vgl. mousedown beim Desktop-Browser)
  • touchend - Der Finger hat das Element verlassen (vgl. mouseup beim Desktop-Browser)
  • click - Der Klick mit einer Maus (ersetzt bei jquery mousedown/mouseup)

Der Plan

Ich habe verschiedene Techniken probiert und diese hat sich für mich als einfachste und Cross-Browser/Device kompatibelste herausgestellt:
In meinem Beispiel berührt der User ein Listing-Element beim Scrollen. Immer wenn er dies tut, wird bei dem entsprechendem Element ein touchstart und touchend Event ausgelöst. Um nun zu schauen ob er dies beim Scrollen auslöst, vergleiche ich die Scroll-Positionen zu beiden Zeitpunkten. Wenn diese gleich ist, so wurden die Events nicht während eines Scroll-Vorganges ausgelöst und ich lasse die gewünschte Aktion ausführen. Etwas anderes ist es wenn der User ein Click-Event auslöst. In diesem Fall lasse ich grundsätzlich die Aktion ausführen, da auf einen Desktop das versehentliche Auslösen beim Scrollen nicht passiert (dauerklicken beim scrollen mal ausgenommen ;) )

Die Umsetzung

In der Function noTouchOnScroll ist der ganze Zauber gekapselt. Man übergibt ihr die Klasse des Elementes mit dem man per Touch/Click etwas machen möchte, und als zweites Argument die Function welche darauf ausgeführt werden soll. In Meinen Beispiel ist dieser Callback das Aufrufen einer Seite, deren Url aus einem data-target Attribut des Elements gezogen wird (In meinen Fall ein <li>-Tag)

$(document).ready(function(){

  function noTouchOnScroll(element,callback){
    var touchPos;
    $(element).on('touchstart', function(e){
      touchPos = $(window).scrollTop();
    }).on('touchend click', function(e){
      if( (e.type=='touchend' && touchPos == $(window).scrollTop()) || e.type=='click' ){
        callback.apply(this, []);
      }
    });
  }

  function goToTarget() {
    var target = $(this).attr('data-target');
    if (target) {
      window.location.href = target;
    }
  }

  noTouchOnScroll('.listingItem', goToTarget);

});

Übrigens...

Die Verwendung eines e.preventDefault() auf touchstart/touchend führ auf iOS Devices und in manchen Android Browsern dazu, das beim touchen kein Scrollen mehr möglich ist. Für den Fall das ihr auf preventDefault eines Events angewiesen seit, müsst ihr das also auch leider in die Logik packen.

 

Viel Spaß und Erfolg mit eurem nächsten Mobile-Device-Projekt!