it-swarm.com.de

Links/Rechts-Streichen auf Touch-Geräten erkennen, aber Bildlauf nach oben/unten ermöglichen

Ich muss das Wischen nach links/rechts erkennen und darauf reagieren, aber ich möchte dem Benutzer die Möglichkeit geben, auf demselben Element zu scrollen, solange er seinen Finger nur nach links/rechts bewegt und dabei maximal X Pixel nach oben/unten bewegt sollte nicht scrollen, aber wenn er X überschreitet, sollte scrollen.

Also was ich getan habe ist:

var startX, startY, $this = $(this);
function touchmove(event) {
        var touches = event.originalEvent.touches;
        if (touches && touches.length) {
            var deltaX = touches[0].pageX - startX;
            var deltaY = touches[0].pageY - startY;
            if (Math.abs(deltaY) > 50) {
                $this.html('X: ' + deltaX + '<br> Y: ' + deltaY + '<br>TRUE');
                $this.unbind('touchmove', touchmove);
                return true;
            } else {
                $this.html('X: ' + deltaX + '<br> Y: ' + deltaY);
                event.preventDefault();
            }
        }
    }

    function touchstart(event) {
        var touches = event.originalEvent.touches;
        if (touches && touches.length) {
            startX = touches[0].pageX;
            startY = touches[0].pageY;
            $this.bind('touchmove', touchmove);
        }
        //event.preventDefault();
    }

Aber ich kann die Fähigkeit zum Scrollen im "Wenn" -Fall nicht wiederherstellen ... 

Danke für alle Tipps.

26
Raphael Jeger

Ich habe meine eigenen Touch-Handler-Events geschrieben. Vielleicht hilft Ihnen das

es prüft auf:

schneller Klick: 'fc'

nach links streichen: 'swl'

nach rechts streichen: 'swr'

nach oben streichen: "swu"

nach unten streichen: 'swd'

jede Prüfung initialisiert ihr entsprechendes Ereignis. Sie können jedoch scrollen und alles tun, was Sie sonst noch tun. Sie haben gerade einige neue Ereignisse. 

sie brauchen swl swr. Ich empfehle Ihnen auch, fc (fastclick) für Klickereignisse zu verwenden ... es ist viel schneller als normales Klicken.

window.onload = function() {
    (function(d) {
        var
            ce = function(e, n) {
                var a = document.createEvent("CustomEvent");
                a.initCustomEvent(n, true, true, e.target);
                e.target.dispatchEvent(a);
                a = null;
                return false
            },
            nm = true,
            sp = {
                x: 0,
                y: 0
            },
            ep = {
                x: 0,
                y: 0
            },
            touch = {
                touchstart: function(e) {
                    sp = {
                        x: e.touches[0].pageX,
                        y: e.touches[0].pageY
                    }
                },
                touchmove: function(e) {
                    nm = false;
                    ep = {
                        x: e.touches[0].pageX,
                        y: e.touches[0].pageY
                    }
                },
                touchend: function(e) {
                    if (nm) {
                        ce(e, 'fc')
                    } else {
                        var x = ep.x - sp.x,
                            xr = Math.abs(x),
                            y = ep.y - sp.y,
                            yr = Math.abs(y);
                        if (Math.max(xr, yr) > 20) {
                            ce(e, (xr > yr ? (x < 0 ? 'swl' : 'swr') : (y < 0 ? 'swu' : 'swd')))
                        }
                    };
                    nm = true
                },
                touchcancel: function(e) {
                    nm = false
                }
            };
        for (var a in touch) {
            d.addEventListener(a, touch[a], false);
        }
    })(document);
    //EXAMPLE OF USE
    var h = function(e) {
        console.log(e.type, e)
    };
    document.body.addEventListener('fc', h, false); // 0-50ms vs 500ms with normal click
    document.body.addEventListener('swl', h, false);
    document.body.addEventListener('swr', h, false);
    document.body.addEventListener('swu', h, false);
    document.body.addEventListener('swd', h, false);
}

in diesem Fall ist h mein Handler für jede Art von Ereignis, und ich füge die Handler dem Körper hinzu.

für was ich deine Frage verstehe, musst du nur schreiben

YOURELEMENT.addEventListener('swr',YOURSWIPERIGHTFUNCTION,false);
YOURELEMENT.addEventListener('swl',YOURSWIPELEFTFUNCTION,false);

um mehrere Elemente und dieselbe Funktion zu behandeln, fügen Sie einfach einen Handler hinzu.

also wenn du hast

<ul id="ul"><li>1</li><li>2</li><li>3</li></ul>

sie machen:

var deleteli=function(e){
    var li=e.target;
    console.log('deleting '+li.textContent);
}
document.getElementById('ul').addEventListener('swl',deleteli,false);

gleiches für FC & SWR

es gibt einen Fehler in ios: Verwenden Sie nicht alert (). Es wird 2 mal ausgeführt.

44
cocco

Die akzeptierte Antwort enthält einen "Fehler". Wenn Sie Chrome nicht für Android verwenden, sondern den eingebauten Browser oder eine "Webansicht" (z. B. für eine HTML5-Hybrid-App), wird der Swipe-Vorgang nicht erkannt.

Ich habe herausgefunden, dass das Ereignis aufgrund des normalen Scrollverhaltens nicht ausgelöst wird. So fügen Sie "e.preventDefault ();" in touchmove würde das Problem beheben oder das Update von Eric Fuller in der akzeptierten Antwort.

Es ist ein schöner Schnipsel, aber in einer mobilen WebApp oder Website kann dies zu einem störenden Scrollen führen, da die Berührungsereignisse die ganze Zeit beobachtet werden.

Also habe ich beschlossen, etwas Neues zu bauen. Es ist nicht so komfortabel wie neue Event-Hörer, aber es ist bequem genug für meine Bedürfnisse und deren Leistung.

function detectswipe(el,func) {
  swipe_det = new Object();
  swipe_det.sX = 0;
  swipe_det.sY = 0;
  swipe_det.eX = 0;
  swipe_det.eY = 0;
  var min_x = 20;  //min x swipe for horizontal swipe
  var max_x = 40;  //max x difference for vertical swipe
  var min_y = 40;  //min y swipe for vertical swipe
  var max_y = 50;  //max y difference for horizontal swipe
  var direc = "";
  ele = document.getElementById(el);
  ele.addEventListener('touchstart',function(e){
    var t = e.touches[0];
    swipe_det.sX = t.screenX; 
    swipe_det.sY = t.screenY;
  },false);
  ele.addEventListener('touchmove',function(e){
    e.preventDefault();
    var t = e.touches[0];
    swipe_det.eX = t.screenX; 
    swipe_det.eY = t.screenY;    
  },false);
  ele.addEventListener('touchend',function(e){
    //horizontal detection
    if ((((swipe_det.eX - min_x > swipe_det.sX) || (swipe_det.eX + min_x < swipe_det.sX)) && ((swipe_det.eY < swipe_det.sY + max_y) && (swipe_det.sY > swipe_det.eY - max_y)))) {
      if(swipe_det.eX > swipe_det.sX) direc = "r";
      else direc = "l";
    }
    //vertical detection
    if ((((swipe_det.eY - min_y > swipe_det.sY) || (swipe_det.eY + min_y < swipe_det.sY)) && ((swipe_det.eX < swipe_det.sX + max_x) && (swipe_det.sX > swipe_det.eX - max_x)))) {
      if(swipe_det.eY > swipe_det.sY) direc = "d";
      else direc = "u";
    }

    if (direc != "") {
      if(typeof func == 'function') func(el,direc);
    }
    direc = "";
  },false);  
}

myfunction(el,d) {
  alert("you swiped on element with id '"+el+"' to "+d+" direction");
}

Um die Funktion zu nutzen, benutzen Sie sie einfach wie

detectswipe('an_element_id',myfunction);

detectswipe('an_other_element_id',my_other_function);

Wird ein Swipe erkannt, wird die Funktion "myfunction" mit dem Parameter element-id und "l, r, u, d" (links, rechts, auf, ab) aufgerufen.

Beispiel: http://jsfiddle.net/rvuayqeo/1/

6
EscapeNetscape

Alle diese Codes müssen verbessert werden (wie die meisten Codes, die Sie bei der Touch-Manipulation finden können).

Beachten Sie beim Spielen mit einem Berührungsereignis, dass der Benutzer mehr als ein Finger hat, dass eine Berührung einen Bezeichner hat und dass die Liste touches alle aktuellen Berührungen auf der Oberfläche darstellt, sogar Berührungendie sich nicht bewegt haben.

Der Prozess ist also relativ einfach:

  1. onuchstart: Die erste geänderte Berührung wird abgerufen (nicht die event.originalEvent.touches-Eigenschaft, sondern event.originalEvent.changedTouches). Registrieren Sie den Bezeichner mit event.originalEvent.changedTouches[0].identifier und den Eigenschaften von touch, nach denen gesucht werden soll (pageX/pageY oder clientX/clientY, die in Kombination mit der DOMElement.getBoundingClientRect()-Methode sehr nützlich sind);

  2. onuchmove: Vergewissern Sie sich, dass die aktuelle Berührung mit event.originalEvent.changedTouches.identifiedTouch( identifier ) in der geändertenTouches-Liste enthalten ist. Wenn nichts zurückgegeben wird, bedeutet dies, dass der Benutzer eine weitere Berührung verschoben hat (nicht die, nach der Sie suchen). Registrieren Sie auch die Touch-Eigenschaften, nach denen Sie suchen und tun möchten, was Sie möchten.

  3. touchend: Auch hier müssen Sie sich vergewissern, dass sich die aktuelle Berührung in der geändertenTouches-Liste befindet. Führen Sie die Arbeit mit den Berührungseigenschaften durch und verwerfen Sie schließlich Ihre aktuelle Berührungskennung.

Wenn Sie es stärker machen möchten, sollten Sie mehrere Berührungen berücksichtigen (nicht nur eine).

Weitere Informationen zu TouchEvent, TouchList und Touch unter: https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Touch_events

3
Loops

Inspiriert von @cocco habe ich eine bessere (nicht minimierte) Version erstellt:

(function(d) {
    // based on original source: https://stackoverflow.com/a/17567696/334451
    var newEvent = function(e, name) {
        // This style is already deprecated but very well supported in real world: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/initCustomEvent
        // in future we want to use CustomEvent function: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
        var a = document.createEvent("CustomEvent");
        a.initCustomEvent(name, true, true, e.target);
        e.target.dispatchEvent(a);
        a = null;
        return false
    };
    var debug = false; // emit info to JS console for all touch events?
    var active = false; // flag to tell if touchend should complete the gesture
    var min_gesture_length = 20; // minimum gesture length in pixels
    var tolerance = 0.3; // value 0 means pixel perfect movement up or down/left or right is required, 0.5 or more means any diagonal will do, values between can be tweaked

    var sp = { x: 0, y: 0, px: 0, py: 0 }; // start point
    var ep = { x: 0, y: 0, px: 0, py: 0 }; // end point
    var touch = {
        touchstart: function(e) {
            active = true;
            t = e.touches[0];
            sp = { x: t.screenX, y: t.screenY, px: t.pageX, py: t.pageY };
            ep = sp; // make sure we have a sensible end poin in case next event is touchend
            debug && console.log("start", sp);
        },
        touchmove: function(e) {
            if (e.touches.length > 1) {
                active = false;
                debug && console.log("aborting gesture because multiple touches detected");
                return;
            }
            t = e.touches[0];
            ep = { x: t.screenX, y: t.screenY, px: t.pageX, py: t.pageY };
            debug && console.log("move", ep, sp);
        },
        touchend: function(e) {
            if (!active)
                return;
            debug && console.log("end", ep, sp);
            var dx = Math.abs(ep.x - sp.x);
            var dy = Math.abs(ep.y - sp.y);

            if (Math.max(dx, dy) < min_gesture_length) {
                debug && console.log("ignoring short gesture");
                return; // too short gesture, ignore
            }

            if (dy > dx && dx/dy < tolerance && Math.abs(sp.py - ep.py) > min_gesture_length) { // up or down, ignore if page scrolled with touch
                newEvent(e, (ep.y - sp.y < 0 ? 'gesture-up' : 'gesture-down'));
                //e.cancelable && e.preventDefault();
            }
            else if (dx > dy && dy/dx < tolerance && Math.abs(sp.px - ep.px) > min_gesture_length) { // left or right, ignore if page scrolled with touch
                newEvent(e, (ep.x - sp.x < 0 ? 'gesture-left' : 'gesture-right'));
                //e.cancelable && e.preventDefault();
            }
            else {
                debug && console.log("ignoring diagonal gesture or scrolled content");
            }
            active = false;
        },
        touchcancel: function(e) {
            debug && console.log("cancelling gesture");
            active = false;
        }
    };
    for (var a in touch) {
        d.addEventListener(a, touch[a], false);
        // TODO: MSIE touch support: https://github.com/CamHenlin/TouchPolyfill
    }
})(window.document);

Wichtige Änderungen gegenüber der Originalversion von @cocco:

  • verwenden Sie event.touches[0].screenX/screenY als Hauptinformationsquelle. Die pageX/pageY-Eigenschaften stellen die Bewegung von Berührungen auf dem Bildschirm nicht korrekt dar. Wenn ein Teil der Seite mit der Berührung scrollt, wirkt sich dies auch auf die pageX/pageY-Werte aus.
  • mindestlänge der Gestenlänge hinzufügen
  • toleranzeinstellung hinzufügen, um nahe diagonale Gesten zu ignorieren
  • ignorieren Sie die Geste, wenn der Seiteninhalt mit der Geste gescrollt wurde (prüfen Sie die Differenz in pageX/pageY, bevor Sie die Geste auslösen).
  • abbruch der Geste, wenn während der Geste mehrere Berührungen ausgeführt werden

Dinge, die in der Zukunft getan werden müssten:

  • verwenden Sie CustomEvent() function interface anstelle der createEvent()-Methode.
  • mSIE-Kompatibilität hinzufügen
  • vielleicht minimale Gestenlänge für pageX/pageY getrennt von screenX/screenY konfigurieren?
  • Es scheint, dass das Scrollen mit Chrome-Threads immer noch Probleme mit der Scroll-Erkennung verursacht, wenn die Touch-Bewegung zu schnell ist. Warten Sie vielleicht bis zum nächsten Frame, bevor Sie entscheiden, wo das Scrollen stattgefunden hat, bevor Sie entscheiden, ob das Ereignis ausgelöst werden soll.

Die Verwendung ist wie folgt:

document.body.addEventListener('gesture-right', function (e) {  ... });

oder Jquery-Stil

$("article").on("gesture-down", function (e) { ... });
1

Das Erkennen von links und rechts während der Berührung ist bewegt sich noch .

Dies erfolgt durch Speichern der letzten Position und Verwenden von timeout zum Löschen der letzten Position nach dem Touchmove-Stopp.

var currentX;
var lastX = 0;
var lastT;
$(document).bind('touchmove', function(e) {
    // If still moving clear last setTimeout
    clearTimeout(lastT);

    currentX = e.originalEvent.touches[0].clientX;

    // After stoping or first moving
    if(lastX == 0) {
        lastX = currentX;
    }

    if(currentX < lastX) {
        // Left
    } else if(currentX > lastX){
        // Right
    }

    // Save last position
    lastX = currentX;

    // Check if moving is done
    lastT = setTimeout(function() {
        lastX = 0;
    }, 100);
});
0
Nebojsa Sapic