iPhone 및 Android에서 JavaScript를 통해 손가락 스 와이프 감지
사용자가 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에서 테스트되었습니다.
1 세대 아이팟 터치와 드로이드 모두에서 작동하는이 jquery touchwipe 플러그인을 발견했습니다. http://www.netcu.de/jquery-touchwipe-iphone-ipad-library
@ 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();
hammer.js를 사용해 보셨습니까? http://eightmedia.github.com/hammer.js/ Windows Phones에서도 작동합니다.
내가 전에 사용한 것은 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;
};
에 테스트 :
- 안드로이드 : 크롬, UC 브라우저
- iOS : Safari, Chrome, UC 브라우저
여기에 몇 가지 답변을 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에서 사용할 수 있습니다
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
}
길고 정확하며 빠른 스 와이프가 아니면 안드로이드에서 스 와이프가 감지되지 않았습니다.
이 두 줄로 올바르게 작동합니다
사용자가 손가락을 드래그하는 동안 터치 엔드 핸들러가 계속 발사되는 데 문제가있었습니다. 그게 내가 잘못하고있는 일인지 아닌지 모르겠지만 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);
}
}
}
}
사용 된 두 :
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;
나는 대부분의 답변을 클래스와 병합했으며 여기에 내 버전이 있습니다.
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"메소드 만 호출하려고 할 때 콘솔 오류를 피하는 데 도움이됩니다.
오프셋과 함께 사용하는 방법의 예입니다.
// 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]
}
가로 스 와이프에 대한 간단한 바닐라 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()
})
세로 스 와이프에는 거의 같은 논리를 사용할 수 있습니다.
마우스 이벤트로 프로토 타입을 작성하여 구현하는 것이 더 쉬울 것입니다.
상단을 포함하여 여기에 많은 답변이 있습니다. 특히 경계 상자 주변의 경우를 고려하지 않으므로주의해서 사용해야합니다.
보다:
종료하기 전에 포인터가 요소 외부로 이동하는 등의 경우와 동작을 잡으려고 실험해야합니다.
스 와이프는 기본 이벤트 처리와 필기 인식 사이에 대략적으로 위치한 상위 수준의 인터페이스 포인터 상호 작용 처리 인 매우 기본적인 제스처입니다.
스 와이프 또는 플링을 감지하는 정확한 방법은 하나도 없지만 사실상 거의 모두 거리와 속도 또는 속도의 임계 값으로 요소를 가로 지르는 동작을 감지하는 기본 원칙을 따릅니다. 주어진 시간 내에 주어진 방향으로 화면 크기의 65 %를 가로 질러 이동하면 스 와이프라고 간단히 말할 수 있습니다. 정확하게 선을 그리는 위치와 계산 방법은 전적으로 귀하에게 달려 있습니다.
어떤 이들은 운동량의 관점에서 방향을보고 요소를 놓을 때 화면에서 얼마나 멀리 밀려 났는지 볼 수도 있습니다. 요소를 드래그 할 수있는 끈적 거리는 스 와이프를 사용하면 더 명확 해집니다.
일관성에 일반적으로 사용되는 포팅 또는 재사용이 가능한 제스처 라이브러리를 찾는 것이 이상적입니다. 여기의 많은 예제는 스 와이프를 어느 방향 으로든 가장 작은 터치로 등록하여 지나치게 단순합니다.
반대의 문제가 있지만 안드로이드 는 명백한 선택이지만 지나치게 복잡합니다.
많은 사람들이이 질문을 한 방향으로의 움직임으로 잘못 해석 한 것으로 보입니다. 스 와이프는 단일 방향으로 압도적으로 넓고 비교적 짧은 동작입니다 (아크가 있고 특정 가속 특성을 가질 수 있음). 플링은 비슷하지만 아이템을 자연스럽게 자신의 운동량 아래에서 공평한 거리로 밀어냅니다.
두 라이브러리는 일부 라이브러리가 플링 또는 스 와이프 만 제공 할 수 있다는 점에서 유사합니다. 플랫 스크린에서는 두 제스처를 진정으로 분리하기가 어렵고 일반적으로 사람들이 두 가지 작업을 모두 수행하고 있습니다 (물리적 화면을 스 와이프하지만 화면에 표시된 UI 요소를 뒤집는 경우).
최선의 선택은 스스로하지 않는 것입니다. 간단한 제스처를 감지하기위한 많은 수의 JavaScript 라이브러리 가 이미 있습니다 .
'Programing' 카테고리의 다른 글
Web.config 변환을 사용하여 appSettings 섹션에서 속성 값을 변경하는 방법 (0) | 2020.04.08 |
---|---|
MySQL> 테이블이 존재하지 않습니다. (0) | 2020.04.08 |
GNU 화면에서 스크롤 휠 사용 (0) | 2020.04.08 |
특정 사용자의 그룹을 찾는 방법은 무엇입니까? (0) | 2020.04.08 |
목록에서 요소를 제거하려면 어떻게해야합니까? (0) | 2020.04.08 |