如何检测用户使用JavaScript在网页上向某个方向滑动手指?
我想知道是否有一种解决方案适用于iPhone和Android手机上的网站。
答案 0 :(得分:285)
Simple vanilla 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 :(得分:42)
我发现这个jquery touchwipe插件适用于我的第一代ipod touch和我的机器人令人难以置信。 http://www.netcu.de/jquery-touchwipe-iphone-ipad-library
答案 2 :(得分:26)
根据@ givanse的回答,您可以使用classes
来完成此操作:
// 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();
你可以这样使用它:
public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
{
Type type = (Type)targetElement;
return type.GetMethods().Select(
m => return new AspectInstance(targetElement, new LogException()) );
}
答案 3 :(得分:18)
答案 4 :(得分:14)
我之前使用过的是你必须检测mousedown事件,记录它的x,y位置(以相关者为准)然后检测mouseup事件,然后减去这两个值。
答案 5 :(得分:13)
jQuery Mobile还包括滑动支持:http://api.jquerymobile.com/swipe/
实施例
$("#divId").on("swipe", function(event) {
alert("It's a swipe!");
});
答案 6 :(得分:9)
我将这里的一些答案合并到一个脚本中,该脚本使用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
上找到答案 7 :(得分:8)
我发现@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;
};
应该可以正常工作。
所以解决方案就变成了,
{{1}}
经过测试:
答案 8 :(得分:6)
我已将TouchWipe
重新打包为简短的jquery插件:detectSwipe
答案 9 :(得分:5)
处理短划线的一些最新答案(无法评论......)
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;
}
};
答案 10 :(得分:5)
trashold,超时滑动,swipeBlockElems添加。
--resolv-conf
答案 11 :(得分:4)
如果有人试图在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
}
除非它是一个非常长,精确和快速的滑动,否则不会检测到扫描到android。
使用这两行可以正常工作
答案 12 :(得分:3)
当用户拖动手指时,我遇到了touchend处理程序不断触发的问题。我不知道是否由于我做错了或不做错,但是我重新对此进行了重新设置以使用touchmove积累动作,并且touchend实际上会触发回调。
我还需要拥有大量这些实例,因此我添加了启用/禁用方法。
短暂滑动不会触发的阈值。 Touchstart每次都会将计数器归零。
您可以动态更改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);
}
}
}
}
答案 13 :(得分:2)
使用了两个:
jQuery mobile:在大多数情况下工作,特别是在开发使用其他jQuery插件的应用程序时,最好使用jQuery移动控件。请访问此处:https://www.w3schools.com/jquerymobile/jquerymobile_events_touch.asp
Hammer Time!最好,轻量级和快速的基于JavaScript的库之一。请访问此处:https://hammerjs.github.io/
答案 14 :(得分:1)
我只想检测左右滑动,但是仅在触摸事件结束 时才触发动作,因此我略微修改了@givanse的出色答案来做到这一点
为什么要这样做?例如,如果在滑动时用户发现他最终不想滑动,他可以将手指移动到原始位置(一种非常流行的“约会”电话应用程序会这样做),然后取消“向右滑动”事件。
因此,为了避免“向右滑动”事件,因为水平方向存在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;
}
答案 15 :(得分:1)
我重新制作了@givanse's solution以充当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);
};
答案 16 :(得分:0)
如果只需要滑动,则最好仅使用所需的部分来缩小尺寸。 这应该可以在任何触摸设备上使用。
这是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;
答案 17 :(得分:0)
有关如何使用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]
}
答案 18 :(得分:0)
我也合并了一些答案,主要是第一个和第二个答案与类,这是我的版本:
class ConnctFourMenuItemHanlder implements EventHandler<ActionEvent> {
@Override
public void handle(ActionEvent event) {
MenuItem item = (MenuItem) event.getSource();
if (item.equals(quit){
((Node)(event.getSource())).getScene().getWindow().hide();
}
}
随后可以按以下方式使用它:
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;
}
}
当您只想说“ onLeft”方法时,它有助于避免控制台错误。
答案 19 :(得分: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()
})
您可以对垂直滑动使用完全相同的逻辑。
答案 20 :(得分:0)
使用鼠标事件进行原型实现可能会更容易。
这里有很多答案,包括最上面的答案,应谨慎使用,因为它们不考虑边缘情况,尤其是在边界框周围。
请参阅:
您将需要尝试捕获一些极端情况和行为,例如指针在结束之前移到元素外部。
滑动是一种非常基本的手势,它是较高级别的界面指针交互处理,大致位于处理原始事件和手写识别之间。
尽管实际上所有方法通常都遵循检测距离和速度或速度的阈值的跨元素运动的基本原理,但是没有一种用于检测挥动或甩动的确切方法。您可能会简单地说,如果在给定时间内在给定方向上跨越屏幕尺寸的65%进行移动,那么它就是一次滑动。确切地在哪里画线以及如何计算这取决于您。
有些人可能还从某个方向的动量以及释放该元素时将其推离屏幕的距离的角度来查看它。使用粘性滑动可以更清楚地看到,可以拖动该元素,然后在释放时将弹回或弹起屏幕,就像松开橡皮筋一样。
尝试找到一个可以移植或重用通常用于保持一致性的手势库可能是理想的选择。这里的许多示例都过于简单化,将滑动记录为任何方向上的丝毫触感。
Mouse Events是显而易见的选择,尽管存在相反的问题,它过于复杂。
许多人似乎误解了这个问题,认为它是一个方向上的任何动作。滑动是在单个方向上压倒性的广泛且相对简短的运动(尽管可能是弧形的并且具有某些加速属性)。猛冲类似,尽管它打算根据自己的动力随意将物品推开一段相当的距离。
两者非常相似,以至于某些库可能只提供刷新或滑动,可以互换使用。在纯平屏幕上,很难真正地将这两个手势分开,并且一般来说人们都在做这两个手势(滑动物理屏幕,但猛冲屏幕上显示的UI元素)。
最好的选择是自己不要做。已经有Android。
答案 21 :(得分:0)
添加到此答案here。这增加了对鼠标事件的支持,以便在台式机上进行测试:
clsGetErros::clsGetErros(QString pstrDescTitulo, QString pstrFile, QString pstrFuncao, std::__exception_ptr::exception_ptr &pptrErro)
{
try
{
if(pptrErro != nullptr)
{
std::rethrow_exception(pptrErro); Erro Here !!!
}
}
catch(std::overflow_error &ex_erros_over)
{
clsGetErros::fcMsgBoxErros(pstrDescTitulo, pstrFile, pstrFuncao, "ERRO OVER FLOW", ex_erros_over.what());
}
catch(std::runtime_error &ex_erros_run)
{
clsGetErros::fcMsgBoxErros(pstrDescTitulo, pstrFile, pstrFuncao, "ERRO RUN TIME", ex_erros_run.what());
}
catch(std::bad_exception &ex_erros_bad_ex)
{
clsGetErros::fcMsgBoxErros(pstrDescTitulo, pstrFile, pstrFuncao, "ERRO BAD EXCEPTION", ex_erros_bad_ex.what());
}
catch(std::bad_alloc &ex_erros_bad_alloc)
{
clsGetErros::fcMsgBoxErros(pstrDescTitulo, pstrFile, pstrFuncao, "ERRO BAD EXCEPTION", ex_erros_bad_alloc.what());
}
}
答案 22 :(得分:0)
我不得不为轮播编写一个简单的脚本,以检测向左或向右滑动。
我使用了指针事件而不是触摸事件。
我希望这对个人有用,我欢迎任何能改进我的代码的见解;与相当出色的JS开发人员一起加入此线程,我感到有些sheep愧。
function getSwipeX({elementId}) {
this.e = document.getElementsByClassName(elementId)[0];
this.initialPosition = 0;
this.lastPosition = 0;
this.threshold = 200;
this.diffInPosition = null;
this.diffVsThreshold = null;
this.gestureState = 0;
this.getTouchStart = (event) => {
event.preventDefault();
if (window.PointerEvent) {
this.e.setPointerCapture(event.pointerId);
}
return this.initalTouchPos = this.getGesturePoint(event);
}
this.getTouchMove = (event) => {
event.preventDefault();
return this.lastPosition = this.getGesturePoint(event);
}
this.getTouchEnd = (event) => {
event.preventDefault();
if (window.PointerEvent) {
this.e.releasePointerCapture(event.pointerId);
}
this.doSomething();
this.initialPosition = 0;
}
this.getGesturePoint = (event) => {
this.point = event.pageX
return this.point;
}
this.whatGestureDirection = (event) => {
this.diffInPosition = this.initalTouchPos - this.lastPosition;
this.diffVsThreshold = Math.abs(this.diffInPosition) > this.threshold;
(Math.sign(this.diffInPosition) > 0) ? this.gestureState = 'L' : (Math.sign(this.diffInPosition) < 0) ? this.gestureState = 'R' : this.gestureState = 'N';
return [this.diffInPosition, this.diffVsThreshold, this.gestureState];
}
this.doSomething = (event) => {
let [gestureDelta,gestureThreshold,gestureDirection] = this.whatGestureDirection();
// USE THIS TO DEBUG
console.log(gestureDelta,gestureThreshold,gestureDirection);
if (gestureThreshold) {
(gestureDirection == 'L') ? // LEFT ACTION : // RIGHT ACTION
}
}
if (window.PointerEvent) {
this.e.addEventListener('pointerdown', this.getTouchStart, true);
this.e.addEventListener('pointermove', this.getTouchMove, true);
this.e.addEventListener('pointerup', this.getTouchEnd, true);
this.e.addEventListener('pointercancel', this.getTouchEnd, true);
}
}
您可以使用new调用该函数。
window.addEventListener('load', () => {
let test = new getSwipeX({
elementId: 'your_div_here'
});
})
答案 23 :(得分:0)
我重新编写了 @ruben-martinez answer 以使用来自@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);
}
我实现他的答案的主要挑战是不知道如何将滑动元素的 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:您可以将函数传递给钩子以接收滑动值。谢谢:) 喜欢就投票吧:)