javascript 如何在React中识别swipe事件?

w41d8nur  于 2023-03-28  发布在  Java
关注(0)|答案(4)|浏览(138)

我目前正在开发一个React应用程序,我想检测div元素(在移动的设备上)上的滑动事件(左,右)。
如何在没有任何额外库的情况下实现这一点?

pxyaymoc

pxyaymoc1#

水平滑动(左、右)

此代码检测左右滑动事件,而不会对通常的触摸事件产生任何影响。

const [touchStart, setTouchStart] = useState(null)
const [touchEnd, setTouchEnd] = useState(null)

// the required distance between touchStart and touchEnd to be detected as a swipe
const minSwipeDistance = 50 

const onTouchStart = (e) => {
  setTouchEnd(null) // otherwise the swipe is fired even with usual touch events
  setTouchStart(e.targetTouches[0].clientX)
}

const onTouchMove = (e) => setTouchEnd(e.targetTouches[0].clientX)

const onTouchEnd = () => {
  if (!touchStart || !touchEnd) return
  const distance = touchStart - touchEnd
  const isLeftSwipe = distance > minSwipeDistance
  const isRightSwipe = distance < -minSwipeDistance
  if (isLeftSwipe || isRightSwipe) console.log('swipe', isLeftSwipe ? 'left' : 'right')
  // add your conditional logic here
}
<div onTouchStart={onTouchStart} onTouchMove={onTouchMove} onTouchEnd={onTouchEnd}/>

垂直滑动(上下)

如果您还需要检测垂直滑动(向上和向下),您可以以类似的方式使用e.targetTouches[0].clientY(请参阅docs)。

piztneat

piztneat2#

@gru的代码工作得很好,唯一的缺点是,当用户试图向下滚动时,它也会检测到滑动,并且也会稍微移动到侧面。
我的更改确保仅当水平移动大于垂直移动时才检测到滑动:

const distanceX = touchStartX - touchEndX
const distanceY = touchStartY - touchEndY
const isLeftSwipe = distanceX > minSwipeDistance
const isRightSwipe = distanceX < -minSwipeDistance

if (isRightSwipe && Math.abs(distanceX) > distanceY) {
  // add your conditional logic here
} 
if (isLeftSwipe && distanceX > distanceY) {
  // add your conditional logic here
}
htzpubme

htzpubme3#

@gru提供的优秀解决方案。我只是将其封装到一个自定义钩子中,以便更容易在不同组件之间集成。
useSwipe.tsx

import {TouchEvent, useState} from "react";

interface SwipeInput {
    onSwipedLeft: () => void
    onSwipedRight: () => void
}

interface SwipeOutput {
    onTouchStart: (e: TouchEvent) => void
    onTouchMove: (e: TouchEvent) => void
    onTouchEnd: () => void
}

export default (input: SwipeInput): SwipeOutput => {
    const [touchStart, setTouchStart] = useState(0);
    const [touchEnd, setTouchEnd] = useState(0);

    const minSwipeDistance = 50;

    const onTouchStart = (e: TouchEvent) => {
        setTouchEnd(0); // otherwise the swipe is fired even with usual touch events
        setTouchStart(e.targetTouches[0].clientX);
    }

    const onTouchMove = (e: TouchEvent) => setTouchEnd(e.targetTouches[0].clientX);

    const onTouchEnd = () => {
        if (!touchStart || !touchEnd) return;
        const distance = touchStart - touchEnd;
        const isLeftSwipe = distance > minSwipeDistance;
        const isRightSwipe = distance < -minSwipeDistance;
        if (isLeftSwipe) {
            input.onSwipedLeft();
        }
        if (isRightSwipe) {
            input.onSwipedRight();
        }
    }

    return {
        onTouchStart,
        onTouchMove,
        onTouchEnd
    }
}

可以像这样集成在不同的组件中

  1. import useSwipe from "whatever-path/useSwipe";
  2. const swipeHandlers = useSwipe({ onSwipedLeft: () => console.log('left'), onSwipedRight: () => console.log('right') });
  3. <div {...swipeHandlers}>some swipeable div (or whatever html tag)</div>
xurqigkl

xurqigkl4#

受dear gruanswer的启发,我将其改编为React Native。代码如下。(它会找到垂直距离,将pageY更改为pageX也会找到水平距离)

const [touchStart, setTouchStart] = useState(null);
  const [touchEnd, setTouchEnd] = useState(null);

  const minSwipeDistance = 50;

  const onTouchStart = (e) => {
    setTouchEnd(null);
    setTouchStart(e.nativeEvent.touches[0].pageY);
  }

  const onTouchMove = (e) => {
    setTouchEnd(e.nativeEvent.touches[0].pageY);
  }

  const onTouchEnd = () => {
    if (!touchStart || !touchEnd) return;
    if (touchStart - touchEnd > minSwipeDistance) {
      // Do something
    }
  }

<View onTouchStart={onTouchStart} onTouchMove={onTouchMove} onTouchEnd={onTouchEnd} >
...
</View>

相关问题