桌面正常的拖拽跳转JS脚本,移动端链接触发失效求助
移动端拖拽元素内超链接无法跳转的修复方案
问题描述
实现了以下功能:
- 元素初始位置随机
- 支持桌面/移动端拖拽
- 桌面端点击元素内超链接可正常跳转,但移动端点击链接无反应
原始代码如下:
var startPosX = 0; var startPosY = 0; var isDragging = false; function setRandomPosition(mydiv) { var screenWidth = window.innerWidth; var screenHeight = window.innerHeight; var randomX = Math.floor(Math.random() * (screenWidth - mydiv.offsetWidth)); var randomY = Math.floor(Math.random() * (screenHeight - mydiv.offsetHeight)); mydiv.style.left = randomX + 'px'; mydiv.style.top = randomY + 'px'; } function startDrag(elmnt, clientX, clientY) { startPosX = clientX; startPosY = clientY; function elementDrag(e) { e.preventDefault(); var currentX = e.clientX || e.touches[0].clientX; var currentY = e.clientY || e.touches[0].clientY; var deltaX = startPosX - currentX; var deltaY = startPosY - currentY; startPosX = currentX; startPosY = currentY; elmnt.style.top = elmnt.offsetTop - deltaY + 'px'; elmnt.style.left = elmnt.offsetLeft - deltaX + 'px'; isDragging = true; } function stopDrag() { document.removeEventListener('mousemove', elementDrag); document.removeEventListener('mouseup', stopDrag); document.removeEventListener('touchmove', elementDrag); document.removeEventListener('touchend', stopDrag); setTimeout(function () { isDragging = false; }, 100); } document.addEventListener('mousemove', elementDrag); document.addEventListener('mouseup', stopDrag); document.addEventListener('touchmove', elementDrag, { passive: false }); document.addEventListener('touchend', stopDrag); } function dragElement(elmnt) { elmnt.addEventListener('mousedown', function (e) { e.preventDefault(); startDrag(elmnt, e.clientX, e.clientY); }); elmnt.addEventListener('touchstart', function (e) { e.preventDefault(); var touch = e.touches[0]; startDrag(elmnt, touch.clientX, touch.clientY); }); } // Call the function to set the random position initially var divs = document.getElementsByClassName('mydiv'); for (var i = 0; i < divs.length; i++) { setRandomPosition(divs[i]); dragElement(divs[i]); } // Add a click event listener to the elements with the href var links = document.querySelectorAll('.mydiv a'); for (var j = 0; j < links.length; j++) { links[j].addEventListener('click', function (e) { if (isDragging) { e.preventDefault(); } else { console.log("Element was clicked without dragging."); // Uncomment the next lines if you want to open the href link when not dragging // var href = this.getAttribute('href'); // if (href) { // window.location.href = href; // } } }); }
问题原因
touchstart事件中调用e.preventDefault()会直接阻止浏览器生成后续的click事件,导致链接的点击监听器完全无法触发。- 只要触发
elementDrag就标记为拖拽,微小的手指滑动也会被判定为拖拽,误阻止链接跳转。
修复后的代码
var startPosX = 0; var startPosY = 0; var isDragging = false; // 拖拽阈值:超过这个距离才判定为拖拽,避免误判点击 var DRAG_THRESHOLD = 5; function setRandomPosition(mydiv) { var screenWidth = window.innerWidth; var screenHeight = window.innerHeight; var randomX = Math.floor(Math.random() * (screenWidth - mydiv.offsetWidth)); var randomY = Math.floor(Math.random() * (screenHeight - mydiv.offsetHeight)); mydiv.style.left = randomX + 'px'; mydiv.style.top = randomY + 'px'; } function startDrag(elmnt, clientX, clientY) { startPosX = clientX; startPosY = clientY; // 记录初始触摸位置,用于判断是否触发拖拽 var initialX = clientX; var initialY = clientY; function elementDrag(e) { var currentX = e.clientX || e.touches[0].clientX; var currentY = e.clientY || e.touches[0].clientY; var deltaX = startPosX - currentX; var deltaY = startPosY - currentY; // 计算滑动距离,超过阈值才判定为拖拽 var distanceX = Math.abs(currentX - initialX); var distanceY = Math.abs(currentY - initialY); if (distanceX > DRAG_THRESHOLD || distanceY > DRAG_THRESHOLD) { isDragging = true; // 仅拖拽时阻止默认行为,不影响正常点击 e.preventDefault(); startPosX = currentX; startPosY = currentY; elmnt.style.top = elmnt.offsetTop - deltaY + 'px'; elmnt.style.left = elmnt.offsetLeft - deltaX + 'px'; } } function stopDrag() { document.removeEventListener('mousemove', elementDrag); document.removeEventListener('mouseup', stopDrag); document.removeEventListener('touchmove', elementDrag); document.removeEventListener('touchend', stopDrag); setTimeout(function () { isDragging = false; }, 100); } document.addEventListener('mousemove', elementDrag); document.addEventListener('mouseup', stopDrag); document.addEventListener('touchmove', elementDrag, { passive: false }); document.addEventListener('touchend', stopDrag); } function dragElement(elmnt) { elmnt.addEventListener('mousedown', function (e) { // mousedown时不阻止默认行为,避免影响右键菜单等功能 startDrag(elmnt, e.clientX, e.clientY); }); elmnt.addEventListener('touchstart', function (e) { // 移除touchstart的preventDefault,允许后续click事件正常触发 var touch = e.touches[0]; startDrag(elmnt, touch.clientX, touch.clientY); }); } // 初始化元素位置和拖拽功能 var divs = document.getElementsByClassName('mydiv'); for (var i = 0; i < divs.length; i++) { setRandomPosition(divs[i]); dragElement(divs[i]); } // 链接点击事件处理 var links = document.querySelectorAll('.mydiv a'); for (var j = 0; j < links.length; j++) { links[j].addEventListener('click', function (e) { if (isDragging) { e.preventDefault(); } else { console.log("Element was clicked without dragging."); // 启用链接跳转逻辑 var href = this.getAttribute('href'); if (href) { window.location.href = href; } } }); }
关键修改点
- 移除
touchstart里的e.preventDefault(),让移动端浏览器能正常生成click事件 - 添加拖拽阈值判断,只有滑动距离超过设定值才标记为拖拽,避免微小滑动误判
- 仅在确认拖拽行为时才调用
e.preventDefault(),不影响正常点击 - 启用链接跳转的代码逻辑,取消注释相关部分
内容的提问来源于stack exchange,提问作者Cedric
相关产品推荐
相关产品推荐

