说说如何使用 JavaScript 实现拖放功能

JavaScript 专栏收录该内容
91 篇文章 1 订阅

拖放指的是:鼠标点击某个对象并按住不放,然后移动到另一个区域,释放鼠标按键将对象放在这个地方。

创建一个绝对定位的元素,然后让它可以在页面上跟着鼠标指针移动,这种技术源自“鼠标拖尾”的经典技巧。单元素的鼠标拖尾是使用 onmousemove 事件来实现的,它总是将指定的元素移动到鼠标指针的位置:

<script type="text/javascript">

    EventUtil.addHandler(document, "mousemove", function (event) {
        var myDiv = document.getElementById("myDiv");
        myDiv.style.left = event.clientX + "px";
        myDiv.style.top = event.clientY + "px";
    });

</script>

EventUtil事件对象说明:请点击

最简单的拖放功能可以这样实现:

<script type="text/javascript">

    var DragDrop = function () {
        var dragging = null;//存放被拖动的元素

        function handleEvent(event) {
            //获取事件和目标
            event = EventUtil.getEvent(event);
            var target = EventUtil.getTarget(event);

            //确定事件类型
            switch (event.type) {
                case "mousedown"://按下鼠标
                    if (target.className.indexOf("draggable") > -1) {//是可以拖动的元素
                        dragging = target;
                    }
                    break;

                case "mousemove"://移动鼠标
                    if (dragging !== null) {//有元素正在被拖动
                        //assign location
                        dragging.style.left = event.clientX + "px";
                        dragging.style.top = event.clientY + "px";
                    }
                    break;
                case "mouseup"://释放鼠标
                    dragging = null;
                    break;
            }

        };

        //公共接口
        return {
            enable: function () {//添加所有相关的事件处理程序
                EventUtil.addHandler(document, "mousedown", handleEvent);
                EventUtil.addHandler(document, "mousemove", handleEvent);
                EventUtil.addHandler(document, "mouseup", handleEvent);
            },
            disable: function () {//移除所有相关的事件处理程序
                EventUtil.removeHandler(document, "mousedown", handleEvent);
                EventUtil.removeHandler(document, "mousemove", handleEvent);
                EventUtil.removeHandler(document, "mouseup", handleEvent);
            }
        }
    }();

    DragDrop.enable();
</script>

DragDrop 对象使用单例模式实现,封装了内部实现细节。dragging 存放被拖动的元素,所以如果不是 null,就表示正在拖动某个元素。

这里是这样定义可拖放元素的:

<div id="myDiv" class="draggable"
     style="background: red;width:100px;height:100px;position:absolute"></div>

为了元素能够被拖放,它必须是绝对定位的!

1 完善拖动功能

上面的拖放程序运行后,你会发现元素的左上角总是和指针在一起的,所以当鼠标开始移动时,元素好像突然跳了一下!我们想要的是用户点击元素的那一个点就是指针应该保持的位置,就好像元素是被鼠标拾起的,这个优化对用户体验很重要的哦O(∩_∩)O~

元素好像突然跳了一下

为了实现这个效果,我们必须计算元素左上角和指针位置之间的差值,在 mousedown 事件确定差值,然后一直保持,直到发生 mouseup 事件。

计算元素左上角和指针位置之间的差值

<script type="text/javascript">

    var DragDrop = function () {
        var dragging = null,//拖动对象
                diffX = 0,//x 轴坐标差值
                diffY = 0;// y 轴坐标差值

        function handleEvent(event) {
            //获取事件和目标
            event = EventUtil.getEvent(event);
            var target = EventUtil.getTarget(event);

            //确定事件类型
            switch (event.type) {
                case "mousedown":
                    if (target.className.indexOf("draggable") > -1) {
                        dragging = target;
                        diffX = event.clientX - target.offsetLeft;
                        diffY = event.clientY - target.offsetTop;
                    }
                    break;

                case "mousemove":
                    if (dragging !== null) {
                        //assign location
                        dragging.style.left = (event.clientX - diffX) + "px";
                        dragging.style.top = (event.clientY - diffY) + "px";
                    }
                    break;
                case "mouseup":
                    dragging = null;
                    break;
            }

        };

        //公共接口
        return {
            enable: function () {
                EventUtil.addHandler(document, "mousedown", handleEvent);
                EventUtil.addHandler(document, "mousemove", handleEvent);
                EventUtil.addHandler(document, "mouseup", handleEvent);
            },
            disable: function () {
                EventUtil.removeHandler(document, "mousedown", handleEvent);
                EventUtil.removeHandler(document, "mousemove", handleEvent);
                EventUtil.removeHandler(document, "mouseup", handleEvent);
            }
        }
    }();

    DragDrop.enable();
</script>

这里的 diffX 和 diffY 是私有变量,因为只有 handleEvent() 函数会用到它们,最终的效果是用户得到了一个更为平滑的拖动体验O(∩_∩)O~

2 添加自定义事件

现在我们需要自定义一些事件,让应用的其他部分可以与拖动功能进行交互。

这里我们使用 EventTarget 类型,关于 EventTarget 类型的详情,请点击

首先创建一个新的 EventTarget 类型,然后添加 enable() 和 disable() 方法,最后返回它:

<script type="text/javascript">

    var DragDrop = function () {
        var dragdrop = new EventTarget(),
                dragging = null,//拖动对象
                diffX = 0,//x 轴坐标差值
                diffY = 0;// y 轴坐标差值

        function handleEvent(event) {
            //获取事件和目标
            event = EventUtil.getEvent(event);
            var target = EventUtil.getTarget(event);

            //确定事件类型
            switch (event.type) {
                case "mousedown":
                    if (target.className.indexOf("draggable") > -1) {
                        dragging = target;
                        diffX = event.clientX - target.offsetLeft;
                        diffY = event.clientY - target.offsetTop;
                        dragdrop.fire({
                            type: "dragstart",
                            target: dragging,
                            x: event.clientX,
                            y: event.clientY
                        });
                    }
                    break;

                case "mousemove":
                    if (dragging !== null) {
                        //assign location
                        dragging.style.left = (event.clientX - diffX) + "px";
                        dragging.style.top = (event.clientY - diffY) + "px";

                        dragdrop.fire({
                            type: "drag",
                            target: dragging,
                            x: event.clientX,
                            y: event.clientY
                        });
                    }
                    break;
                case "mouseup":
                    dragdrop.fire({
                        type: "dragend",
                        target: dragging,
                        x: event.clientX,
                        y: event.clientY
                    });
                    dragging = null;
                    break;
            }

        };

        //公共接口
        dragdrop.enable = function () {
            EventUtil.addHandler(document, "mousedown", handleEvent);
            EventUtil.addHandler(document, "mousemove", handleEvent);
            EventUtil.addHandler(document, "mouseup", handleEvent);
        };
        dragdrop.disable = function () {
            EventUtil.removeHandler(document, "mousedown", handleEvent);
            EventUtil.removeHandler(document, "mousemove", handleEvent);
            EventUtil.removeHandler(document, "mouseup", handleEvent);
        };

        return dragdrop;
    }();

    DragDrop.enable();

    DragDrop.addHandler("dragstart", function (event) {
        var status = document.getElementById("status");
        status.innerHTML = "Started dragging " + event.target.id;
    });

    DragDrop.addHandler("drag", function (event) {
        var status = document.getElementById("status");
        status.innerHTML += "<br/> Dragged " + event.target.id + " to (" + event.x + ","
        + event.y + ")";
    });

    DragDrop.addHandler("dragend", function (event) {
        var status = document.getElementById("status");
        status.innerHTML +=
                "<br/> Dropped " + event.target.id + " at (" + event.x + "," + event.y + ")";
    });
</script>

这里,我们自定义了 dragstart、drag、dragend 事件,这样元素被拖放的整个过程就被记录了下来。添加了自定义事件的 DragDrop 对象变得更健壮咯O(∩_∩)O~

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

©️2022 CSDN 皮肤主题:精致技术 设计师:CSDN官方博客 返回首页

打赏作者

deniro_li

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值