Bagaimana Anda bisa mendeteksi bahwa pengguna menggesekkan jarinya ke suatu arah di atas halaman web dengan JavaScript?
Saya bertanya-tanya apakah ada satu solusi yang akan berfungsi untuk situs web di iPhone dan ponsel Android.
Bagaimana Anda bisa mendeteksi bahwa pengguna menggesekkan jarinya ke suatu arah di atas halaman web dengan JavaScript?
Saya bertanya-tanya apakah ada satu solusi yang akan berfungsi untuk situs web di iPhone dan ponsel Android.
Jawaban:
Contoh kode vanilla JS sederhana:
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;
};
Diuji di Android.
touchstart
, touchmove
?
Berdasarkan jawaban @ givanse, ini adalah bagaimana Anda dapat melakukannya dengan 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);
}
}
Anda dapat menggunakannya seperti ini:
// 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 karena Anda handleTouchMove
sebenarnya tidak mengembalikan apa pun. juga tidak ada gunanya untuk memanggil bind ketika memanggil fungsi dengan this.
karena sudah terikat dengan konteks saat ini
.bind(this);
dan itu bekerja dengan anggun. terima kasih @nicholas_r
touches[0]
ke changedTouches[0]
dan tipe event handler handleTouchMove
kehandleTouchEnd
run()
dua kali dan Anda mendapatkan kebocoran memori yang tidak menyenangkan
Saya menggabungkan beberapa jawaban di sini ke dalam skrip yang menggunakan CustomEvent untuk memecat acara yang digesek di DOM. Tambahkan skrip 0.7k swiped-events.min.js ke halaman Anda dan dengarkan acara swiped :
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
});
Anda juga dapat melampirkan langsung ke elemen:
document.getElementById('myBox').addEventListener('swiped-down', function(e) {
console.log(e.target); // the element that was swiped
});
Anda dapat menentukan atribut berikut untuk menyesuaikan bagaimana fungsi interaksi swipe di halaman Anda (ini adalah opsional) .
<div data-swipe-threshold="10"
data-swipe-timeout="1000"
data-swipe-ignore="false">
Swiper, get swiping!
</div>
Kode sumber tersedia di Github
apa yang saya gunakan sebelumnya adalah Anda harus mendeteksi acara mousedown, merekam lokasi x, y (mana yang relevan) kemudian mendeteksi acara mouseup, dan kurangi dua nilai.
jQuery Mobile juga mencakup dukungan swipe: http://api.jquerymobile.com/swipe/
Contoh
$("#divId").on("swipe", function(event) {
alert("It's a swipe!");
});
Saya telah menemukan jawaban brilian @givanse sebagai yang paling dapat diandalkan dan kompatibel di beberapa browser seluler untuk mendaftarkan tindakan gesek.
Namun, ada perubahan dalam kodenya yang diperlukan untuk membuatnya berfungsi di browser seluler modern yang menggunakan jQuery
.
event.touches
tidak akan ada jika jQuery
digunakan dan menghasilkan undefined
dan harus diganti oleh event.originalEvent.touches
. Tanpa jQuery
, event.touches
seharusnya bekerja dengan baik.
Jadi solusinya menjadi,
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;
};
Diuji pada:
event.originalEvent
. Masalahnya event.touches
sudah tidak ada lagi sekarang dan menghasilkan undefined
.
event.originalEvent
. Saya akan memperbarui jawaban saya. Terima kasih! :)
Saya telah dikemas ulang TouchWipe
sebagai plugin jquery pendek:detectSwipe
Beberapa mod jawaban uppest (tidak dapat mengomentari ...) untuk menangani gesekan singkat
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, sapuan timeout, tambahkan swipeBlockElems.
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;
}
Jika ada yang mencoba menggunakan jQuery Mobile di Android dan memiliki masalah dengan deteksi gesek JQM
(Saya punya beberapa di Xperia Z1, Galaxy S3, Nexus 4 dan beberapa telepon Wiko juga) ini bisa berguna:
//Fix swipe gesture on android
if(android){ //Your own device detection here
$.event.special.swipe.verticalDistanceThreshold = 500
$.event.special.swipe.horizontalDistanceThreshold = 10
}
Gesek pada android tidak terdeteksi kecuali itu gesekan yang sangat panjang, tepat dan cepat.
Dengan dua garis ini berfungsi dengan benar
$.event.special.swipe.scrollSupressionThreshold = 8;
tetapi Anda menempatkan saya di arah yang benar! Terima kasih!
Saya mengalami masalah dengan handler touchend menembak terus menerus sementara pengguna menyeret jari. Saya tidak tahu apakah itu karena sesuatu yang saya lakukan salah atau tidak, tetapi saya mengembalikan ini untuk mengumpulkan gerakan dengan touchmove dan touchend benar-benar memicu callback.
Saya juga perlu memiliki banyak contoh ini dan saya menambahkan metode aktifkan / nonaktifkan.
Dan ambang batas di mana gesekan singkat tidak menyala. Touchstart nol adalah penghitung setiap kali.
Anda dapat mengubah target_node dengan cepat. Mengaktifkan penciptaan adalah opsional.
/** 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);
}
}
}
}
Saya telah menggabungkan beberapa jawaban juga, sebagian besar yang pertama dan yang kedua dengan kelas, dan inilah versi saya:
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;
}
}
Setelah itu dapat menggunakannya sebagai berikut:
let swiper = new Swipe({
onLeft() {
console.log('You swiped left.');
}
});
Ini membantu untuk menghindari kesalahan konsol ketika Anda ingin memanggil hanya katakanlah metode "onLeft".
Digunakan dua:
jQuery mobile: bekerja di sebagian besar kasus dan khususnya ketika Anda sedang mengembangkan aplikasi yang menggunakan plugin jQuery lainnya maka lebih baik menggunakan kontrol jQuery mobile untuk ini. Kunjungi di sini: https://www.w3schools.com/jquerymobile/jquerymobile_events_touch.asp
Waktu palu! salah satu perpustakaan berbasis javascript terbaik, ringan dan cepat. Kunjungi di sini: https://hammerjs.github.io/
Jika Anda hanya perlu menggesek, Anda lebih baik dari ukuran bijaksana hanya menggunakan bagian yang Anda butuhkan. Ini harus bekerja pada perangkat sentuh apa pun.
Ini ~ 450 byte setelah kompresi gzip, minifikasi, babel dll.
Saya menulis kelas di bawah ini berdasarkan jawaban yang lain, menggunakan persentase yang dipindahkan alih-alih piksel, dan pola dispatcher acara untuk mengaitkan / melepas kaitan sesuatu.
Gunakan seperti ini:
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;
Saya ingin mendeteksi geser ke kiri dan kanan saja, tetapi memicu tindakan hanya ketika acara sentuh berakhir , jadi saya sedikit mengubah jawaban hebat @ givanse untuk melakukan itu.
Kenapa melakukan itu? Jika misalnya, saat menggesekkan, pengguna melihat ia akhirnya tidak ingin menggesek, ia dapat menggerakkan jarinya di posisi semula. (aplikasi telepon "kencan" yang sangat populer melakukan ini;)), dan kemudian "geser ke kanan" acara dibatalkan.
Jadi untuk menghindari peristiwa "gesek ke kanan" hanya karena ada perbedaan 3px secara horizontal, saya menambahkan ambang di mana peristiwa dibuang: untuk memiliki peristiwa "gesek ke kanan", pengguna harus menggesek setidaknya 1/3 dari lebar browser (tentu saja Anda dapat memodifikasi ini).
Semua detail kecil ini meningkatkan pengalaman pengguna. Berikut adalah kode (Vanilla JS):
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;
}
Contoh vanilla JS sederhana untuk sapuan horizontal:
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()
})
Anda dapat menggunakan logika yang hampir sama untuk sapuan vertikal.
Menambah jawaban ini di sini . Yang ini menambahkan dukungan untuk acara mouse untuk pengujian di desktop:
<!--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!') })
});
Saya mengerjakan ulang solusi @givanse agar berfungsi sebagai hook React. Input adalah beberapa pendengar acara opsional, output adalah ref fungsional (perlu fungsional sehingga kait dapat dijalankan kembali ketika / jika ref berubah).
Juga ditambahkan di param ambang geseran vertikal / horizontal, sehingga gerakan kecil tidak secara tidak sengaja memicu acara pendengar, tetapi ini dapat diatur ke 0 untuk meniru jawaban asli lebih dekat.
Kiat: untuk kinerja terbaik, fungsi input pendengar acara harus ditulis memo.
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);
};
Contoh cara menggunakan dengan offset.
// 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]
}
Anda mungkin memiliki waktu yang lebih mudah untuk menerapkannya terlebih dahulu dengan acara mouse ke prototipe.
Ada banyak jawaban di sini, termasuk bagian atas, harus digunakan dengan hati-hati karena mereka tidak mempertimbangkan kasus tepi terutama di sekitar kotak pembatas.
Lihat:
Anda perlu bereksperimen untuk menangkap kasus dan perilaku tepi seperti penunjuk yang bergerak di luar elemen sebelum berakhir.
Babatan adalah gerakan yang sangat dasar yang merupakan tingkat yang lebih tinggi dari pemrosesan interaksi penunjuk antarmuka kira-kira duduk antara memproses peristiwa mentah dan pengenalan tulisan tangan.
Tidak ada metode tunggal yang tepat untuk mendeteksi gesekan atau gesekan meskipun hampir semua umumnya mengikuti prinsip dasar mendeteksi gerakan melintasi elemen dengan ambang jarak dan kecepatan atau kecepatan. Anda mungkin hanya mengatakan bahwa jika ada gerakan melintasi 65% dari ukuran layar dalam arah tertentu dalam waktu tertentu maka itu adalah swipe. Tepat di mana Anda menggambar garis dan bagaimana Anda menghitungnya, itu terserah Anda.
Beberapa orang mungkin juga melihatnya dari perspektif momentum ke arah dan seberapa jauh dari layar telah didorong ketika elemen dilepaskan. Ini lebih jelas dengan gesekan lengket di mana elemen dapat diseret dan kemudian pada rilis akan bangkit kembali atau terbang dari layar seolah-olah elastis pecah.
Mungkin ideal untuk mencoba menemukan perpustakaan gerakan yang dapat Anda porting atau gunakan kembali yang biasa digunakan untuk konsistensi. Banyak contoh di sini terlalu sederhana, mendaftarkan gesekan sebagai sentuhan sedikit ke segala arah.
Android akan menjadi pilihan yang jelas meskipun memiliki masalah yang berlawanan, itu terlalu rumit.
Banyak orang tampaknya salah mengartikan pertanyaan itu sebagai gerakan ke arah mana pun. Babatan adalah gerakan yang luas dan relatif singkat yang sangat dalam satu arah (meskipun dapat melengkung dan memiliki sifat percepatan tertentu). Serupa adalah serupa meskipun bermaksud untuk dengan santai mendorong item jauh jarak yang adil di bawah momentumnya sendiri.
Keduanya cukup mirip bahwa beberapa perpustakaan hanya menyediakan fling atau swipe, yang dapat digunakan secara bergantian. Pada layar datar, sulit untuk benar-benar memisahkan kedua gerakan dan secara umum orang melakukan keduanya (menggesekkan layar fisik tetapi melemparkan elemen UI yang ditampilkan di layar).
Pilihan terbaik Anda adalah tidak melakukannya sendiri. Sudah ada banyak perpustakaan JavaScript untuk mendeteksi gerakan sederhana .