คุณจะตรวจจับได้อย่างไรว่าผู้ใช้รูดนิ้วไปในทิศทางใดทิศทางหนึ่งผ่านหน้าเว็บด้วย JavaScript
ฉันสงสัยว่ามีวิธีแก้ไขปัญหาเดียวที่สามารถใช้ได้กับเว็บไซต์ทั้ง iPhone และโทรศัพท์ Android หรือไม่
คุณจะตรวจจับได้อย่างไรว่าผู้ใช้รูดนิ้วไปในทิศทางใดทิศทางหนึ่งผ่านหน้าเว็บด้วย JavaScript
ฉันสงสัยว่ามีวิธีแก้ไขปัญหาเดียวที่สามารถใช้ได้กับเว็บไซต์ทั้ง iPhone และโทรศัพท์ Android หรือไม่
คำตอบ:
ตัวอย่างรหัสวานิลลาอย่างง่าย:
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
touchstart
, touchmove
?
ตามคำตอบของ @ givanse นี่คือวิธีที่คุณสามารถทำได้ด้วย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);
}
}
คุณสามารถใช้มันได้มากกว่านี้:
// 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
ไม่ได้กำหนดเนื่องจากคุณhandleTouchMove
ไม่ได้ส่งคืนอะไร นอกจากนี้ยังไม่มีประโยชน์ที่จะเรียกการผูกเมื่อเรียกฟังก์ชันด้วยthis.
เนื่องจากถูกผูกไว้กับบริบทปัจจุบันแล้ว
.bind(this);
และมันก็ทำงานได้อย่างสง่างาม ขอบคุณ @nicholas_r
touches[0]
เป็นchangedTouches[0]
และประเภทการจัดการเหตุการณ์handleTouchMove
เพื่อhandleTouchEnd
run()
สองครั้งและคุณจะได้รับการรั่วไหลของหน่วยความจำที่น่ารังเกียจ
ฉันรวมคำตอบบางส่วนที่นี่ลงในสคริปต์ที่ใช้CustomEventเพื่อเริ่มต้นเหตุการณ์ swiped ใน DOM เพิ่มสคริปต์swiped-events.min.js 0.7kลงในหน้าของคุณและฟังเหตุการณ์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
});
คุณยังสามารถแนบโดยตรงกับองค์ประกอบ:
document.getElementById('myBox').addEventListener('swiped-down', function(e) {
console.log(e.target); // the element that was swiped
});
คุณสามารถระบุแอตทริบิวต์ต่อไปนี้ในการปรับแต่งวิธีรูดปฏิสัมพันธ์ฟังก์ชั่นในหน้าเว็บของคุณ(เหล่านี้เป็นตัวเลือก)
<div data-swipe-threshold="10"
data-swipe-timeout="1000"
data-swipe-ignore="false">
Swiper, get swiping!
</div>
ซอร์สโค้ดมีอยู่ในGithub
สิ่งที่ฉันใช้ก่อนหน้านี้คือคุณต้องตรวจจับเหตุการณ์ mousedown บันทึกตำแหน่ง x, y (แล้วแต่จำนวนใดที่เกี่ยวข้อง) จากนั้นตรวจพบเหตุการณ์การวางเมาส์และลบค่าทั้งสอง
jQuery Mobile ยังรองรับการกวาดนิ้วด้วย: http://api.jquerymobile.com/swipe/
ตัวอย่าง
$("#divId").on("swipe", function(event) {
alert("It's a swipe!");
});
ฉันได้พบ @givanse คำตอบที่ยอดเยี่ยมว่าน่าเชื่อถือและเข้ากันได้กับเบราว์เซอร์มือถือหลาย ๆ ตัวสำหรับการลงทะเบียนการดำเนินการปัด
jQuery
แต่มีการเปลี่ยนแปลงในรหัสของเขาจำเป็นที่จะทำให้มันทำงานในเบราว์เซอร์มือถือที่ทันสมัยวันที่มีการใช้
event.touches
จะไม่อยู่ถ้าjQuery
มีการใช้และผลในและควรถูกแทนที่ด้วยundefined
event.originalEvent.touches
โดยไม่ต้องjQuery
, event.touches
ควรปรับการทำงาน
ดังนั้นการแก้ปัญหากลายเป็น
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;
};
ทดสอบเมื่อ:
event.originalEvent
เหตุการณ์สัมผัสถ้าได้รับการสนับสนุนโดยเบราเซอร์จะได้สัมผัสผ่าน สิ่งที่เป็นได้หยุดที่จะมีอยู่ในขณะนี้และผลในการevent.touches
undefined
event.originalEvent
การเปิดใช้งาน ฉันจะอัปเดตคำตอบของฉัน ขอบคุณ! :)
ฉันได้บรรจุใหม่TouchWipe
เป็นปลั๊กอิน jquery สั้น ๆ :detectSwipe
บางคำตอบที่ยอดเยี่ยม (ไม่สามารถแสดงความคิดเห็น ... ) เพื่อจัดการกับ swipes สั้น ๆ
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;
}
};
ถังขยะ, การหมดเวลากวาด, รูดเพิ่มล็อคเอ็มเอ็มเอ็ม
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;
}
หากใครพยายามใช้ jQuery Mobile บน Android และมีปัญหากับการตรวจจับการรูด JQM
(ฉันมีบางอย่างใน Xperia Z1, Galaxy S3, Nexus 4 และโทรศัพท์ Wiko บางรุ่นด้วย) สิ่งนี้มีประโยชน์:
//Fix swipe gesture on android
if(android){ //Your own device detection here
$.event.special.swipe.verticalDistanceThreshold = 500
$.event.special.swipe.horizontalDistanceThreshold = 10
}
การกวาดนิ้วบน Android ไม่ถูกตรวจพบเว้นเสียแต่ว่ามันจะยาวมากแม่นยำและรวดเร็ว
ด้วยสองบรรทัดนี้ทำงานอย่างถูกต้อง
$.event.special.swipe.scrollSupressionThreshold = 8;
แต่คุณทำให้ฉันไปในทิศทางที่ถูกต้อง! ขอบคุณ!
ฉันมีปัญหากับตัวจัดการ touchend ที่ยิงอย่างต่อเนื่องในขณะที่ผู้ใช้ลากนิ้วไปมา ฉันไม่รู้ว่าเป็นเพราะสิ่งที่ฉันทำผิดหรือเปล่า แต่ฉันต้องการสิ่งนี้อีกครั้งเพื่อสะสมการเคลื่อนไหวด้วย touchmove และ touchend จริง ๆ แล้วทำการโทรกลับ
ฉันต้องมีอินสแตนซ์เหล่านี้จำนวนมากด้วยดังนั้นฉันจึงเพิ่มวิธีเปิด / ปิดใช้งาน
และจุดเริ่มต้นที่การกวาดนิ้วสั้น ๆ ไม่ทำงาน Touchstart zero คือตัวนับแต่ละครั้ง
คุณสามารถเปลี่ยน target_node ได้ทันที เปิดใช้งานเมื่อสร้างเป็นตัวเลือก
/** 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);
}
}
}
}
ฉันได้รวมคำตอบบางส่วนเข้าด้วยแล้วส่วนใหญ่เป็นคำตอบแรกและคำที่สองในชั้นเรียนและนี่คือเวอร์ชันของฉัน:
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;
}
}
หลังจากนั้นสามารถใช้งานได้ดังต่อไปนี้:
let swiper = new Swipe({
onLeft() {
console.log('You swiped left.');
}
});
มันจะช่วยหลีกเลี่ยงข้อผิดพลาดของคอนโซลเมื่อคุณต้องการโทรเพียงแค่ใช้วิธี "onLeft" เท่านั้น
ใช้สอง:
jQuery mobile:ทำงานในกรณีส่วนใหญ่และเป็นพิเศษเมื่อคุณพัฒนาแอพพลิเคชั่นซึ่งใช้ปลั๊กอิน jQuery อื่น ๆ และควรใช้ jQuery mobile control สำหรับเรื่องนี้ดีกว่า เยี่ยมชมได้ที่นี่: https://www.w3schools.com/jquerymobile/jquerymobile_events_touch.asp
ค้อนเวลา! หนึ่งในห้องสมุดที่ดีที่สุดน้ำหนักเบาและรวดเร็วจาวาสคริปต์ เยี่ยมชมได้ที่นี่: https://hammerjs.github.io/
หากคุณต้องการรูดเพียงอย่างเดียวคุณก็ควรเลือกใช้เฉพาะส่วนที่คุณต้องการ สิ่งนี้ควรใช้กับอุปกรณ์ระบบสัมผัส
นี่คือ ~ 450 bytes 'หลังจากการบีบอัด gzip, minification, babel เป็นต้น
ฉันเขียนคลาสด้านล่างตามคำตอบอื่น ๆ โดยใช้เปอร์เซ็นต์ย้ายแทนพิกเซลและรูปแบบโปรแกรมเลือกจ่ายงานกิจกรรมเพื่อเชื่อมต่อ / ถอดสิ่งต่างๆ
ใช้มันอย่างนั้น:
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;
ฉันต้องการตรวจจับการปัดซ้ายและขวาเท่านั้น แต่กระตุ้นการทำงานเฉพาะเมื่อเหตุการณ์การสัมผัสสิ้นสุดลงดังนั้นฉันจึงปรับเปลี่ยนเล็กน้อยคำตอบที่ยอดเยี่ยมของ @ givanse ในการทำเช่นนั้น
ทำไมต้องทำเช่นนั้น? ตัวอย่างเช่นในขณะที่ปัดผู้ใช้สังเกตเห็นว่าเขาไม่ต้องการรูดในที่สุดเขาสามารถเลื่อนนิ้วของเขาไปที่ตำแหน่งเดิม (แอพพลิเคชั่นโทรศัพท์ "dating" ที่เป็นที่นิยมมากทำเช่นนี้;)) และจากนั้น กิจกรรมถูกยกเลิก
ดังนั้นเพื่อหลีกเลี่ยงเหตุการณ์ "การปัดนิ้วที่ถูกต้อง" เพียงเพราะมีความแตกต่างในแนวนอน 3px ฉันได้เพิ่มขีด จำกัด ที่เหตุการณ์ถูกยกเลิก: เพื่อให้มีเหตุการณ์ "การกวาดนิ้วที่ถูกต้อง" ผู้ใช้จะต้องปัดอย่างน้อย 1/3 ของความกว้างของเบราว์เซอร์ (แน่นอนว่าคุณสามารถแก้ไขได้)
รายละเอียดเล็ก ๆ เหล่านี้ช่วยยกระดับประสบการณ์ผู้ใช้ นี่คือรหัส (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;
}
ตัวอย่างง่ายๆของวานิลลา JS สำหรับการกวาดในแนวนอน:
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()
})
คุณสามารถใช้ตรรกะเดียวกันสวยในการกวาดแนวตั้ง
การเพิ่มคำตอบนี้ที่นี่ อันนี้เพิ่มการสนับสนุนสำหรับเหตุการณ์เมาส์สำหรับการทดสอบบนเดสก์ท็อป:
<!--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!') })
});
ตัวอย่างของวิธีใช้กับออฟเซ็ต
// 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]
}
คุณอาจมีเวลาง่ายขึ้นก่อนที่จะใช้มันกับเหตุการณ์เมาส์เพื่อต้นแบบ
มีคำตอบมากมายที่นี่รวมถึงด้านบนควรใช้ด้วยความระมัดระวังเนื่องจากพวกเขาไม่ได้พิจารณากรณีขอบโดยเฉพาะรอบ ๆ กล่องที่มีขอบ
ดู:
คุณจะต้องทำการทดลองเพื่อตรวจจับเคสและพฤติกรรมเช่นตัวชี้ที่เคลื่อนไหวนอกองค์ประกอบก่อนสิ้นสุด
การกวาดนิ้วเป็นท่าทางขั้นพื้นฐานซึ่งเป็นระดับที่สูงขึ้นของการโต้ตอบกับตัวชี้ส่วนต่อประสานระหว่างการประมวลผลเหตุการณ์ดิบและการรู้จำลายมือ
ไม่มีวิธีการที่แน่นอนเพียงวิธีเดียวในการตรวจจับการปัดหรือการเหวี่ยงแม้ว่าโดยทั่วไปแล้วทั้งหมดจะทำตามหลักการพื้นฐานของการตรวจจับการเคลื่อนไหวในองค์ประกอบที่มีขีด จำกัด ของระยะทางและความเร็วหรือความเร็ว คุณอาจพูดง่ายๆว่าหากมีการเคลื่อนไหวข้าม 65% ของขนาดหน้าจอในทิศทางที่กำหนดภายในเวลาที่กำหนดมันจะเป็นการปัด ตรงที่คุณวาดเส้นและวิธีการคำนวณขึ้นอยู่กับคุณ
บางคนอาจมองจากมุมมองของโมเมนตัมในทิศทางและระยะห่างจากหน้าจอเมื่อผลักองค์ประกอบออกไป นี่คือชัดเจนด้วย swipes เหนียวที่องค์ประกอบสามารถลากและจากนั้นปล่อยจะเด้งกลับหรือบินออกจากหน้าจอราวกับว่ายืดหยุ่นแตก
อาจเป็นวิธีที่ดีในการพยายามค้นหาไลบรารีท่าทางสัมผัสที่คุณสามารถใช้พอร์ตหรือนำมาใช้ซ้ำซึ่งมักใช้เพื่อความมั่นคง ตัวอย่างจำนวนมากที่นี่เรียบง่ายมากเกินไปการลงทะเบียนปัดเป็นการสัมผัสที่น้อยที่สุดในทุกทิศทาง
Androidจะเป็นตัวเลือกที่ชัดเจนแม้ว่าจะมีปัญหาตรงกันข้ามมันซับซ้อนเกินไป
หลายคนดูเหมือนจะตีความคำถามผิด ๆ ว่าเป็นการเคลื่อนไหวในทิศทางใด การปัดนิ้วนั้นเป็นการเคลื่อนไหวที่กว้างและสั้น ๆ อย่างท่วมท้นในทิศทางเดียว การพุ่งนั้นคล้ายกัน แต่ตั้งใจที่จะขับสิ่งของออกไปในระยะที่พอเหมาะภายใต้โมเมนตัมของมัน
ทั้งสองมีความคล้ายคลึงกันพอสมควรที่ห้องสมุดบางแห่งอาจจัดเตรียมแบบปัดหรือปัดซึ่งสามารถใช้แทนกันได้ บนหน้าจอแบนเป็นการยากที่จะแยกท่าทางทั้งสองออกจากกันอย่างแท้จริงและผู้คนกำลังพูดกันว่ากำลังทำทั้งสองอย่างอยู่ (การปัดหน้าจอทางกายภาพ แต่โยนองค์ประกอบ UI ที่แสดงบนหน้าจอ)
ตัวเลือกที่ดีที่สุดของคุณคืออย่าทำเอง มีอยู่เป็นจำนวนมากของห้องสมุด JavaScript สำหรับการตรวจจับท่าทางที่เรียบง่าย
ฉันทำใหม่โซลูชันของ@givanseเพื่อใช้เป็น React hook อินพุตเป็นผู้ฟังเหตุการณ์ที่เป็นตัวเลือกเอาต์พุตคือการอ้างอิงการทำงาน (ต้องใช้งานได้ดังนั้นตะขอสามารถเรียกใช้อีกครั้งเมื่อ / หากการอ้างอิงเปลี่ยนไป)
นอกจากนี้ยังมีการเพิ่มใน param threshold การปัดแบบแนวตั้ง / แนวนอนเพื่อให้การเคลื่อนไหวขนาดเล็กไม่ได้ตั้งใจให้ผู้ฟังเหตุการณ์เกิดเหตุการณ์ขึ้นโดยบังเอิญ แต่สิ่งเหล่านี้สามารถตั้งค่าเป็น 0 เพื่อเลียนแบบคำตอบดั้งเดิมได้ใกล้ชิด
เคล็ดลับ:เพื่อประสิทธิภาพที่ดีที่สุดฟังก์ชันอินพุตฟังเหตุการณ์ควรได้รับการจดบันทึก
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);
};