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() ,用于注销某个事件类型的事件处理程序。
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>
注意为了元素能被拖放,它必须是绝对定位的。this
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 对象的每一个事件添加了事件处理程序。还使用了一个元素来实现被拖动的元素当前的状态和位置。一旦元素被放下了,就能够看到从它一开始被拖动以后通过的全部的中间步骤。firefox
为 DragDrop 添加自定义事件可使这个对象更健壮,它将能够在网络应用中处理复杂的拖放功能。prototype