367

JavaScript を使用して、ユーザーが Web ページ上で指を何らかの方向にスワイプしたことをどのように検出できますか?

iPhone と Android フォンの両方の Web サイトで機能するソリューションが 1 つあるのではないかと考えていました。

4

23 に答える 23

57

ここでの回答のいくつかを、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
});

左にスワイプ

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>

アプリケーション全体のデフォルトを設定するには、最上位の要素に config 属性を設定します。

<body data-swipe-threshold="100" data-swipe-timeout="250">
    <div>Swipe me</div>
    <div>or me</div>
</body>

ソースコードはGithubで入手できます

于 2018-01-15T01:12:47.363 に答える
16

私が以前に使用したのは、mousedown イベントを検出し、その x、y 位置 (関連する方) を記録してから、mouseup イベントを検出し、2 つの値を減算する必要があるということです。

于 2010-02-15T04:52:58.157 に答える
15

jQuery Mobile にはスワイプのサポートも含まれています: http://api.jquerymobile.com/swipe/

$("#divId").on("swipe", function(event) {
    alert("It's a swipe!");
});
于 2012-11-26T15:52:11.487 に答える
11

短いスワイプに対処するための最高の回答のいくつかのモッド(コメントできません...)

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;
    }
};
于 2016-09-14T08:44:52.867 に答える
6

しきい値、タイムアウト スワイプ、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_THRESHOLD = 200;
const  DIFF_THRESHOLD = 130;

function handleTouchEnd() {

let timeDiff = Date.now() - timeDown; 
if (Math.abs(xDiff) > Math.abs(yDiff)) { /*most significant*/
  if (Math.abs(xDiff) > DIFF_THRESHOLD && timeDiff < TIME_THRESHOLD) {
    if (xDiff > 0) {
      // console.log(xDiff, TIME_THRESHOLD, DIFF_THRESHOLD)
      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_THRESHOLD && timeDiff < TIME_THRESHOLD) {
    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;
}
于 2016-11-25T07:56:16.637 に答える
2

@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);
};
于 2020-05-26T23:35:53.120 に答える
0

touchStart および touchEnd による処理:

var handleSwipe = function(elem,callbackOnRight, callbackOnLeft, callbackOnDown, 
      callbackOnUp) => {

        elem.ontouchstart = handleTouchStart;
        elem.ontouchend = handleTouchEnd;

        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 handleTouchEnd(evt) {
            if (!xDown || !yDown) {
                return;
            }

            var xUp = evt.changedTouches[0].clientX;
            var yUp = evt.changedTouches[0].clientY;

            var xDiff = xDown - xUp;
            var yDiff = yDown - yUp;
            var minDif = 30;

            console.log(`xDiff:${xDiff}, yDiff:${yDiff}`);

            if (Math.abs(xDiff) > Math.abs(yDiff)) {
                if (xDiff > minDif) {
                    if (callbackOnLeft)
                        callbackOnLeft();
                } else if (xDiff < -1 * minDif){
                    if (callbackOnRight)
                        callbackOnRight();
                }
            } else {
                if (yDiff > minDif) {
                    if (callbackOnDown)
                        callbackOnDown();
                } else if (yDiff < -1* minDif){
                    if (callbackOnUp)
                        callbackOnUp();
                }
            }
            
            xDown = null;
            yDown = null;
        };
    }
于 2021-12-11T13:01:02.333 に答える
0

左または右へのスワイプを検出するカルーセル用の簡単なスクリプトを作成する必要がありました。

Touch Events の代わりに Pointer Events を利用しました。

これが個人の役に立つことを願っています。コードを改善するための洞察を歓迎します。このスレッドに非常に優れた JS 開発者と一緒に参加するのは、かなり恥ずかしく思います。

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'
  });
})
于 2020-07-25T23:42:31.763 に答える