如何检测用户用JavaScript在网页上向某个方向滑动手指?
我想知道是否有一种解决方案可以同时适用于iPhone和Android手机上的网站。
如何检测用户用JavaScript在网页上向某个方向滑动手指?
我想知道是否有一种解决方案可以同时适用于iPhone和Android手机上的网站。
当前回答
简单的水平滑动JS示例:
let touchstartX = 0
let touchendX = 0
function checkDirection() {
if (touchendX < touchstartX) alert('swiped left!')
if (touchendX > touchstartX) alert('swiped right!')
}
document.addEventListener('touchstart', e => {
touchstartX = e.changedTouches[0].screenX
})
document.addEventListener('touchend', e => {
touchendX = e.changedTouches[0].screenX
checkDirection()
})
垂直滑动也可以使用相同的逻辑。
其他回答
我之前使用的方法是,您必须检测mousedown事件,记录其x,y位置(任何相关的位置),然后检测mouseup事件,并减去两个值。
我重做了@ruben-martinez的答案,使用来自@givanse的惊人的解决方案,使用自定义反应钩子处理滑动事件。
import React, { useEffect, useRef, useState } from "react";
export default function useSwiper() {
const [domRef, setDomRef] = useState<any>();
const xDown: React.MutableRefObject<number | null> = useRef(null);
const yDown: React.MutableRefObject<number | null> = useRef(null);
useEffect(() => {
if (!domRef) return;
function getTouches(event: React.TouchEvent<HTMLDivElement>) {
return event.touches;
}
function handleTouchStart(event: any) {
const firstTouch = getTouches(event)[0];
xDown.current = firstTouch.clientX;
yDown.current = firstTouch.clientY;
}
function handleTouchMove(event: React.TouchEvent<HTMLDivElement>) {
if (!xDown.current || !yDown.current) return;
const firstTouch = getTouches(event)[0];
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)) {
// handle horizontal swipes
if (xDiff > 0) {
// we swiped right
console.log("right");
} else {
// we swiped left
console.log("left");
}
} else {
// handle vertical swipes
if (yDiff > 0) {
// we swiped down
console.log("down");
} else {
// we swiped up
console.log("up");
}
}
}
function handleTouchEnd(event: React.TouchEvent<HTMLDivElement>) {
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, false);
domRef.removeEventListener("touchmove", handleTouchMove, false);
domRef.removeEventListener("touchend", handleTouchEnd, false);
};
}, [domRef]);
return (ref: any) => setDomRef(ref);
}
我在实现他的答案时遇到的主要挑战是不知道如何将swipe元素的ref绑定到自定义钩子中的ref。
基本上,所发生的是我们从自定义钩子返回一个函数。这个函数允许我们传入一个来自我们想要监听的滑动动作的元素的ref。自定义钩子接收到ref后,用元素的ref更新钩子状态,从而触发重新渲染,这样我们就有了实际的元素!
这种函数式的ref样式还允许我们对多个元素使用钩子。如下所示,我想使用它的项目列表,以启用滑动删除:)
import useSwiper from "./hooks/useSwipe";
const EntryCard = ({ entry, godMode, reload }: EntryProps) => {
const swiperRef = useSwiper();
const handleEntryClick =
(entry: Entry) => async (event: React.MouseEvent<HTMLDivElement>) => {
if (!godMode) return;
try {
reload((state) => !state);
} catch (err) {
console.log("Error deleting entry: ", err);
}
};
return (
<div className="item" onClick={handleEntryClick(entry)} ref={swiperRef}>
<div className="username">{entry.userName}</div>
<div className="score">{entry.weekScore}</div>
</div>
);
};
PS:你可以把函数传递给钩子来接收滑动值。谢谢:)如果你喜欢,请投票:)
我将这里的一些答案合并到一个脚本中,该脚本使用CustomEvent在DOM中触发滑动事件。添加0.7k的swiped-events.min.js脚本到你的页面,并监听滑动事件:
刷卡
document.addEventListener('swiped', function(e) {
console.log(e.target); // the element that was swiped
console.log(e.detail.dir); // swiped direction
});
swiped-left
document.addEventListener('swiped-left', function(e) {
console.log(e.target); // the element that was swiped
});
swiped-right
document.addEventListener('swiped-right', function(e) {
console.log(e.target); // the element that was swiped
});
swiped-up
document.addEventListener('swiped-up', function(e) {
console.log(e.target); // the element that was swiped
});
swiped-down
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>
要在应用程序范围内设置默认值,请在最顶部的元素上设置配置属性:
<body data-swipe-threshold="100" data-swipe-timeout="250">
<div>Swipe me</div>
<div>or me</div>
</body>
源代码可在Github
jQuery Mobile还包括滑动支持:http://api.jquerymobile.com/swipe/
例子
$("#divId").on("swipe", function(event) {
alert("It's a swipe!");
});
根据@givanse的回答,以下是你可以用类来做的:
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();