js原生拖放实现

更新日期: 2019-07-18阅读: 1.9k标签: 拖拽

定义事件操作工具

let EventUtil = new Object;
/*此方法用来给特定对象添加事件,oTarget是指定对象,sEventType是事件类型,如click、keydown等,fnHandler是事件回调函数*/
EventUtil.addEventHandler = function (oTarget, sEventType, fnHandler) {
     // firefox情况下
     if (oTarget.addEventListener) {
         oTarget.addEventListener(sEventType, fnHandler, false);
     }
     // IE下
     else if (oTarget.attachEvent) {
         oTarget.attachEvent("on" + sEventType, fnHandler);
     }
     else {
         oTarget["on" + sEventType] = fnHandler;
     }
};
/*此方法用来移除特定对象的特定事件,oTarget是指定对象,sEventType是事件类型,如click、keydown等,fnHandler是事件回调函数*/      
EventUtil.removeEventHandler = function (oTarget, sEventType, fnHandler) {
     if (oTarget.removeEventListener) {
         oTarget.removeEventListener(sEventType, fnHandler, false);
     } else if (oTarget.detachEvent) {
         oTarget.detachEvent("on" + sEventType, fnHandler);
     } else {
         oTarget["on" + sEventType] = null;
     }
};

/*格式化事件,因为IE和其他浏览器下获取事件的方式不同并且事件的属性也不尽相同,通过此方法提供一个一致的事件*/
EventUtil.formatEvent = function (oEvent) {
     // isIE和isWin引用到一个js文件,判断浏览器和操作系统类型
     if (isIE && isWin) {
         oEvent.charCode = (oEvent.type == "keypress") ? oEvent.keyCode : 0;
         // IE只支持冒泡,不支持捕获
         oEvent.eventPhase = 2;
         oEvent.isChar = (oEvent.charCode > 0);
         oEvent.pageX = oEvent.clientX + document.body.scrollLeft;
         oEvent.pageY = oEvent.clientY + document.body.scrollTop;
         // 阻止事件的默认行为
         oEvent.preventDefault = function () {
             this.returnValue = false;
         };

          // 将toElement,fromElement转化为标准的relatedTarget
         if (oEvent.type == "mouseout") {
             oEvent.relatedTarget = oEvent.toElement;
         } else if (oEvent.type == "mouseover") {
             oEvent.relatedTarget = oEvent.fromElement;
         }
         // 取消冒泡     
         oEvent.stopPropagation = function () {
             this.cancelBubble = true;
         };

         oEvent.target = oEvent.srcElement;
         // 添加事件发生时间属性,IE没有
         oEvent.time = (new Date).getTime();
     }
     return oEvent;
};

EventUtil.getEvent = function() {
     if (window.event) {
         // 格式化IE的事件
         return this.formatEvent(window.event);
     } else {
         return EventUtil.getEvent.caller.arguments[0];
     }
};

高级自定义事件-观察者:

function EventTarget(){
    this.handlers = {};
}
EventTarget.prototype = {
    constructor: EventTarget,
    addHandler: function(type, handler){
        if (typeof this.handlers[type] == "undefined"){
            this.handlers[type] = [];
        }
        this.handlers[type].push(handler);
    },
    fire: function(event){
        if (!event.target){
            event.target = this;
        }
        if (this.handlers[event.type] instanceof Array){
            let handlers = this.handlers[event.type];
            for (var i=0, len=handlers.length; i < len; i++){
                handlers[i](event);
            }
        }
    },
    removeHandler: function(type, handler){
        if (this.handlers[type] instanceof Array){
            let handlers = this.handlers[type];
            for (var i=0, len=handlers.length; i < len; i++){
                if (handlers[i] === handler){
                    break;
                }
            }
            handlers.splice(i, 1);
        }
    }
};

EventTarget 类型有一个单独的属性 handlers ,用于储存事件处理程序。还有三个方法:

addHandler() ,用于注册给定类型事件的事件处理程序;
fire() ,用于触发一个事件;
removeHandler() ,用于注销某个事件类型的事件处理程序。

addHandler() 方法接受两个参数:事件类型和用于处理该事件的函数。当调用该方法时,会进行一次检查,看看 handlers 属性中是否已经存在一个针对该事件类型的数组;如果没有,则创建一个新的。然后使用 push() 将该处理程序添加到数组的末尾。如果要触发一个事件,要调用 fire() 函数。该方法接受一个单独的参数,是一个至少包含 type属性的对象。

fire() 方法先给 event 对象设置一个 target 属性,如果它尚未被指定的话。然后它就查找对应该事件类型的一组处理程序,调用各个函数,并给出 event 对象。因为这些都是自定义事件,所以 event 对象上还需要的额外信息由你自己决定。

removeHandler() 方法是 addHandler() 的辅助,它们接受的参数一样:事件的类型和事件处理程序。这个方法搜索事件处理程序的数组找到要删除的处理程序的位置。如果找到了,则使用 break操作符退出 for 循环。然后使用 splice() 方法将该项目从数组中删除。


定义拖放函数:

let DragDrop = function(){
    let dragdrop = new EventTarget();
    let dragging = null;
    let diffx = 0;
    let diffy = 0;
    function handleEvent(event){
        // 获取事件和目标
        event = EventUtil.getEvent(event);
        let 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){
                    // 指定位置
                    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对象封装了拖放的所有基本功能。这是一个单例对象,并使用了模块模式来隐藏某些实现细节。dragging变量起初是null,将会存放被拖动的元素,所以当该变量不为null时,就知道正在拖动某个东西。handleEvent()函数处理拖放功能中的所有的三个鼠标事件。它首先获取event对象和事件目标的引用。之后,用一个switch语句确定要触发哪个事件样式。当mousedown事件发生时,会检查target的class是否包含 "draggable" 类,如果是,那么将target存放到dragging中。这个技巧可以很方便地通过标记语言而非JavaScript脚本来确定可拖动的元素。

handleEvent()的mousemove情况和前面的代码一样,不过要检查dragging是否为null。当它不是null,就知道dragging 就是要拖动的元素,这样就会把它放到恰当的位置上。mouseup情况就仅仅是将 dragging 重置为null,让 mousemove事件中的判断失效。

DragDrop还有两个公共方法:enable()和disable(),它们只是相应添加和删除所有的事件处理程序。这两个函数提供了额外的对拖放功能的控制手段。

要使用DragDrop对象,只要在页面上包含这些代码并调用enable()。拖放会自动针对所有包含"draggable" 类的元素启用,如下例所示:

<div class="draggable" style="position:absolute; background:red"> </div>


注意为了元素能被拖放,它必须是绝对定位的。

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

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

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

这段代码定义了三个事件:dragstart、drag和dragend。它们都将被拖动的元素设置为了target,并给出了 x 和 y 属性来表示当前的位置。它们触发于dragdrop对象上,之后在返回对象前给对象增加enable()和disable()方法。这些模块模式中的细小更改令DragDrop对象支持了事件.

这里,为 DragDrop 对象的每个事件添加了事件处理程序。还使用了一个元素来实现被拖动的元素当前的状态和位置。一旦元素被放下了,就可以看到从它一开始被拖动之后经过的所有的中间步骤。

为 DragDrop 添加自定义事件可以使这个对象更健壮,它将可以在网络应用中处理复杂的拖放功能。


链接: https://fly63.com/article/detial/6015

原生js实现拖拽与拖放事件,JavaScript实现元素拖拽、图片到指定区域进行预览的例子

拖拽,拖放事件可以通过拖拽实现数据传递,达到良好的交互效果,如:从操作系统拖拽文件实现文件选择,拖拽实现元素布局的修改。原生Js实现元素拖拽、图片到指定区域进行预览的方法实现

Vue自定义指令:通过Vue.directive实现集成第三方插件,拖拽功能,图片加载等功能

当我们需要对Dom元素进行底层操作的时候,这时候我们就需要使用vue的自定义指令。这篇文章将讲解:如何注册Vue自定义指令?Vue的钩子函数,vue钩子函数参数,vue实现拖拽功能,实现图片加载功能,Vue自定义指令集成第三方插件 ...

移动端拖拽 - 固定定位 fixed

移动端的拖拽有两种主流的实现方案:1. 将元素设置为固定定位,然后在拖拽的时候修改其定位,实现拖拽的效果;2. 使用 transform 中的平移 translate 属性实现拖拽。

vue模块拖拽实现

正巧在之前面试中遇到问实现拖拽效果。当时面试的时候简单回答了实现的方式与逻辑。现在闲来无事,把这个东西实现了一下。原理很简单,写的很方便。

原生js实现拖拽功能

如果要设置物体拖拽,必须使用三个事件,分别是:1、onmousedown:鼠标按下事件2、onmousemove:鼠标移动事件3、onmouseup:鼠标抬开事件

js实现本地图片文件拖拽效果

如何拖拽图片到指定位置,具体方法如下,在从本地上传图片的时候,如果使用拖拽效果,想想应该是更加的高大上,下面直接上js代码

ngDraggable.js_AngularJS之拖拽排序

ngDraggable.js是一款比较简单实用的angularJS拖拽插件,借助于封装好的一些自定义指令,能够快速的进行一些拖拽应用开发。首先先介绍一些基本的概念;ng-drop:是否允许放入拖拽元素

拖放实现--兼容手机与pc端

拖放是一种非常流行的用户界面模式。它的概念很简单:点击某个对象,并按住鼠标按钮不放,将鼠标移到到另一个区域,然后释放按钮将对象放到这里。

实现平滑过渡的拖拽排序

最近重读Vue官方文档,在列表的排序过渡这一小节,文档提到,<transition-group> 组件有一个特殊的地方,不仅可以实现进入和离开动画,还可以改变定位,官网示例如下

Element ui表格组件+sortablejs实现行拖拽排序

运营小姐姐说想要可以直接拖拽排序的功能,原来在序号六的广告可能会因为金主爸爸加钱换到序号一的位置,拖拽操作就很方便;实现方式:template部分、script部分

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!