目录:
- 用H5方法实现拖拽交互
- 自定义事件
- 自定义拖拽事件
- 实现兼容所有浏览器的拖拽交互
跟着教程用H5实现了一个简单的拖拽,左右两个白盒子是容器,两边的红盒子可以任意拖拽。
满足以下两个要求:
- 被拖起来的盒子变成黄色,并且在原容器中消失,跟随鼠标移动。
- 被拖拽的盒子进入容器时,容器会变颜色,离开时恢复原来的颜色。
- 拖拽释放后,添加到准确的位置。
HTML+CSS为:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>拖动</title> </head> <style> body{ background-color: #ccc; } .container { width: 200px; height: 800px; background-color: #fff; border: 1px solid #000; margin: 50px; float: left; } .box { width: 200px; height: 80px; background-color: #f00; border: 1px solid #000; } .light { background-color: #f9f; } .move { background-color: #ffff73; } .hide { display: none; } </style> <body> <div class="wrap"> <div class="container"> <div class="box">1</div> <div class="box">2</div> <div class="box">3</div> <div class="box">4</div> </div><!--container结束--> <div class="container"> <div class="box">5</div> <div class="box">6</div> <div class="box">7</div> </div><!--container结束--> </div><!--wrap结束-->
<script type="text/javascript" src="js/util.js"></script>
<script type="text/javascript" src="js/dragAnddrop.js"></script> </body> </html>
(util.js中是一些平时经常会用到的方法,像下面会出现的$.on( )用于接受一个选择器,然后在其表示的节点上绑定事件。$.getElements( )负责选出符合接收到的选择器的所有元素。)
看教程之前,我的代码大致是这样的:
window.onload=function(){ var boxes=getElements(".box"); //设置拖动目标可以被拖动 each(me.box,function(item,index){ item.draggable=true; }); //获取拖动目标,并为其添加样式 $.on(".wrap","dragstart",function(e){ var e=e||window.event, target=e.target||e.srcElement; if (hasClass(target,"box")) { e.dataTransfer.setData("text/plain",".move"); } }); //其他功能 }
然后我看到了教程中这样的代码:
(function () { var dnd = { // 初始化 init: function () { var me = this; me.src = document.querySelector('#demo1-src'); me.panelList = document.querySelector('.panel-list'); // 为拖拽源监听dragstart,设置关联数据 me.src.addEventListener('dragstart', me.onDragStart, false); //省略 onDragStart: function (e) { e.dataTransfer.setData('text/plain', 'demo1-src'); }, //省略 dnd.init(); }());
顿时觉得自己写了一坨屎。不过还好,终于见识到了传说中的面向对象。
在用H5实现拖拽交互的过程中,我遇到一个问题:
为drop添加事件处理程序的时候,要用appendChild方法将被拖拽的盒子添加到容器中去,那么要怎么获取到被拖拽的元素呢?
我先想到可以在dragstart事件处理程序中把被拖拽的元素保存在一个变量里,然后再drop的事件处理程序访问它。但是很遗憾,并不能访问到。想一想,这是因为变量被声明之后的值是undefined,他在dragstart事件处理程序中被赋值,结束之后这个值就已经失效了,所以drop的事件处理程序中访问到的变量值是undefined。
然后我想到了,在事件处理程序中想要获得信息,可以通过传入的事件对象,想到这里,之前看的云里雾里的dataTransfer对象就派上用场了。可以在dragstart事件处理程序中将为被拖拽的对象添加的class通过setData()方法传递给drop,这样就可以获取到他了。
最终写好的代码如下:
window.onload=function(){ var dragdrop={ //初始化 init:function(){ var me=this; me.box=getElements(".box"); //设置拖动目标可以被拖动 each(me.box,function(item,index){ item.draggable=true; }); //获取拖动目标,并为其添加样式 $.on(".wrap","dragstart",me.dragStart); //让拖动目标在拖起来的时候在原容器中消失 $.on(".wrap","drag",me.Drag); //松开的时候恢复原状 $.on(".wrap","dragend",me.dragEnd); //监听放置目标的dragenter事件,添加视觉效果 $.on(".wrap","dragenter",me.dragEnter); //设置放置目标 $.on(".wrap","dragover",me.prevent); //取消视觉效果 $.on(".wrap","dragleave",me.dragLeave); //在拖放目标上处理 $.on(".wrap","drop",me.dragDrop); }, dragStart:function(e){ var e=e||window.event, target=e.target||e.srcElement; if (hasClass(target,"box")) { e.dataTransfer.setData("text/plain",".move"); addClass(target,"move"); } }, Drag:function(e){ var e=e||window.event, target=e.target||e.srcElement; if (hasClass(target,"box")) { addClass(target,"hide"); } }, dragEnd:function(e){ var e=e||window.event, target=e.target||e.srcElement; if (hasClass(target,"box")) { removeClass(target,"hide"); removeClass(target,"move"); } }, dragEnter:function(e){ var e=e||window.event, target=e.target||e.srcElement; if (hasClass(target,"container")) { addClass(target,"light"); } }, prevent:function(e){ $.prevent(e); }, dragLeave:function(e){ var e=e||window.event, target=e.target||e.srcElement; if (hasClass(target,"container")) { removeClass(target,"light"); } }, dragDrop:function(e){ var e=e||window.event, target=e.target||e.srcElement; if (hasClass(target,"container")) { var dragging=$(e.dataTransfer.getData("text/plain")); removeClass(dragging,"move"); removeClass(target,"light"); target.appendChild(dragging); } }, } dragdrop.init(); }
虽然还没有很深刻的体会到这种面向对象写法的好处,但还是模仿着写了。
接下来就要开始照顾不支持H5的宝宝们了。
一开始就被一系列的问题卡住,他怎么动起来?什么时候让他动起来?怎么让他跟着鼠标走?他怎么回去?怎么给它绑定事件处理程序?
前两个问题还能勉强想出来,当鼠标按下的时候,可以给他设置position:absolute让他动起来,然后让他的left和top和mousedown事件的鼠标坐标相同就可以了。
后几个问题就真的束手无策了。
在《JavaScript高级程序设计》中找到答案,发现这件事情真的没那么简单。
最本质的,要深刻地理解事件是怎么回事。
事件是一种叫做观察者的设计模式,这是一种创建松散耦合代码的技术。对象可以发布事件,用来表示在该对象生命周期中某个有趣的时刻到了。然后其他对象可以观察该对象,等待这些有趣的时刻到来并通过运行代码来响应。
意思就是说,事件是一个对象发出的信号,他邀请别人一起来庆祝他重要的时刻,不管有没有人愿意来,他都可以发出信号。
那么,他要怎样发出信号呢? 通过 函数调用 很容易就可以实现对象之间的通信。
有行为就需要有管理机制,得到一个名字,检测其对应的函数,执行函数。所以就需要一个对象来进行管理。
函数的调用需要一些代码,需要函数名。所以这个对象中应该保存着函数名表示事件类型,还要保存该类型相应的代码,所以他还需要一个个方法为其添加事件类型和处理函数,还要有一个让函数中的代码执行的方法,这个方法读取函数名,然后执行这个函数名对应的代码。可以添加就要可以删除,所以还需要一个负责删除处理程序的方法。
所以,这个对象应该长这样:
{
事件类型和他的代码们:
{type1:[fun1,fun2...]
type2:[fun1,fun2,..]
.....}
接待员:为对象添加type和相应fun。
执行官:接收一个type执行相应代码。
清理员:接收一个type和他想删除的fun,为其删掉这个fun。
}
用JavaScript实现就长下面这样:
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(e){ var handlers=this.handlers[e.type] if (isArray(handlers)) { for (var i = 0,len = handlers.length;i<len; i++) { handlers[i](e); } } }, removeHandler:function(type,handler){ if (isArray(this.handlers[type])) { removeItem(this.handlers[type],handler); } }, };
用这种构造函数+原型的方式,就是为了自定义的事件可以继承他的方法,并拥有自己的事件类型。
有了这个完美的事件管理机制,就可以自定义拖拽事件对象了。
按照H5的思路,他应该可以触发这6种事件:dragstart、drag、dragend、dragenter、dragleave和drop。
首先,他如何触发dragstart?什么时候应该触发dragstart?
拖拽的本质就是,鼠标在一个元素上按下不松开,挪动鼠标,放到另一个地方,松开。
听起来好像很熟悉,就是我们熟悉的mousedown、mousemove和mouseup嘛。
所以,当元素上发生mousedown的时候,就触发dragstart事件,移动的时候触发drag,移动到目标元素里面的时候触发dragenter,移出去的时候触发dragleave,松开的时候要是在目标元素里面就触发drop,然后触发dragend(因为不在里面的话要回到原位)。
如果要绑定事件的话,就要知道绑定在哪里,因为事先不知道要被绑定的元素,所以绑定在document上,让每个DOM对象都有机会成为被拖拽的和放置目标。然后指定筛选条件,在指定的满足条件的对象上面触发事件。
那么,如何指定被拖拽对象和放置目标呢?
还是模仿H5,他通过设置draggable属性和阻止浏览器默认行为,我们也可以通过添加一个自定义属性或者类名,来判别目标对象。
想明白这些之后,就可以开始写处理程序了,解决了重重问题之后,最后的对象是这样的:
//自定义拖动事件(和HTML的class属性耦合) var DragDrop=function(){ var dragdrop=new eventTarget(), dragging=null, x=0,y=0, border_r,border_l,border_top,border_btm, left,right,top,bottom; function handle(e){ var e=e||window.event, target=e.target||e.srcElement, drops=getElements(".dropable"); //问题1 switch(e.type){ case "mousedown": if (hasClass(target,"draggable")) { dragging=target; x=e.clientX-target.offsetLeft; y=e.clientY-target.offsetTop; dragdrop.fire({ type:"dragstart", target:dragging, x:e.clientX, y:e.clientY }); } break; case "mousemove": if (dragging!==null) { dragging.style.left=e.clientX-x+"px"; dragging.style.top=e.clientY-y+"px"; dragdrop.fire({ type:"drag", target:dragging, x:e.clientX, y:e.clientY }); if (drops[0]) { for (var i = 0; i < drops.length; i++) { border_l=dragging.offsetLeft; border_r=parseInt(getCSS(dragging,"width"))+border_l; //问题2 border_top=dragging.offsetTop; border_btm=parseInt(getCSS(dragging,"height"))+border_top; left=drops[i].offsetLeft; right=parseInt(getCSS(drops[i],"width"))+left; top=drops[i].offsetTop; bottom=parseInt(getCSS(drops[i],"height"))+top; if(border_r>left&&border_l<right&&border_top<bottom&&border_btm>top){ dragdrop.fire({ type:"dragenter", target:drops[i] }); }else{ dragdrop.fire({ type:"dragleave", target:drops[i] }); } } } } break; case "mouseup": if (drops[0]&&dragging) { for (var i = 0; i < drops.length; i++) { dragWidth=parseInt(getCSS(dragging,"width")); border_r=dragWidth+dragging.offsetLeft; border_l=dragging.offsetLeft; left=drops[i].offsetLeft; right=drops[i].offsetLeft+parseInt(getCSS(drops[i],"width")); if(border_r>left&&border_l<right&&border_top<bottom&&border_btm>top){ //问题3 dragdrop.fire({ type:"drop", target:drops[i], dragging:dragging }); break; } } } dragdrop.fire({ type:"dragend", target:dragging, x:e.clientX, y:e.clientY }); dragging=null; break; } }; dragdrop.enable=function(){ $.add(document,"mousedown",handle); $.add(document,"mousemove",handle); $.add(document,"mouseup",handle); }; dragdrop.disable=function(){ $.remove(document,"mousedown",handle); $.remove(document,"mousemove",handle); $.remove(document,"mouseup",handle); }; return dragdrop; }
问题1:
最开始的时候,我是不知道该怎么将被拖拽对象和目标对象分开的,我一直想,当感受到拖拽的时候就让事件的target变成被拖拽的元素,当感受到有东西改过来时让事件的target变成目标对象,当我尝试着把dragenter事件让mouseenter来触发时,失望的发现,鼠标上拖着东西的时候是无法触发mouseenter的。
然后我想到,既然只能获得被拖拽的对象,也没有想mousedown那样的事件可以来获取放置目标,那就换个思路。通过class来获取,毕竟在我心中class是个万能的东西。所以我的逻辑就是,获取到所有class=droppable的对象,判断他们是否被拖动元素覆盖,是的话就触发dragenter,不是的话就触发dragleave。(这也就导致了问题3。)
问题2:
我想到的判断拖拽元素是否在目标元素上方的方法是,看被拖动元素是否有两条边线在目标元素之内。这就需要获取拖拽元素和目标元素的width。
而用node.style.width获取不到。查了一下发现,这个方法只能获取到写在标签里面的样式。想要获取CSS中的样式,需要用DOM2级样式中定义的document.defaultView.getComputerStyle()和IE的obj.currentStyle。所以就写了一个getCSS方法,代码如下:
//获得元素的CSS样式 function getCSS(ele,name){ if (ele) { return document.defaultView.getComputedStyle? document.defaultView.getComputedStyle(ele,null)[name]:ele.currentStyle[name]; } }
问题3:
由于我上面判断目标对象的逻辑,被拖拽的元素会更容易drop进第一个带有droppable的容器里面。这个问题还有待解决。
定义好拖拽事件对象之后,就可以为其绑定处理程序了。
这时候就体现出之前面向对象写法的好处了:①他将所有事件处理函数都变成对象自身的方法,减少了很多游离再全局中的变量。②这些方法只有他自己能调用,外部不需要知道这里会发生什么,只需要知道他能做这些事情就够了。
这样的写法,让一切变得非常井然有序,逻辑清晰。
因为他们处理的方法是不同的,所以事件处理程序中的执行代码会有些差异,需要判断一下,不然会有冲突。
到这里,已经可以实现我想要的功能了,而且还没有发现什么重大的问题。所以暂时先写成这个样子啦。
虽然一直很嫌弃不支持新方法的浏览器,尤其是IE。但是这次要好好的感谢一下他,让我更深刻的了解了事件,并且让我见识到了JavaScript如此强大的函数,它可以创造无限可能。
完整代码(https://github.com/mamengyi/Baidu/tree/master/2015_Spring/task0002/%E6%8B%96%E6%8B%BD%E4%BA%A4%E4%BA%92)
//自定义事件 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(e){ var handlers=this.handlers[e.type] if (isArray(handlers)) { for (var i = 0,len = handlers.length;i<len; i++) { handlers[i](e); } } }, removeHandler:function(type,handler){ if (isArray(this.handlers[type])) { removeItem(this.handlers[type],handler); } }, }; //自定义拖动事件(和HTML的class属性耦合) var DragDrop=function(){ var dragdrop=new eventTarget(), dragging=null, x=0,y=0, border_r,border_l,border_top,border_btm, left,right,top,bottom; function handle(e){ var e=e||window.event, target=e.target||e.srcElement, drops=getElements(".dropable"); switch(e.type){ case "mousedown": if (hasClass(target,"draggable")) { dragging=target; x=e.clientX-target.offsetLeft; y=e.clientY-target.offsetTop; dragdrop.fire({ type:"dragstart", target:dragging, x:e.clientX, y:e.clientY }); } break; case "mousemove": if (dragging!==null) { dragging.style.left=e.clientX-x+"px"; dragging.style.top=e.clientY-y+"px"; dragdrop.fire({ type:"drag", target:dragging, x:e.clientX, y:e.clientY }); if (drops[0]) { for (var i = 0; i < drops.length; i++) { border_l=dragging.offsetLeft; border_r=parseInt(getCSS(dragging,"width"))+border_l; border_top=dragging.offsetTop; border_btm=parseInt(getCSS(dragging,"height"))+border_top; left=drops[i].offsetLeft; right=parseInt(getCSS(drops[i],"width"))+left; top=drops[i].offsetTop; bottom=parseInt(getCSS(drops[i],"height"))+top; if(border_r>left&&border_l<right&&border_top<bottom&&border_btm>top){ dragdrop.fire({ type:"dragenter", target:drops[i] }); }else{ dragdrop.fire({ type:"dragleave", target:drops[i] }); } } } } break; case "mouseup": if (drops[0]&&dragging) { for (var i = 0; i < drops.length; i++) { dragWidth=parseInt(getCSS(dragging,"width")); border_r=dragWidth+dragging.offsetLeft; border_l=dragging.offsetLeft; left=drops[i].offsetLeft; right=drops[i].offsetLeft+parseInt(getCSS(drops[i],"width")); if(border_r>left&&border_l<right&&border_top<bottom&&border_btm>top){ //会更容易drop进第一个盒子里。 dragdrop.fire({ type:"drop", target:drops[i], dragging:dragging }); break; } } } dragdrop.fire({ type:"dragend", target:dragging, x:e.clientX, y:e.clientY }); dragging=null; break; } }; dragdrop.enable=function(){ $.add(document,"mousedown",handle); $.add(document,"mousemove",handle); $.add(document,"mouseup",handle); }; dragdrop.disable=function(){ $.remove(document,"mousedown",handle); $.remove(document,"mousemove",handle); $.remove(document,"mouseup",handle); }; return dragdrop; } //拖动 window.onload=function(){ var dragdrop={ //初始化 inith5:function(){ var me=this; me.box=getElements(".box"); //设置拖动目标可以被拖动 each(me.box,function(item,index){ item.draggable=true; }); //获取拖动目标,并为其添加样式 $.on(".wrap","dragstart",me.dragStart); //让拖动目标在拖起来的时候在原容器中消失 $.on(".wrap","drag",me.Drag); //松开的时候恢复原状 $.on(".wrap","dragend",me.dragEnd); //监听放置目标的dragenter事件,添加视觉效果 $.on(".wrap","dragenter",me.dragEnter); //设置放置目标 $.on(".wrap","dragover",me.prevent); //取消视觉效果 $.on(".wrap","dragleave",me.dragLeave); //在拖放目标上处理 $.on(".wrap","drop",me.dragDrop); }, init:function(){ var me=this, dragevent=new DragDrop(); dragevent.enable(); //设置拖动目标可以被拖动 me.box=getElements(".box"); each(me.box,function(item,index){ addClass(item,"draggable"); }); //获取拖动目标,并为其添加样式 dragevent.addHandler("dragstart",me.dragStart); //松开的时候恢复原状 dragevent.addHandler("dragend",me.dragEnd); //监听放置目标的dragenter事件,添加视觉效果 dragevent.addHandler("dragenter",me.dragEnter); //设置放置目标 me.container=getElements(".container"); each(me.container,function(item,index){ addClass(item,"dropable"); }); //取消视觉效果 dragevent.addHandler("dragleave",me.dragLeave); //在拖放目标上处理 dragevent.addHandler("drop",me.dragDrop); }, dragStart:function(e){ var e=e||window.event, target=e.target||e.srcElement; if (hasClass(target,"box")) { if (e.dataTransfer) { e.dataTransfer.setData("text/plain",".move"); addClass(target,"move"); }else{ addClass(target,"moving"); } } }, Drag:function(e){ var e=e||window.event, target=e.target||e.srcElement; if (e.dataTransfer&&hasClass(target,"box")) { addClass(target,"hide"); } }, dragEnd:function(e){ var e=e||window.event, target=e.target||e.srcElement; if (e.dataTransfer&&hasClass(target,"box")) { removeClass(target,"hide"); removeClass(target,"move"); }else{ removeClass(target,"moving"); } }, dragEnter:function(e){ var e=e||window.event, target=e.target||e.srcElement; if (hasClass(target,"container")) { addClass(target,"light"); } }, prevent:function(e){ $.prevent(e); }, dragLeave:function(e){ var e=e||window.event, target=e.target||e.srcElement; if (hasClass(target,"container")) { removeClass(target,"light"); } }, dragDrop:function(e){ var e=e||window.event, target=e.target||e.srcElement; if (e.dataTransfer&&hasClass(target,"container")) { var dragging=$(e.dataTransfer.getData("text/plain")); removeClass(dragging,"move"); removeClass(target,"light"); target.appendChild(dragging); }else if (e.dragging) { var lights=getElements(".light"), len=lights.length; for (var i = 0; i < len; i++) { removeClass(lights[0],"light"); //注意这里是一个NodeList } removeClass(e.dragging,"moving"); target.appendChild(e.dragging); } }, } if(supportDrag()){ dragdrop.inith5(); }else{ dragdrop.init(); } }
util:
//对数组(类数组对象)的每项都执行fn(item,index) function each(arr,fn){ for(var i = 0 , len = arr.length ; i<len ; i++){ fn(arr[i],i); } } //DOM元素选择器 function getElements(selector){ //类选择器,返回全部项 if(/.((?:[wu00c0-uFFFF-]|\.)+)/.test(selector)){ if(document.getElementsByClassName){ return document.getElementsByClassName(selector.slice(1,selector.length)); } var nodes = document.all ? document.all : document.getElementsByTagName('*'); var arr=[];//用来保存符合的className; for(var i=0;i<nodes.length;i++){ if(hasClass(nodes[i],selector.slice(1,selector.length))){ arr.push(nodes[i]); } } return arr; } //ID选择器 if(/#((?:[wu00c0-uFFFF-]|\.)+)/.test(selector)){ return document.getElementById(selector.slice(1,selector.length)); } //tag选择器 if(/^((?:[wu00c0-uFFFF-]|\.)+)/.test(selector)){ return document.getElementsByTagName(selector); } //属性选择器 if(/^[[A-Za-z0-9_-S]+]$/.test(selector)){ selector = selector.slice(1,selector.length-1); var eles = document.getElementsByTagName("*"); selector = selector.split("="); var att = selector[0]; var value = selector[1]; var arr = []; if (value) { for (var i = 0; i < eles.length; i++) { if(eles[i].getAttribute(att)==value){ arr.push(eles[i]); } } }else{ for (var i = 0; i < eles.length; i++) { if(eles[i].getAttribute(att)){ arr.push(eles[i]); } } } return arr; } } function $(selector){ var all=selector.split(/s+/); var result = [],rooot=[document]; for (var i = 0; i < all.length; i++) { var type=all[i][0]; switch(type){ //ID case "#" : for (var j = 0; j < rooot.length; j++) { var ele=rooot[j].getElementById(all[i].slice(1)); if (ele) { result.push(ele); } } break; //class case ".": for (var j = 0; j < rooot.length; j++) { if (document.getElementsByClassName) { var eles=rooot[j].getElementsByClassName(all[i].slice(1)); if (eles) { result=result.concat(Array.prototype.slice.call(eles)); } }else{ var arr = rooot[j].getElementsByTagName("*"); for (var i = 0; i < arr.length; i++) { if (hasClass(arr[i], className)) { result.push(arr[i]); } } } } break; //属性 case "[": var att = all[i].slice(1,all[i].length-1).split("="); var key = att[0],value=att[1]; for (var j = 0; j < rooot.length; j++) { var eles=rooot[j].getElementsByTagName("*"); for (var i = 0; i < eles.length; i++) { if (value) { for (var i = 0; i < eles.length; i++) { if(eles[i].getAttribute(key)==value){ result.push(eles[i]); } } }else{ for (var i = 0; i < eles.length; i++) { if(eles[i].getAttribute(key)){ result.push(eles[i]); } } } } } break; //tag default: for (var j = 0; j < rooot.length; j++) { eles=rooot[j].getElementsByTagName(all[i]); if (eles) { result=result.concat(Array.prototype.slice.call(eles)); } } } rooot=result; result=[]; } return rooot[0]; } //检查ele是否有className function hasClass(ele,className){ if (ele&&ele.className) { var classes=ele.className.split(/s+/);//这里必须要切成数组之后再判断 if(classes.indexOf(className)!=-1){ return true; } } return false; } // 为element增加一个样式名为newClassName的新样式 function addClass(ele,newClass){ if (!hasClass(ele,newClass)) { ele.className=ele.className?[ele.className,newClass].join(" "):newClass; } } // 移除element中的样式oldClassName function removeClass(ele,oldClass){ if (hasClass(ele,oldClass)) { var arr = ele.className.split(/s+/); for (var i = 0; i < arr.length; i++) { if(arr[i]===oldClass){ arr.splice(i,1); break; } } ele.className=arr.join(" "); } } //获得元素的CSS样式 function getCSS(ele,name){ if (ele) { return document.defaultView.getComputedStyle? document.defaultView.getComputedStyle(ele,null)[name]:ele.currentStyle[name]; } } //添加事件 function addEvent(selector,event,listener){ var ele=$(selector); if(ele.addEventListener){ ele.addEventListener(event,listener,false); }else{ ele.attachEvent("on"+event,listener); } } //添加事件(给节点) function addEventToNode(ele,event,listener){ if(ele.addEventListener){ ele.addEventListener(event,listener,false); }else{ ele.attachEvent("on"+event,listener); } } //移除事件 function removeEvent(selector,event,listener){ var ele=$(selector); if(ele.removeEventListener){ ele.removeEventListener(event,listener,false); }else{ ele.detachEvent("on"+event,listener); } } function removeNodeEvent(ele,event,listener){ if(ele.removeEventListener){ ele.removeEventListener(event,listener,false); }else{ ele.detachEvent("on"+event,listener); } }
//阻止浏览器默认行为
function preventDefault(e){
if (e&&e.preventDefault) {
e.preventDefault();
}else{
e.returnValue=false;
}
return false;
}
$.prevent=preventDefault;
$.on = addEvent; $.add = addEventToNode; $.un = removeEvent; $.remove=removeNodeEvent;
//判断是否支持ondrag事件
function supportDrag(){
var div = document.createElement('div');
return ('draggable' in div) || ('ondragstart' in div && 'ondrop' in div);
}
参考:
教程:http://qiudeqing.com/html5/2015/05/17/drag-and-drop.html