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

桌面正常的拖拽跳转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;
            // }
        }
    });
}

问题原因

  1. touchstart事件中调用e.preventDefault()会直接阻止浏览器生成后续的click事件,导致链接的点击监听器完全无法触发。
  2. 只要触发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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 11:25:16