사용자가 JavaScript를 사용하여 웹 페이지에서 손가락을 어느 방향으로 쓸어 내었다는 것을 어떻게 알 수 있습니까?
iPhone과 Android 전화 모두에서 웹 사이트에 사용할 수있는 솔루션이 하나 있는지 궁금합니다.
사용자가 JavaScript를 사용하여 웹 페이지에서 손가락을 어느 방향으로 쓸어 내었다는 것을 어떻게 알 수 있습니까?
iPhone과 Android 전화 모두에서 웹 사이트에 사용할 수있는 솔루션이 하나 있는지 궁금합니다.
답변:
간단한 바닐라 JS 코드 샘플 :
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
는 실제로 아무것도 반환하지 않았기 때문에 undefined 하지 않을 수 있습니다. 또한 함께 함수를 호출 할 때 바인딩 호출 쓸모 this.
가 이미 현재 컨텍스트에 바인딩 있기 때문에
.bind(this);
했는데 정상적으로 작동했습니다. 감사합니다 @nicholas_r
touches[0]
에 changedTouches[0]
이벤트 핸들러 유형 handleTouchMove
에를handleTouchEnd
run()
두 번 전화 하면 심한 메모리 누수가 발생합니다
여기에 몇 가지 답변을 CustomEvent 를 사용 하여 DOM에서 스 와이프 된 이벤트를 발생 시키는 스크립트로 병합했습니다 . 0.7k swiped-events.min.js 스크립트를 페이지에 추가하고 스 와이프 한 이벤트를 수신하십시오 .
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에서 사용할 수 있습니다
jQuery를 모바일도 슬쩍 지원을 포함합니다 : 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
. 답변을 업데이트하겠습니다. 감사! :)
TouchWipe
짧은 jquery 플러그인으로 다시 패키지 했습니다.detectSwipe
짧은 스 와이프를 처리하기위한 uppest 답변 (댓글을 달 수 없습니다 ...)의 일부 모드
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;
}
};
휴지통, 타임 아웃 스 와이프, 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;
}
누구나 Android에서 jQuery Mobile을 사용하려고하는데 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
}
길고 정확하며 빠른 스 와이프가 아니면 안드로이드에서 스 와이프가 감지되지 않았습니다.
이 두 줄로 올바르게 작동합니다
$.event.special.swipe.scrollSupressionThreshold = 8;
그러나 당신은 나를 올바른 방향으로 놓았다! 감사합니다!
사용자가 손가락을 드래그하는 동안 터치 엔드 핸들러가 계속 발사되는 데 문제가있었습니다. 그게 내가 잘못하고있는 일인지 아닌지 모르겠지만 touchmove와 함께 이동을 축적하기 위해 이것을 다시 배선하고 touchend는 실제로 콜백을 발생시킵니다.
또한 이러한 인스턴스가 많이 필요했기 때문에 활성화 / 비활성화 방법을 추가했습니다.
짧은 스 와이프가 실행되지 않는 임계 값입니다. Touchstart는 매번 카운터를 0으로 만듭니다.
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 모바일 컨트롤을 사용하는 것이 좋습니다. 여기를 방문하십시오 : https://www.w3schools.com/jquerymobile/jquerymobile_events_touch.asp
해머 타임! 가장 가볍고 빠른 자바 스크립트 기반 라이브러리 중 하나입니다. 여기를 방문하십시오 : https://hammerjs.github.io/
살짝 밀기 만하면 필요한 부분 만 사용하는 것이 현명합니다. 모든 터치 장치에서 작동합니다.
이것은 gzip 압축, 축소, babel 등 후 ~ 450 바이트입니다.
다른 답변을 기반으로 아래 클래스를 작성했습니다. 픽셀 대신 이동 비율과 이벤트 디스패처 패턴을 사용하여 사물을 연결 / 해제합니다.
다음과 같이 사용하십시오.
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의 큰 대답을 약간 수정했습니다.
왜 그렇게해야합니까? 예를 들어, 스 와이프하는 동안 사용자가 마지막으로 스 와이프하고 싶지 않다는 것을 알게 되면 손가락을 원래 위치로 움직일 수 있습니다 (매우 인기있는 "데이트"전화 응용 프로그램이이를 수행합니다)). 이벤트가 취소되었습니다.
따라서 가로로 3 픽셀의 차이가 있기 때문에 "오른쪽으로 스 와이프"이벤트를 피하기 위해 이벤트를 버리는 임계 값을 추가했습니다. "오른쪽으로 스 와이프"이벤트를 가지려면 사용자가 최소한 스 와이프해야합니다. 브라우저 너비의 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 %를 가로 질러 이동하는 경우 스 와이프라고 간단히 말할 수 있습니다. 정확하게 선을 그리는 위치와 계산 방법은 전적으로 귀하에게 달려 있습니다.
어떤 이들은 운동량의 관점에서 방향을보고 요소를 놓을 때 화면에서 얼마나 멀리 밀려 났는지 볼 수도 있습니다. 요소를 드래그 할 수있는 끈적 거리는 스 와이프를 사용하면 더 명확 해집니다.
일관성에 일반적으로 사용되는 포팅 또는 재사용이 가능한 제스처 라이브러리를 찾는 것이 이상적입니다. 여기의 많은 예제는 스 와이프를 어느 방향 으로든 가장 작은 터치로 등록하여 지나치게 단순합니다.
반대의 문제가 있지만 안드로이드 는 명백한 선택이 될 것입니다. 매우 복잡합니다.
많은 사람들이이 질문을 한 방향으로의 움직임으로 잘못 해석 한 것으로 보입니다. 스 와이프는 단일 방향으로 압도적으로 넓고 비교적 짧은 동작입니다 (아크가 있고 특정 가속 특성을 가질 수 있음). 플링은 비슷하지만 아이템을 자연스럽게 자신의 운동량 아래에서 공평한 거리로 밀어 내려고합니다.
두 라이브러리는 일부 라이브러리가 플링 또는 스 와이프 만 제공 할 수 있다는 점에서 충분히 유사합니다. 플랫 스크린에서는 두 제스처를 진정으로 분리하기가 어렵고 일반적으로 사람들이 두 가지 작업을 모두 수행하고 있습니다 (실제 스크린을 스 와이프하지만 화면에 표시된 UI 요소를 튕기는 경우).
가장 좋은 방법은 직접하지 않는 것입니다. 간단한 제스처를 감지하기위한 많은 수의 JavaScript 라이브러리 가 이미 있습니다 .
@givanse 의 솔루션을 재 작업 했습니다. 을 React 후크로 작동하도록 . 입력은 선택적인 이벤트 리스너이며 출력은 기능적인 참조입니다 (참조가 변경 될 때 후크가 재실행 될 수 있도록 기능적이어야 함).
또한 세로 / 가로 스 와이프 임계 값 매개 변수에 추가되어 작은 동작으로 인해 이벤트 리스너가 실수로 트리거되지는 않지만 원래 답변을 더 가깝게 모방하도록 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);
};