You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现拖拽容器与Thumb点击事件互斥,且兼容平板设备?

解决拖拽结束后触发点击事件的问题

核心思路是通过记录拖拽移动的距离区分"点击"和"拖拽"行为:当移动距离超过极小阈值(如5px)时判定为拖拽,阻止后续点击事件;反之则允许触发点击。以下是修改后的完整实现:

HTML(保持不变)

<div class="aplbox-thumb-container-wrap">
  <div class="aplbox-thumb-container" style="width: 1300px;">
    <div class="aplbox-thumb" data-id="0"></div>
    <div class="aplbox-thumb" data-id="1"></div>
    <div class="aplbox-thumb" data-id="2"></div>
    <div class="aplbox-thumb" data-id="3"></div>
    <div class="aplbox-thumb" data-id="4"></div>
    <div class="aplbox-thumb" data-id="5"></div>
    <div class="aplbox-thumb" data-id="6"></div>
    <div class="aplbox-thumb" data-id="7"></div>
    <div class="aplbox-thumb" data-id="8"></div>
    <div class="aplbox-thumb" data-id="9"></div>
    <div class="aplbox-thumb" data-id="10"></div>
    <div class="aplbox-thumb" data-id="11"></div>
  </div>
</div>

CSS(保持不变)

.aplbox-thumb-container-wrap {
  position: absolute;
  top: 0;
  left: 0;
  background-color: #ccc;
  width: 100%;
  height: 100px;
  overflow: hidden;
  box-sizing: border-box;
}

.aplbox-thumb-container {
  position: relative;
  padding: 5px 0;
  height: 100%;
  display: flex;
  flex-direction: row;
  transform: translateX(0);
  touch-action: none;
}

.aplbox-thumb {
  width: 100px;
  height: 70px;
  margin-right: 5px;
  box-sizing: border-box;
  background: #333;
  flex-shrink: 0;
  overflow: hidden;
  margin-bottom: 5px;
}

JavaScript(关键修改)

var thumbContainer = document.querySelector('.aplbox-thumb-container'),
  thumbContainerWrap = document.querySelector('.aplbox-thumb-container-wrap'),
  startXThumb,
  startTouchThumb,
  isDragged = false; // 新增:标记是否发生有效拖拽

if ("ontouchstart" in window) {
  thumbContainer.addEventListener("touchstart", dragStartThumb);
}
thumbContainer.addEventListener("mousedown", dragStartThumb);

function dragStartThumb(e) {
  if (e.preventDefault) e.preventDefault();
  e.stopPropagation();

  if (!startTouchThumb) {
    startTouchThumb = true;
    isDragged = false; // 重置拖拽标记

    document.addEventListener('mousemove', dragMoveThumb);
    document.addEventListener('mouseup', dragEndThumb);

    if ("ontouchstart" in window) {
      document.addEventListener('touchmove', dragMoveThumb);
      document.addEventListener('touchend', dragEndThumb);
    }

    var point;
    if (e.type === 'touchstart') {
      var touches = e.changedTouches;
      if (touches.length > 1) return false;
      point = touches[0];
      e.preventDefault();
    } else {
      point = e;
      e.preventDefault();
    }

    var currX = thumbContainer.style.transform.replace(/[^\d.-]/g, ''); // 修复:保留负号
    currX = parseInt(currX) || 0;

    startXThumb = point.pageX + currX;
  }
}

function dragMoveThumb(e) {
  if (startTouchThumb) {
    var point;
    if (e.type === 'touchmove') {
      var touches = e.changedTouches;
      if (touches.length > 1) return false;
      point = touches[0];
      e.preventDefault();
    } else {
      point = e;
      e.preventDefault();
    }

    var diff = point.pageX - startXThumb;
    // 移动距离超过5px则标记为拖拽
    if (Math.abs(diff) > 5) {
      isDragged = true;
    }

    if (diff > 0) diff = 0;
    else if (diff < -thumbContainer.offsetWidth + thumbContainerWrap.offsetWidth) {
      diff = -thumbContainer.offsetWidth + thumbContainerWrap.offsetWidth;
    }

    thumbContainer.style.transform = 'translateX(' + diff + 'px)';
  }
}

function dragEndThumb(e) {
  e.stopPropagation();

  if (startTouchThumb) {
    startTouchThumb = false;

    document.removeEventListener('mousemove', dragMoveThumb);
    document.removeEventListener('mouseup', dragEndThumb);

    if ("ontouchstart" in window) {
      document.removeEventListener('touchmove', dragMoveThumb);
      document.removeEventListener('touchend', dragEndThumb);
    }

    // 触摸设备:拖拽结束后阻止一次系统模拟的点击事件
    if (isDragged && e.type === 'touchend') {
      document.addEventListener('click', preventClickOnce, { once: true });
    }
  }
}

// 临时阻止一次点击事件
function preventClickOnce(e) {
  e.stopPropagation();
  e.preventDefault();
}

// click thumb
thumbContainerWrap.addEventListener('click', function(e) {
  // 若发生过拖拽则跳过点击逻辑
  if (isDragged) {
    isDragged = false; // 重置标记
    return;
  }

  if (e.target.closest('.aplbox-thumb')) {
    console.log('click');
  }
});

关键修改说明:

  1. 拖拽状态标记:新增isDragged变量记录是否发生有效拖拽(移动距离>5px)。
  2. 触摸设备兼容:在触摸结束时,临时添加一次性点击阻止器,避免系统自动触发的模拟点击。
  3. 点击事件过滤:点击触发时先判断拖拽状态,若为拖拽则直接返回,不执行点击逻辑。
  4. 正则修复:修正currX的正则表达式,保留负号以支持反向拖拽的正确计算。

内容的提问来源于stack exchange,提问作者Toniq

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 02:06:03