滑动方向 判断

4 阅读1分钟
/**
 * 滑动方向检测器
 * @param {Object} options
 * @param {HTMLElement} [options.target=document.body] - 监听的目标元素
 * @param {number} [options.threshold=30] - 判定有效滑动的最小距离(像素)
 * @param {function} [options.onSwipe] - 回调函数 (direction: 'up' | 'down' | null)
 */
 function createSwipeDetector({ target = document.body, threshold = 30, onSwipe = null } = {}) {
  let startY = 0;
  let endY = 0;

  const handleTouchStart = (e) => {
    if (e.touches.length !== 1) return; // 只处理单指
    startY = e.touches[0].clientY;
    endY = startY;
  };

  const handleTouchMove = (e) => {
    if (e.touches.length !== 1) return;
    endY = e.touches[0].clientY;
    // 如果你后续需要阻止滚动,可以在这里加 e.preventDefault()
    // 注意:需确保 touchmove 监听器不是 passive 的
  };

  const handleTouchEnd = () => {
    const diff = endY - startY;
    let direction = null;

    if (diff > threshold) {
      direction = 'down';
    } else if (diff < -threshold) {
      direction = 'up';
    }

    if (onSwipe && direction) {
      onSwipe(direction);
    }
  };

  // 绑定事件(注意:touchmove 需要 passive: false 才能 preventDefault,但这里没用到,所以可设为 true 提升性能)
  // 如果未来要阻止默认行为(比如禁用页面滚动),请设 passive: false
  const optionsPassive = { passive: true };
  target.addEventListener('touchstart', handleTouchStart, optionsPassive);
  target.addEventListener('touchmove', handleTouchMove, { passive: false }); // 允许 preventDefault
  target.addEventListener('touchend', handleTouchEnd, optionsPassive);
  target.addEventListener('touchcancel', handleTouchEnd, optionsPassive);

  /**
   * 销毁监听器(用于手动清理)
   */
  const destroy = () => {
    target.removeEventListener('touchstart', handleTouchStart);
    target.removeEventListener('touchmove', handleTouchMove);
    target.removeEventListener('touchend', handleTouchEnd);
    target.removeEventListener('touchcancel', handleTouchEnd);
  };

  return { destroy };
}