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