Je dois détecter les glissades gauche/droite et y réagir, mais je veux donner à l'utilisateur la possibilité de faire défiler le même élément, aussi longtemps qu'il ne déplace son doigt que vers la gauche/droite avec un mouvement maximum de X pixels vers le haut/bas , il ne devrait pas défiler, mais quand il dépasse X, il devrait défiler.
Alors ce que j'ai fait c'est:
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();
}
Mais je ne rétablis pas la possibilité de faire défiler dans le cas "si" ...
Merci pour tous les conseils.
J'ai écrit mon propre gestionnaire d'événements Touch.maybe cela vous aide
il vérifie:
clic rapide: 'fc'
glisser à gauche: 'swl'
glisser à droite: 'swr'
balayez vers le haut: 'swu'
glisser vers le bas: 'swd'
chaque vérification initialise son événement correspondant, mais vous pouvez faire défiler et faire ce que vous faites normalement. vous avez juste quelques nouveaux événements.
vous avez besoin de swl swr, je suggère également d'utiliser fc (fastclick) pour les événements de clic ... c'est beaucoup plus rapide qu'un clic normal.
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);
}
dans ce cas, h est mon gestionnaire pour chaque type d’événement et j’ajoute les gestionnaires au corps.
pour ce que je comprends votre question il vous suffit d'écrire
YOURELEMENT.addEventListener('swr',YOURSWIPERIGHTFUNCTION,false);
YOURELEMENT.addEventListener('swl',YOURSWIPELEFTFUNCTION,false);
pour gérer plusieurs éléments et la même fonction ... il suffit d'ajouter un gestionnaire.
donc si vous avez
<ul id="ul"><li>1</li><li>2</li><li>3</li></ul>
tu fais:
var deleteli=function(e){
var li=e.target;
console.log('deleting '+li.textContent);
}
document.getElementById('ul').addEventListener('swl',deleteli,false);
idem pour fc & swr
il y a un bogue dans ios: n'utilisez pas alert () .. il sera exécuté 2 fois.
Il y a un "bug" dans la réponse acceptée. Si vous n'utilisez pas Chrome sur Android mais le navigateur intégré ou une "Webview" (pour une application html5-hybrid-app) par exemple, le balayage n'est pas détecté.
J'ai découvert que l'événement ne se déclenchait pas à cause du comportement de défilement normal. Donc, en ajoutant "e.preventDefault ();" in touchmove résoudrait le problème ou le correctif d’Eric Fuller dans la réponse acceptée.
C'est une belle copie mais dans une application Web mobile ou un site Web, cela pourrait entraîner un mauvais bégaiement du défilement, car les événements tactiles sont observés en permanence.
J'ai donc décidé de construire quelque chose de nouveau. Ce n'est pas aussi confortable d’avoir de nouveaux auditeurs d’événements, mais c’est assez confortable pour mes besoins et sa performance.
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");
}
Pour utiliser la fonction, utilisez-la simplement comme
detectswipe('an_element_id',myfunction);
detectswipe('an_other_element_id',my_other_function);
Si un balayage est détecté, la fonction "myfunction" est appelée avec le paramètre element-id et "l, r, u, d" (gauche, droite, haut, bas).
Exemple: http://jsfiddle.net/rvuayqeo/1/
Tous ces codes doivent être améliorés (comme la plupart des codes que vous pouvez trouver sur la manipulation tactile).
Lorsque vous jouez avec un événement tactile, gardez à l'esprit que l'utilisateur a plus d'un doigt, qu'une touche a un identificateur et que la liste touches
représente toutes les touches actuelles sur la surface, même les touches n'ayant pas déplacé.
Le processus est donc relativement simple:
ontouchstart: obtient le premier contact modifié (pas la propriété event.originalEvent.touches
, mais celle event.originalEvent.changedTouches
). Enregistrez son identifiant avec event.originalEvent.changedTouches[0].identifier
et les propriétés tactiles à rechercher (pageX
/pageY
ou clientX
/clientY
qui sont plutôt utiles en combinaison avec la méthode DOMElement.getBoundingClientRect()
);
ontouchmove: assurez-vous que le contact actuel est dans la liste des nappes modifiées avec event.originalEvent.changedTouches.identifiedTouch( identifier )
. S'il ne renvoie rien, cela signifie que l'utilisateur a déplacé une autre touche (pas celle que vous recherchez). Enregistrez également les propriétés tactiles à rechercher et à faire ce que vous voulez.
ontouchend: encore une fois, vous devez être sûr que le contact actuel est dans la liste des nappes modifiées. Effectuez le travail avec les propriétés tactiles et finalement supprimez votre identifiant tactile actuel.
Si vous voulez le faire plus fort, considérez plusieurs touches (pas une seule) à observer.
Plus d'informations sur TouchEvent, TouchList et Touch sur: https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Touch_events
Inspiré par @cocco, j'ai créé une meilleure version (non minimisée):
(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);
Changements importants par rapport à la version originale de @cocco:
event.touches[0].screenX/screenY
comme source principale d’informations. Les propriétés pageX/pageY
ne représentent pas correctement le mouvement des contacts à l'écran car si un élément de page défile avec le toucher, cela affecte également les valeurs de pageX/pageY
.pageX/pageY
avant de déclencher le geste)Ce qu'il faudrait faire à l'avenir:
CustomEvent()
function interface au lieu de la méthode createEvent()
.pageX/pageY
séparément de screenX/screenY
?L'utilisation est la suivante:
document.body.addEventListener('gesture-right', function (e) { ... });
ou style jquery
$("article").on("gesture-down", function (e) { ... });
Détection de gauche et de droite lorsque le toucher est toujours en mouvement .
Ceci est fait en sauvegardant la dernière position et en utilisant timeout pour effacer la dernière position après un arrêt tactile.
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);
});