Bir kullanıcının JavaScript içeren bir web sayfası üzerinde parmağını bir yönde kaydırdığını nasıl tespit edebilirsiniz?
Hem iPhone hem de Android telefondaki web siteleri için işe yarayacak tek bir çözüm olup olmadığını merak ediyordum.
Bir kullanıcının JavaScript içeren bir web sayfası üzerinde parmağını bir yönde kaydırdığını nasıl tespit edebilirsiniz?
Hem iPhone hem de Android telefondaki web siteleri için işe yarayacak tek bir çözüm olup olmadığını merak ediyordum.
Yanıtlar:
Basit vanilya JS kodu örneği:
document.addEventListener('touchstart', handleTouchStart, false);
document.addEventListener('touchmove', handleTouchMove, false);
var xDown = null;
var yDown = null;
function getTouches(evt) {
return evt.touches || // browser API
evt.originalEvent.touches; // jQuery
}
function handleTouchStart(evt) {
const firstTouch = getTouches(evt)[0];
xDown = firstTouch.clientX;
yDown = firstTouch.clientY;
};
function handleTouchMove(evt) {
if ( ! xDown || ! yDown ) {
return;
}
var xUp = evt.touches[0].clientX;
var yUp = evt.touches[0].clientY;
var xDiff = xDown - xUp;
var yDiff = yDown - yUp;
if ( Math.abs( xDiff ) > Math.abs( yDiff ) ) {/*most significant*/
if ( xDiff > 0 ) {
/* left swipe */
} else {
/* right swipe */
}
} else {
if ( yDiff > 0 ) {
/* up swipe */
} else {
/* down swipe */
}
}
/* reset values */
xDown = null;
yDown = null;
};
Android'de test edildi.
touchstart
, touchmove
?
@ Givanse'nin cevabına dayanarak, bunu şu şekilde yapabilirsiniz classes
:
class Swipe {
constructor(element) {
this.xDown = null;
this.yDown = null;
this.element = typeof(element) === 'string' ? document.querySelector(element) : element;
this.element.addEventListener('touchstart', function(evt) {
this.xDown = evt.touches[0].clientX;
this.yDown = evt.touches[0].clientY;
}.bind(this), false);
}
onLeft(callback) {
this.onLeft = callback;
return this;
}
onRight(callback) {
this.onRight = callback;
return this;
}
onUp(callback) {
this.onUp = callback;
return this;
}
onDown(callback) {
this.onDown = callback;
return this;
}
handleTouchMove(evt) {
if ( ! this.xDown || ! this.yDown ) {
return;
}
var xUp = evt.touches[0].clientX;
var yUp = evt.touches[0].clientY;
this.xDiff = this.xDown - xUp;
this.yDiff = this.yDown - yUp;
if ( Math.abs( this.xDiff ) > Math.abs( this.yDiff ) ) { // Most significant.
if ( this.xDiff > 0 ) {
this.onLeft();
} else {
this.onRight();
}
} else {
if ( this.yDiff > 0 ) {
this.onUp();
} else {
this.onDown();
}
}
// Reset values.
this.xDown = null;
this.yDown = null;
}
run() {
this.element.addEventListener('touchmove', function(evt) {
this.handleTouchMove(evt).bind(this);
}.bind(this), false);
}
}
Bunun gibi kullanmaktan daha fazlasını yapabilirsiniz:
// Use class to get element by string.
var swiper = new Swipe('#my-element');
swiper.onLeft(function() { alert('You swiped left.') });
swiper.run();
// Get the element yourself.
var swiper = new Swipe(document.getElementById('#my-element'));
swiper.onLeft(function() { alert('You swiped left.') });
swiper.run();
// One-liner.
(new Swipe('#my-element')).onLeft(function() { alert('You swiped left.') }).run();
.bind
undefined'i çağırmaya çalışırken bir istisna alacaksınız çünkü handleTouchMove
aslında hiçbir şey döndürmediniz. Ayrıca this.
zaten geçerli bağlama bağlı olduğu için işlev
.bind(this);
ve incelikle çalıştı. thank you @nicholas_r
touches[0]
için changedTouches[0]
ve olay işleyicisi türü handleTouchMove
içinhandleTouchEnd
run()
iki kez arayın ve kötü bir bellek sızıntısı olsun
Burada cevaplardan birkaçını DOM'da hızlıca kaydırılan olayları tetiklemek için CustomEvent kullanan bir komut dosyasına birleştirdim . Sayfanıza 0.7k swiped-events.min.js komut dosyasını ekleyin ve kaydırılan etkinlikleri dinleyin :
document.addEventListener('swiped-left', function(e) {
console.log(e.target); // the element that was swiped
});
document.addEventListener('swiped-right', function(e) {
console.log(e.target); // the element that was swiped
});
document.addEventListener('swiped-up', function(e) {
console.log(e.target); // the element that was swiped
});
document.addEventListener('swiped-down', function(e) {
console.log(e.target); // the element that was swiped
});
Doğrudan bir öğeye de ekleyebilirsiniz:
document.getElementById('myBox').addEventListener('swiped-down', function(e) {
console.log(e.target); // the element that was swiped
});
Saydam etkileşiminin sayfanızdaki işlevlerini nasıl değiştireceğini ayarlamak için aşağıdaki özellikleri belirleyebilirsiniz (bunlar isteğe bağlıdır) .
<div data-swipe-threshold="10"
data-swipe-timeout="1000"
data-swipe-ignore="false">
Swiper, get swiping!
</div>
Kaynak kodu Github'da mevcuttur
daha önce kullandığım mousedown olayı tespit etmek, x, y konumunu (hangisi alakalı ise) kaydetmek ve daha sonra mouseup olayını tespit etmek ve iki değeri çıkarmak zorundasınız.
jQuery Mobile ayrıca kaydırma desteği de içerir: http://api.jquerymobile.com/swipe/
Misal
$("#divId").on("swipe", function(event) {
alert("It's a swipe!");
});
Kaydırma işlemlerini kaydetmek için @givanse mükemmel yanıtını birden çok mobil tarayıcıda en güvenilir ve uyumlu olarak buldum.
Ancak, kodunu kullanan modern mobil tarayıcılarda çalışması için gerekli bir değişiklik var jQuery
.
event.touches
eğer var olmayacak jQuery
kullanılan ve sonuçları edilir undefined
ve değiştirilmesi gerektiğini event.originalEvent.touches
. Olmadan jQuery
, event.touches
iyi çalışmalı.
Böylece çözüm,
document.addEventListener('touchstart', handleTouchStart, false);
document.addEventListener('touchmove', handleTouchMove, false);
var xDown = null;
var yDown = null;
function handleTouchStart(evt) {
xDown = evt.originalEvent.touches[0].clientX;
yDown = evt.originalEvent.touches[0].clientY;
};
function handleTouchMove(evt) {
if ( ! xDown || ! yDown ) {
return;
}
var xUp = evt.originalEvent.touches[0].clientX;
var yUp = evt.originalEvent.touches[0].clientY;
var xDiff = xDown - xUp;
var yDiff = yDown - yUp;
if ( Math.abs( xDiff ) > Math.abs( yDiff ) ) {/*most significant*/
if ( xDiff > 0 ) {
/* left swipe */
} else {
/* right swipe */
}
} else {
if ( yDiff > 0 ) {
/* up swipe */
} else {
/* down swipe */
}
}
/* reset values */
xDown = null;
yDown = null;
};
Test tarihi:
event.originalEvent
. Şey artık event.touches
var olmaktan çıkıyor ve sonuçlanıyor undefined
.
event.originalEvent
. Cevabımı güncelleyeceğim. Teşekkürler! :)
TouchWipe
Kısa bir jquery eklentisi olarak yeniden paketledim :detectSwipe
Kısa tokatlamak için başa çıkmak için bazı uppest cevap modu (yorum yapamıyorum ...)
document.addEventListener('touchstart', handleTouchStart, false);
document.addEventListener('touchmove', handleTouchMove, false);
var xDown = null;
var yDown = null;
function handleTouchStart(evt) {
xDown = evt.touches[0].clientX;
yDown = evt.touches[0].clientY;
};
function handleTouchMove(evt) {
if ( ! xDown || ! yDown ) {
return;
}
var xUp = evt.touches[0].clientX;
var yUp = evt.touches[0].clientY;
var xDiff = xDown - xUp;
var yDiff = yDown - yUp;
if(Math.abs( xDiff )+Math.abs( yDiff )>150){ //to deal with to short swipes
if ( Math.abs( xDiff ) > Math.abs( yDiff ) ) {/*most significant*/
if ( xDiff > 0 ) {/* left swipe */
alert('left!');
} else {/* right swipe */
alert('right!');
}
} else {
if ( yDiff > 0 ) {/* up swipe */
alert('Up!');
} else { /* down swipe */
alert('Down!');
}
}
/* reset values */
xDown = null;
yDown = null;
}
};
trashold, zaman aşımı tokatlamak, tokatlamakBlockElems ekleyin.
document.addEventListener('touchstart', handleTouchStart, false);
document.addEventListener('touchmove', handleTouchMove, false);
document.addEventListener('touchend', handleTouchEnd, false);
const SWIPE_BLOCK_ELEMS = [
'swipBlock',
'handle',
'drag-ruble'
]
let xDown = null;
let yDown = null;
let xDiff = null;
let yDiff = null;
let timeDown = null;
const TIME_TRASHOLD = 200;
const DIFF_TRASHOLD = 130;
function handleTouchEnd() {
let timeDiff = Date.now() - timeDown;
if (Math.abs(xDiff) > Math.abs(yDiff)) { /*most significant*/
if (Math.abs(xDiff) > DIFF_TRASHOLD && timeDiff < TIME_TRASHOLD) {
if (xDiff > 0) {
// console.log(xDiff, TIME_TRASHOLD, DIFF_TRASHOLD)
SWIPE_LEFT(LEFT) /* left swipe */
} else {
// console.log(xDiff)
SWIPE_RIGHT(RIGHT) /* right swipe */
}
} else {
console.log('swipeX trashhold')
}
} else {
if (Math.abs(yDiff) > DIFF_TRASHOLD && timeDiff < TIME_TRASHOLD) {
if (yDiff > 0) {
/* up swipe */
} else {
/* down swipe */
}
} else {
console.log('swipeY trashhold')
}
}
/* reset values */
xDown = null;
yDown = null;
timeDown = null;
}
function containsClassName (evntarget , classArr) {
for (var i = classArr.length - 1; i >= 0; i--) {
if( evntarget.classList.contains(classArr[i]) ) {
return true;
}
}
}
function handleTouchStart(evt) {
let touchStartTarget = evt.target;
if( containsClassName(touchStartTarget, SWIPE_BLOCK_ELEMS) ) {
return;
}
timeDown = Date.now()
xDown = evt.touches[0].clientX;
yDown = evt.touches[0].clientY;
xDiff = 0;
yDiff = 0;
}
function handleTouchMove(evt) {
if (!xDown || !yDown) {
return;
}
var xUp = evt.touches[0].clientX;
var yUp = evt.touches[0].clientY;
xDiff = xDown - xUp;
yDiff = yDown - yUp;
}
Herkes Android'de jQuery Mobile kullanmaya çalışıyor ve JQM tokatlamak algılama ile ilgili sorunları varsa
(Xperia Z1, Galaxy S3, Nexus 4 ve bazı Wiko telefonlarda da vardı) bu yararlı olabilir:
//Fix swipe gesture on android
if(android){ //Your own device detection here
$.event.special.swipe.verticalDistanceThreshold = 500
$.event.special.swipe.horizontalDistanceThreshold = 10
}
Android üzerinde hızlıca kaydırma, çok uzun, kesin ve hızlı bir kaydırma olmadığı sürece algılanmadı.
Bu iki çizgi ile düzgün çalışıyor
$.event.special.swipe.scrollSupressionThreshold = 8;
ama sen beni doğru yöne koydun! Teşekkür ederim!
Kullanıcı parmağını sürüklerken touchend işleyicisi sürekli ateş ile sorun vardı. Bunun yanlış yaptığım bir şeyden kaynaklanıp kaynaklanmadığını bilmiyorum ama touchmove ile hareketleri biriktirmek için yeniden bağladım ve touchend aslında geri aramayı tetikliyor.
Ayrıca bu örneklerin çok sayıda olması gerekiyordu ve bu yüzden etkinleştirme / devre dışı bırakma yöntemleri ekledim.
Ve kısa bir tokatlamanın ateşlemediği bir eşik. Touchstart zero her seferinde sayaçlardır.
Target_node komutunu anında değiştirebilirsiniz. Oluşturmada etkinleştir isteğe bağlıdır.
/** Usage: */
touchevent = new Modules.TouchEventClass(callback, target_node);
touchevent.enable();
touchevent.disable();
/**
*
* Touch event module
*
* @param method set_target_mode
* @param method __touchstart
* @param method __touchmove
* @param method __touchend
* @param method enable
* @param method disable
* @param function callback
* @param node target_node
*/
Modules.TouchEventClass = class {
constructor(callback, target_node, enable=false) {
/** callback function */
this.callback = callback;
this.xdown = null;
this.ydown = null;
this.enabled = false;
this.target_node = null;
/** move point counts [left, right, up, down] */
this.counts = [];
this.set_target_node(target_node);
/** Enable on creation */
if (enable === true) {
this.enable();
}
}
/**
* Set or reset target node
*
* @param string/node target_node
* @param string enable (optional)
*/
set_target_node(target_node, enable=false) {
/** check if we're resetting target_node */
if (this.target_node !== null) {
/** remove old listener */
this.disable();
}
/** Support string id of node */
if (target_node.nodeName === undefined) {
target_node = document.getElementById(target_node);
}
this.target_node = target_node;
if (enable === true) {
this.enable();
}
}
/** enable listener */
enable() {
this.enabled = true;
this.target_node.addEventListener("touchstart", this.__touchstart.bind(this));
this.target_node.addEventListener("touchmove", this.__touchmove.bind(this));
this.target_node.addEventListener("touchend", this.__touchend.bind(this));
}
/** disable listener */
disable() {
this.enabled = false;
this.target_node.removeEventListener("touchstart", this.__touchstart);
this.target_node.removeEventListener("touchmove", this.__touchmove);
this.target_node.removeEventListener("touchend", this.__touchend);
}
/** Touchstart */
__touchstart(event) {
event.stopPropagation();
this.xdown = event.touches[0].clientX;
this.ydown = event.touches[0].clientY;
/** reset count of moves in each direction, [left, right, up, down] */
this.counts = [0, 0, 0, 0];
}
/** Touchend */
__touchend(event) {
let max_moves = Math.max(...this.counts);
if (max_moves > 500) { // set this threshold appropriately
/** swipe happened */
let index = this.counts.indexOf(max_moves);
if (index == 0) {
this.callback("left");
} else if (index == 1) {
this.callback("right");
} else if (index == 2) {
this.callback("up");
} else {
this.callback("down");
}
}
}
/** Touchmove */
__touchmove(event) {
event.stopPropagation();
if (! this.xdown || ! this.ydown) {
return;
}
let xup = event.touches[0].clientX;
let yup = event.touches[0].clientY;
let xdiff = this.xdown - xup;
let ydiff = this.ydown - yup;
/** Check x or y has greater distance */
if (Math.abs(xdiff) > Math.abs(ydiff)) {
if (xdiff > 0) {
this.counts[0] += Math.abs(xdiff);
} else {
this.counts[1] += Math.abs(xdiff);
}
} else {
if (ydiff > 0) {
this.counts[2] += Math.abs(ydiff);
} else {
this.counts[3] += Math.abs(ydiff);
}
}
}
}
Cevapların birçoğunu da birleştirdim, çoğunlukla birinci ve ikincisi sınıflarla birleştim ve işte benim versiyonum:
export default class Swipe {
constructor(options) {
this.xDown = null;
this.yDown = null;
this.options = options;
this.handleTouchStart = this.handleTouchStart.bind(this);
this.handleTouchMove = this.handleTouchMove.bind(this);
document.addEventListener('touchstart', this.handleTouchStart, false);
document.addEventListener('touchmove', this.handleTouchMove, false);
}
onLeft() {
this.options.onLeft();
}
onRight() {
this.options.onRight();
}
onUp() {
this.options.onUp();
}
onDown() {
this.options.onDown();
}
static getTouches(evt) {
return evt.touches // browser API
}
handleTouchStart(evt) {
const firstTouch = Swipe.getTouches(evt)[0];
this.xDown = firstTouch.clientX;
this.yDown = firstTouch.clientY;
}
handleTouchMove(evt) {
if ( ! this.xDown || ! this.yDown ) {
return;
}
let xUp = evt.touches[0].clientX;
let yUp = evt.touches[0].clientY;
let xDiff = this.xDown - xUp;
let yDiff = this.yDown - yUp;
if ( Math.abs( xDiff ) > Math.abs( yDiff ) ) {/*most significant*/
if ( xDiff > 0 && this.options.onLeft) {
/* left swipe */
this.onLeft();
} else if (this.options.onRight) {
/* right swipe */
this.onRight();
}
} else {
if ( yDiff > 0 && this.options.onUp) {
/* up swipe */
this.onUp();
} else if (this.options.onDown){
/* down swipe */
this.onDown();
}
}
/* reset values */
this.xDown = null;
this.yDown = null;
}
}
Daha sonra aşağıdaki gibi kullanabilirsiniz:
let swiper = new Swipe({
onLeft() {
console.log('You swiped left.');
}
});
Sadece "onLeft" yöntemini çağırmak istediğinizde konsol hatalarını önlemeye yardımcı olur.
İki kullanılır:
jQuery mobile: çoğu durumda ve özellikle diğer jQuery eklentisini kullanan uygulama geliştirirken, bunun için jQuery mobil kontrollerini kullanmak daha iyidir. Buradan ziyaret edin: https://www.w3schools.com/jquerymobile/jquerymobile_events_touch.asp
Çekiç süresi ! en iyi, hafif ve hızlı javascript tabanlı kütüphanelerden biridir. Buradan ziyaret edin: https://hammerjs.github.io/
Sadece tokatlamak gerekiyorsa, sadece ihtiyacınız olan kısmı kullanarak boyut akıllıca daha iyi. Bu, herhangi bir dokunmatik cihazda çalışmalıdır.
Bu gzip sıkıştırma, küçültme, babil vb. Sonra ~ 450 bayttır.
Aşağıdaki sınıfı diğer cevaplara göre yazdım, piksel yerine taşınan yüzdeyi ve bir şeyleri kancalamak / kancalarını kaldırmak için bir olay dağıtıcı desen kullanır.
Şöyle kullanın:
const dispatcher = new SwipeEventDispatcher(myElement);
dispatcher.on('SWIPE_RIGHT', () => { console.log('I swiped right!') })
export class SwipeEventDispatcher {
constructor(element, options = {}) {
this.evtMap = {
SWIPE_LEFT: [],
SWIPE_UP: [],
SWIPE_DOWN: [],
SWIPE_RIGHT: []
};
this.xDown = null;
this.yDown = null;
this.element = element;
this.options = Object.assign({ triggerPercent: 0.3 }, options);
element.addEventListener('touchstart', evt => this.handleTouchStart(evt), false);
element.addEventListener('touchend', evt => this.handleTouchEnd(evt), false);
}
on(evt, cb) {
this.evtMap[evt].push(cb);
}
off(evt, lcb) {
this.evtMap[evt] = this.evtMap[evt].filter(cb => cb !== lcb);
}
trigger(evt, data) {
this.evtMap[evt].map(handler => handler(data));
}
handleTouchStart(evt) {
this.xDown = evt.touches[0].clientX;
this.yDown = evt.touches[0].clientY;
}
handleTouchEnd(evt) {
const deltaX = evt.changedTouches[0].clientX - this.xDown;
const deltaY = evt.changedTouches[0].clientY - this.yDown;
const distMoved = Math.abs(Math.abs(deltaX) > Math.abs(deltaY) ? deltaX : deltaY);
const activePct = distMoved / this.element.offsetWidth;
if (activePct > this.options.triggerPercent) {
if (Math.abs(deltaX) > Math.abs(deltaY)) {
deltaX < 0 ? this.trigger('SWIPE_LEFT') : this.trigger('SWIPE_RIGHT');
} else {
deltaY > 0 ? this.trigger('SWIPE_UP') : this.trigger('SWIPE_DOWN');
}
}
}
}
export default SwipeEventDispatcher;
Yalnızca sola ve sağa hızlıca kaydırmayı algılamak istedim, ancak yalnızca dokunma olayı sona erdiğinde eylemi tetikledim , bu yüzden @ givanse'ın bunu yapmak için harika cevabını biraz değiştirdim.
Bunu neden yapmalı? Örneğin, kaydırırken, kullanıcı nihayet kaydırmak istemediğini fark ederse , parmağını orijinal konumuna (çok popüler bir "flört" telefon uygulaması bunu yapar;)) ve sonra "sağa kaydır" olay iptal edildi.
Bu nedenle, yatay olarak 3 piksellik bir fark olduğu için "sağa hızlıca kaydır" olayından kaçınmak için, altına bir olayın atıldığı bir eşik ekledim: "sağa hızlıca kaydır" etkinliğine sahip olmak için, kullanıcının en azından hızlıca kaydırması gerekir Tarayıcı genişliğinin 1 / 3'ü (elbette bunu değiştirebilirsiniz).
Tüm bu küçük ayrıntılar kullanıcı deneyimini geliştirir. İşte (Vanilla JS) kodu:
var xDown = null, yDown = null, xUp = null, yUp = null;
document.addEventListener('touchstart', touchstart, false);
document.addEventListener('touchmove', touchmove, false);
document.addEventListener('touchend', touchend, false);
function touchstart(evt) { const firstTouch = (evt.touches || evt.originalEvent.touches)[0]; xDown = firstTouch.clientX; yDown = firstTouch.clientY; }
function touchmove(evt) { if (!xDown || !yDown ) return; xUp = evt.touches[0].clientX; yUp = evt.touches[0].clientY; }
function touchend(evt) {
var xDiff = xUp - xDown, yDiff = yUp - yDown;
if ((Math.abs(xDiff) > Math.abs(yDiff)) && (Math.abs(xDiff) > 0.33 * document.body.clientWidth)) {
if (xDiff < 0)
document.getElementById('leftnav').click();
else
document.getElementById('rightnav').click();
}
xDown = null, yDown = null;
}
Yatay kaydırma için basit vanilya JS örneği:
let touchstartX = 0
let touchendX = 0
const slider = document.getElementById('slider')
function handleGesure() {
if (touchendX < touchstartX) alert('swiped left!')
if (touchendX > touchstartX) alert('swiped right!')
}
slider.addEventListener('touchstart', e => {
touchstartX = e.changedTouches[0].screenX
})
slider.addEventListener('touchend', e => {
touchendX = e.changedTouches[0].screenX
handleGesure()
})
Dikey kaydırma için aynı mantığı kullanabilirsiniz.
Bu yanıta burada ekliyoruz . Bu, masaüstünde test etmek için fare olayları için destek ekler:
<!--scripts-->
class SwipeEventDispatcher {
constructor(element, options = {}) {
this.evtMap = {
SWIPE_LEFT: [],
SWIPE_UP: [],
SWIPE_DOWN: [],
SWIPE_RIGHT: []
};
this.xDown = null;
this.yDown = null;
this.element = element;
this.isMouseDown = false;
this.listenForMouseEvents = true;
this.options = Object.assign({ triggerPercent: 0.3 }, options);
element.addEventListener('touchstart', evt => this.handleTouchStart(evt), false);
element.addEventListener('touchend', evt => this.handleTouchEnd(evt), false);
element.addEventListener('mousedown', evt => this.handleMouseDown(evt), false);
element.addEventListener('mouseup', evt => this.handleMouseUp(evt), false);
}
on(evt, cb) {
this.evtMap[evt].push(cb);
}
off(evt, lcb) {
this.evtMap[evt] = this.evtMap[evt].filter(cb => cb !== lcb);
}
trigger(evt, data) {
this.evtMap[evt].map(handler => handler(data));
}
handleTouchStart(evt) {
this.xDown = evt.touches[0].clientX;
this.yDown = evt.touches[0].clientY;
}
handleMouseDown(evt) {
if (this.listenForMouseEvents==false) return;
this.xDown = evt.clientX;
this.yDown = evt.clientY;
this.isMouseDown = true;
}
handleMouseUp(evt) {
if (this.isMouseDown == false) return;
const deltaX = evt.clientX - this.xDown;
const deltaY = evt.clientY - this.yDown;
const distMoved = Math.abs(Math.abs(deltaX) > Math.abs(deltaY) ? deltaX : deltaY);
const activePct = distMoved / this.element.offsetWidth;
if (activePct > this.options.triggerPercent) {
if (Math.abs(deltaX) > Math.abs(deltaY)) {
deltaX < 0 ? this.trigger('SWIPE_LEFT') : this.trigger('SWIPE_RIGHT');
} else {
deltaY > 0 ? this.trigger('SWIPE_UP') : this.trigger('SWIPE_DOWN');
}
}
}
handleTouchEnd(evt) {
const deltaX = evt.changedTouches[0].clientX - this.xDown;
const deltaY = evt.changedTouches[0].clientY - this.yDown;
const distMoved = Math.abs(Math.abs(deltaX) > Math.abs(deltaY) ? deltaX : deltaY);
const activePct = distMoved / this.element.offsetWidth;
if (activePct > this.options.triggerPercent) {
if (Math.abs(deltaX) > Math.abs(deltaY)) {
deltaX < 0 ? this.trigger('SWIPE_LEFT') : this.trigger('SWIPE_RIGHT');
} else {
deltaY > 0 ? this.trigger('SWIPE_UP') : this.trigger('SWIPE_DOWN');
}
}
}
}
// add a listener on load
window.addEventListener("load", function(event) {
const dispatcher = new SwipeEventDispatcher(document.body);
dispatcher.on('SWIPE_RIGHT', () => { console.log('I swiped right!') })
dispatcher.on('SWIPE_LEFT', () => { console.log('I swiped left!') })
});
Ofset ile nasıl kullanılacağına dair bir örnek.
// at least 100 px are a swipe
// you can use the value relative to screen size: window.innerWidth * .1
const offset = 100;
let xDown, yDown
window.addEventListener('touchstart', e => {
const firstTouch = getTouch(e);
xDown = firstTouch.clientX;
yDown = firstTouch.clientY;
});
window.addEventListener('touchend', e => {
if (!xDown || !yDown) {
return;
}
const {
clientX: xUp,
clientY: yUp
} = getTouch(e);
const xDiff = xDown - xUp;
const yDiff = yDown - yUp;
const xDiffAbs = Math.abs(xDown - xUp);
const yDiffAbs = Math.abs(yDown - yUp);
// at least <offset> are a swipe
if (Math.max(xDiffAbs, yDiffAbs) < offset ) {
return;
}
if (xDiffAbs > yDiffAbs) {
if ( xDiff > 0 ) {
console.log('left');
} else {
console.log('right');
}
} else {
if ( yDiff > 0 ) {
console.log('up');
} else {
console.log('down');
}
}
});
function getTouch (e) {
return e.changedTouches[0]
}
Prototip oluşturmak için önce fare olaylarıyla uygulamak daha kolay bir zamanınız olabilir.
Burada üst kısım dahil olmak üzere birçok cevap vardır, özellikle sınırlayıcı kutular etrafında kenar durumlarını dikkate almadığından dikkatli kullanılmalıdır.
Görmek:
Bitmeden önce öğenin dışına hareket eden işaretçi gibi kenar durumları ve davranışları yakalamak için denemeler yapmanız gerekir.
Kaydırma, ham olayları işleme ile el yazısı tanıma arasında kabaca oturan daha yüksek bir arabirim işaretçisi etkileşim işlemidir.
Bir tokatlamak veya fırlatmayı tespit etmek için tek bir kesin yöntem yoktur, ancak neredeyse hepsi genellikle bir öğe boyunca mesafe ve hız veya hız eşiği ile bir hareketi tespit etmek için temel bir prensibi takip eder. Belirli bir süre içinde belirli bir yönde ekran boyutunun% 65'i boyunca bir hareket varsa, o zaman bir kaydırma olduğunu söyleyebilirsiniz. Çizgiyi nerede çizdiğiniz ve nasıl hesapladığınız tam size bağlıdır.
Bazıları buna bir yöndeki momentum perspektifinden ve eleman bırakıldığında ekrandan ne kadar uzağa itildiğine de bakabilir. Bu, elemanın sürüklenebileceği yapışkan tomurcuklarla daha açıktır ve daha sonra serbest bırakıldığında elastik kırılmış gibi ekrandan geri döner veya ekrandan uçar.
Muhtemelen tutarlılık için yaygın olarak kullanılan port veya yeniden kullanabileceğiniz bir hareket kütüphanesi bulmaya çalışmak idealdir. Buradaki örneklerin çoğu aşırı derecede basittir ve bir tokatlamayı herhangi bir yöne en ufak bir dokunuş olarak kaydeder.
Android , tam tersi bir seçim olsa da, tam tersi bir sorun var, aşırı karmaşık.
Birçok insan soruyu bir yönde herhangi bir hareket olarak yanlış yorumlamış gibi görünüyor. Kaydırma, ezici bir şekilde tek bir yönde geniş ve nispeten kısa bir harekettir (gerçi olabilir ve belirli hızlanma özelliklerine sahip olabilir). Bir atış benzerdir, ancak bir öğeyi kendi momentumu altında adil bir mesafeden rasgele itmek niyetindedir.
İkisi, bazı kütüphanelerin yalnızca birbirinin yerine kullanılabilecek bir fırlatma veya kaydırma sağlaması için yeterince benzerdir. Düz bir ekranda iki hareketi gerçekten ayırmak zordur ve genellikle konuşan insanlar her ikisini de yapar (fiziksel ekranı kaydırmak, ancak ekranda görüntülenen UI öğesini fırlatmak).
En iyi seçenek kendiniz yapmamaktır. Basit hareketleri algılamak için çok sayıda JavaScript kitaplığı zaten var .
Tepki kancası işlevi görmek için @givanse'nin çözümünü elden geçirdim . Giriş isteğe bağlı bazı olay dinleyicileri, çıktı işlevsel bir ref (işlevsel olması gerekir, böylece ref değiştiğinde / değiştiğinde kanca yeniden çalışabilir).
Dikey / yatay kaydırma eşiği parametresinde de eklenir, böylece küçük hareketler olay dinleyicilerini yanlışlıkla tetiklemez, ancak orijinal yanıtı daha yakından taklit etmek için 0'a ayarlanabilir.
İpucu: en iyi performans için olay dinleyicisi giriş işlevleri not edilmelidir.
function useSwipeDetector({
// Event listeners.
onLeftSwipe,
onRightSwipe,
onUpSwipe,
onDownSwipe,
// Threshold to detect swipe.
verticalSwipeThreshold = 50,
horizontalSwipeThreshold = 30,
}) {
const [domRef, setDomRef] = useState(null);
const xDown = useRef(null);
const yDown = useRef(null);
useEffect(() => {
if (!domRef) {
return;
}
function handleTouchStart(evt) {
const [firstTouch] = evt.touches;
xDown.current = firstTouch.clientX;
yDown.current = firstTouch.clientY;
};
function handleTouchMove(evt) {
if (!xDown.current || !yDown.current) {
return;
}
const [firstTouch] = evt.touches;
const xUp = firstTouch.clientX;
const yUp = firstTouch.clientY;
const xDiff = xDown.current - xUp;
const yDiff = yDown.current - yUp;
if (Math.abs(xDiff) > Math.abs(yDiff)) {/*most significant*/
if (xDiff > horizontalSwipeThreshold) {
if (onRightSwipe) onRightSwipe();
} else if (xDiff < -horizontalSwipeThreshold) {
if (onLeftSwipe) onLeftSwipe();
}
} else {
if (yDiff > verticalSwipeThreshold) {
if (onUpSwipe) onUpSwipe();
} else if (yDiff < -verticalSwipeThreshold) {
if (onDownSwipe) onDownSwipe();
}
}
};
function handleTouchEnd() {
xDown.current = null;
yDown.current = null;
}
domRef.addEventListener("touchstart", handleTouchStart, false);
domRef.addEventListener("touchmove", handleTouchMove, false);
domRef.addEventListener("touchend", handleTouchEnd, false);
return () => {
domRef.removeEventListener("touchstart", handleTouchStart);
domRef.removeEventListener("touchmove", handleTouchMove);
domRef.removeEventListener("touchend", handleTouchEnd);
};
}, [domRef, onLeftSwipe, onRightSwipe, onUpSwipe, onDownSwipe, verticalSwipeThreshold, horizontalSwipeThreshold]);
return (ref) => setDomRef(ref);
};