JavaScript实现拖拽效果:原理、兼容性与边界碰撞处理

作者:木棉

时间:2026-10-24

浏览:587

本文详解JavaScript实现拖拽效果的完整流程,涵盖鼠标按下、移动与抬起的事件绑定逻辑。针对IE低版本浏览器默认行为冲突,介绍setCapture全局捕获方案。同时解析可视区域边界限制及基于坐标临界值的物体碰撞检测算法,提供核心代码逻辑与实现细节。

文章目录

本文分享利用JavaScript实现拖拽交互的具体代码示例,供读者参考学习。

1.1 拖拽的基本效果

实现思路如下:

当鼠标在目标元素上按下时,触发移动准备动作(事件绑定至该元素)。

鼠标在页面上移动时,目标元素跟随鼠标位置进行位移(事件绑定至页面)。

当鼠标抬起时,目标元素停止移动(事件绑定至页面)。


var o = document.querySelector('div');
​
        //鼠标按下
        o.onmousedown = function (e) {
            //鼠标相对于盒子的位置
            var offsetX = e.clientX - o.offsetLeft;
            var offsetY = e.clientY - o.offsetTop;
            //鼠标移动
            document.onmousemove = function (e) {
                o.style.left = e.clientX - offsetX + "px";
                o.style.top = e.clientY - offsetY + "px";
            }
            //鼠标抬起
            document.onmouseup = function () {
                document.onmousemove = null;
                document.onmouseup = null;
            }
}

1.2 拖拽中可能遇到的问题

若元素内部包含文本或图片,浏览器默认允许拖拽这些媒体内容,导致交互冲突。通常可通过设置return false来拦截默认行为,但在低版本IE浏览器中此方法无效。此时,可采用全局捕获机制来解决IE兼容性问题。

1.2.1 全局捕获

全局捕获机制仅适用于低版本IE浏览器。


<button>btn1</button>
    <button>btn2</button>
    <script>
        var bts = document.querySelectorAll('button')
​
        bts[0].onclick = function () {
            console.log(1);
        }
        bts[1].onclick = function () {
            console.log(2);
        }
​
        // bts[0].setCapture()  //添加全局捕获
        // bts[0].releaseCapture() ;//释放全局捕获
</script>

一旦为指定节点启用全局捕获,页面中其他元素将不再触发同类事件。

1.2.2 完整版的拖拽实现


var o = document.querySelector('div');
​
        //鼠标按下
        o.onmousedown = function (e) {
            if (o.setCapture) {   //IE低版本
                o.setCapture()
            }
            e = e || window.event
            //鼠标相对于盒子的位置
            var offsetX = e.clientX - o.offsetLeft;
            var offsetY = e.clientY - o.offsetTop;
            //鼠标移动
            document.onmousemove = function (e) {
                e = e || window.event
                o.style.left = e.clientX - offsetX + "px";
                o.style.top = e.clientY - offsetY + "px";
            }
            //鼠标抬起
            document.onmouseup = function () {
                document.onmousemove = null;
                document.onmouseup = null;
                if (o.releaseCapture) {
                    o.releaseCapture();//释放全局捕获   
                }
            }
            return false;//标准浏览器的默认行为
        }

1.3 拖拽边界限制

可视区域宽度获取方式:

可视区域高度获取方式:


//屏幕的高度
// var h=document.documentElement.clientHeight
// var w=document.documentElement.clientWidth;


// console.log(h,w);

逻辑分析如下:

元素最大left值等于可视区域宽度减去元素自身宽度。

元素最小left值为0。

元素最小top值为0。

元素最大top值等于可视区域高度减去元素自身高度。

1.4 碰撞检测

碰撞检测的核心在于确定坐标临界值。

1.1 拖拽的基本效果 

将两个物体的四条边分别标记为:L1, T1, R1, B1 和 L2, T2, R2, B2。

若满足 L1 > R2 或 T1 > B2 或 R1 < L2 或 B1 < T2,则判定为未发生碰撞。


<div class="one">
​
    </div>
    <div class="two"></div>
    <script>
        var o = document.querySelector('.one');
        var ox = document.querySelector('.two');
​
        //鼠标按下
        o.onmousedown = function (e) {
            if (o.setCapture) {   //IE低版本
                o.setCapture()
            }
            e = e || window.event
            //鼠标相对于盒子的位置
            var offsetX = e.clientX - o.offsetLeft;
            var offsetY = e.clientY - o.offsetTop;
            //计算最大左边距和上边距(边界)
            var maxLeft = document.documentElement.clientWidth - this.offsetWidth;
            var maxTop = document.documentElement.clientHeight - this.offsetHeight;
            //碰撞
            var L2 = ox.offsetLeft;
            var T2 = ox.offsetTop;
            var R2 = L2 + ox.offsetWidth;
            var B2 = T2 + ox.offsetHeight
            //鼠标移动
            document.onmousemove = function (e) {
                e = e || window.event
                var x = e.clientX - offsetX;
                var y = e.clientY - offsetY;
​
                //计算边界
                if (x <= 0) x = 0
                if (y <= 0) y = 0
                if (x >= maxLeft) x = maxLeft;
                if (y >= maxTop) y = maxTop;
​
                o.style.left = x + "px";
                o.style.top = y + "px";
                //计算碰撞
                var L1 = o.offsetLeft;
                var T1 = o.offsetTop;
                var R1 = L1 + o.offsetWidth;
                var B1 = T1 + o.offsetHeight;
                if (L1 > R2 || T1 > B2 || R1 < L2 || B1 < T2) {   //不碰撞
                    ox.style.backgroundColor = "blue"
                } else {
                    ox.style.backgroundColor = "orange"
                }
            }
            //鼠标抬起
            document.onmouseup = function () {
                document.onmousemove = null;
                document.onmouseup = null;
                if (o.releaseCapture) {
                    o.releaseCapture();//释放全局捕获   
                }
            }
            return false;//标准浏览器的默认行为
        }
​
</script>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章