之前被小伙伴问自己能不能写一个简单的原生的 我稍微犹豫了下 这次重新学习下拖拽的过程 分享下 参考 JavaScript高级程序设计
必要的准备
自定义事件(实现事件模型)
简单来说事件模型就是观察者模式的一种使用,主体负责发布和管理事件,观察者通过订阅特定的事件类型来观察主体发布的事件,举个例子你有一个按钮,它触发click事件就是在发布事件,事件处理程序就是观察者
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){ //触发特定的事件处理程序 就分别将event对象传递给特定类型下数组中每个事件处理函数 if(!event.target) { event.target = this; } if(this.handlers[event.type] instanceof Array) { var handlers = this.handlers[event.type]; for(var i = 0,len = handlers.length;i < len;i+=1) { handlers[i](event); } } }, removeHandler:function(type,handler) { if(this.handlers[type] instanceof Array) { var handlers = this.handlers[type]; for(var i = 0,len = handlers.length;i < len;i+=1) { if(handlers[i] == handler) { break; } } handlers.splice(i,1); } } }
我们可以这样使用上面的事件处理程序
function test() { alert(1); } var target = new EventTarget(); target.addHandler("message",test); //订阅了一个type是message的事件处理函数 target.fire({type:"message"}); //触发该事件 会发现alert1
理解:自定义事件能使我们定义我们自己的事件type,能在我们需要进行交互的时刻触发特定的事件处理程序代码
实现跨浏览器的事件对象EventUtil 参考之前的blog js事件小记
下面来完成拖动的代码
其实简单的理解拖动的过程就是当鼠标mousedown的时候(如果元素可以拖动),让它的绝对定位的left top是鼠标的event.clientX event.clientY 并且在mousemove的时候,时刻去跟随鼠标的位置更新自己的left top 最后在mouseup的时候不让改元素可以移动 我们通过在拖动中加入自定义事件就能够在特定的时刻相应我们的行为,例如网络传输数据,通过页面的元素与用户交互,输出拖动元素的信息等
var DragDrop = function(){ var dragdrop = new EventTarget(), dragging = null, diffX = 0,//diffX diffY 是为了处理每次拖动的时候鼠标位置的问题 diffY = 0; function handlerEvent(event) { var 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) { 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",handlerEvent); EventUtil.addHandler(document,"mousemove",handlerEvent); EventUtil.addHandler(document,"mouseup",handlerEvent); }; dragdrop.disable = function(){ EventUtil.removeHandler(document,"mousedown",handlerEvent); EventUtil.removeHandler(document,"mousemove",handlerEvent); EventUtil.removeHandler(document,"mouseup",handlerEvent); }; return dragdrop; }(); DragDrop.enable();
上面的例子通过单例的模式,模块化的封装了拖动模块
其他相关点
z-index z-index 只在定位元素上有效果 即除了定位为static的元素