如何实现拖拽容器与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'); } });
关键修改说明:
- 拖拽状态标记:新增
isDragged变量记录是否发生有效拖拽(移动距离>5px)。 - 触摸设备兼容:在触摸结束时,临时添加一次性点击阻止器,避免系统自动触发的模拟点击。
- 点击事件过滤:点击触发时先判断拖拽状态,若为拖拽则直接返回,不执行点击逻辑。
- 正则修复:修正
currX的正则表达式,保留负号以支持反向拖拽的正确计算。
内容的提问来源于stack exchange,提问作者Toniq
相关产品推荐
相关产品推荐

