JavaScript实现元素拖拽与自动占位功能详解

作者:小圆点

时间:2026-10-24

浏览:665

本文介绍如何使用JavaScript实现元素的拖拽与自动占位功能。通过监听鼠标事件,判断拖拽目标是否为相邻模块,并在指定位置插入占位元素,实现任务进度的可视化展示。

文章目录

本文分享一个近期项目中遇到的技术难点:如何实现页面元素的自由移动。掌握此方法后,结合特定逻辑,即可构建出类似任务进度条的动态页面效果。

功能需求说明:

首先,让我们直观地看一下最终实现的效果:

功能需求说明:

功能需求说明:

核心功能要求:用户可拖动元素至其他板块的指定位置。根据项目需求,设置了限制条件:元素仅能移动至当前模块的下一个相邻模块;若尝试移动至非相邻模块,元素将自动返回原位。此外,若拖拽距离未超过设定阈值,元素也会自动回弹至初始位置。

逻辑分析:

实现的关键在于鼠标按下事件的处理。此时,不仅要获取当前被拖动的元素,还需获取其所属的模块(因此,在初始化时需为每个模块设置 index 属性,值为该模块的索引号)。这一步骤旨在鼠标松开时判断目标模块是否为当前模块的下一个模块(逻辑稍显复杂,需仔细理解)。若条件满足,则需与目标模块内的所有元素逐一比对位置,以确定具体的插入点。确定位置后,需在该处新建一个空元素,并将原元素的内容复制至新元素中。最后,务必移除原位置的元素,完成整个拖拽与占位过程。

具体代码实现如下:


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./js/jQuery.min.js"></script>
    <style>
        * {
            margin: 0;
            left: 0;
            list-style: none;
            box-sizing: border-box;
        }
        .container {
            display: flex;
            justify-content: space-around;
            width: 1000px;
            height: 600px;
            margin: 100px auto;
            padding: 0;
        }
        .container li {
            width: 180px;
            height: 100%;
            background-color: plum;
            border-radius: 10px;
            padding: 5px;
        }
        .item {
            width: 170px;
            height: 100px;
            background-color: salmon;
            margin: 5px 0;
            border-radius: 10px;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <ul class="container">
       <li>
           <div class="item">1</div>
           <div class="item">2</div>
           <div class="item">3</div>
       </li> 
       <li>
        <div class="item">4</div>
        <div class="item">5</div>
        <div class="item">6</div>
       </li> 
       <li>
        <div class="item">7</div>
        <div class="item">8</div>
        <div class="item">9</div>
       </li> 
       <li></li>
       <li></li>
    </ul>
    <script>
        $(function(){
            for (var i = 0; i < 5; i++) {
               $(".container li")[i].setAttribute('index', i);
            }
            $('.item').on('mousedown',function(e){
                var index = Number($(this).parent()[0].getAttribute('index'));
                //获取当前所选任务的左边距和上边距
                startLeft = $(this).offset().left;
                startTop = $(this).offset().top;
                //求鼠标在所选任务里的位置
                mouseX = e.pageX - startLeft;
                mouseY = e.pageY - startTop;
                $(this).on('mousemove',function(e){
                    $(this).offset({
                       left: e.pageX - mouseX,
                       top: e.pageY - mouseY        
                    })
                })
                $(this).on('mouseup',function(){
                    //用来记录item移动到那个位置
                    k = -1;
                    $(this).off('mousemove');
                     //获取所选 模块 的下一个 模块索引
                    if (index >= 4) {
                        index = 3;
                    }
                    var next = $('.container li').eq(index + 1);
                     
                    //如果鼠标放开时,所移动到的距离正好位于所选模块的下一个模块的区间内,就执行
                   if ($(this).offset().left >= next.offset().left&&$(this).offset().left <= next.offset().left + next[0].offsetWidth) {
                   //获取到所选的item中的内容
                   var text = $(this).html();
                   //在最终所要放置的位置新建一个空任务,再把所获取到的内容添加进去
                   var father = document.createElement('div');
                   father.className = 'item';
                   $(father).append(text);
                  //把点击的当前元素获取过来
                  var ele = $(this);
                 //如果当前模块没有item,则直接添加到第一个位置,如果有,则比较看它的top比哪个 大就放在哪个的后面
                 if (next.children().length == 0) {
                    next.append(father);
                } else {
                   $.each(next.children(), function (i,item) {
                    if ( ele.offset().top > $(item).offset().top) {
                        k = i;
                    }
                   })
                    //如果 k == -1 说明 要把任务放在该模块的第一个位置
                    if (k == -1) {
                        next.children().eq(0).before(father);
                    } else {
                        next.children().eq(k).after(father);
                 }
                    
                }
                //解绑移动事件,清空原来位置的item
                $(this).off("mousemove");
                $(this).remove();
                $(this).empty();
            } else {
                //这里就是移动不成功,回到原来位置
                $(this).offset({
                    left: startLeft,
                    top: startTop
                })
                $(this).off("mousemove");
            }
                })
            })
        })
    </script>
</body>
</html>

功能扩展:

将此案例与后台数据结合,即可实现多任务不同进度的动态显示与拖拽交互,效果如下图所示:

功能需求说明:

赶紧动手实践起来吧!

功能需求说明:

至此,关于 JavaScript 实现元素拖拽与占位功能的介绍已完毕。如需了解更多相关 js 元素拖动占位内容,请搜索本站历史文章或继续浏览下方相关文章。感谢大家的支持!

实用工具推荐

电子包浆

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

使用 ›
图片压缩

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

使用 ›
相关文章