拖放首先是由IE4.0引入的,一开始只有IE支持此功能。但现在已经作为HTML5的标准的一部分。
有2种行为可以实现拖放:系统拖放和模拟拖放,其中以前只有IE实现了系统拖放
系统拖放的优点:可以实现浏览器和桌面、浏览器和浏览器、窗口之间、框架页之间的移动;
拖放一开始只支持图像和文本拖放,后来进行了扩展,现在几乎所有元素都可被拖放了。
(一)系统拖放
1.拖放事件
拖放事件分为2种:在被拖放项的事件和在放置目标上的事件
1)被拖放项事件
某个项被触发时的事件触发顺序:dragstart; drag; dragend
dragstart: 当按下鼠标按钮,开始移动鼠标时,开始触发此事件
drag: 只要对象还在被拖得,此事件就会一直触发,类似mousemove
dragend:在拖放停止时(在有效或无效的放置对象上放下该项),则触发此事件
2)放置目标事件
当被拖放项拖到有效的放置目标上后触发顺序:dragenter; dragover; dragleave/drop
dragenter: 当被拖放项刚进入放置目标时触发,类似mouseover
dragover:当被拖放项在目标边界内将一直触发,当被拖放项被拖出目标后则停止触发
dragleave:当此目标不是被拖放项最终的放置目标,则在离开此目标时触发该事件,类似mouseout
drop: 当此目标正是被拖放项最终的放置目标,则触发此事件代替dragleave。
2种事件的触发顺序是:dragstart drag .... dragenter dragover..... drop dragleave dragend
注意:
所有的元素上都能绑定放置目标的事件,但并不保证此元素是有效的放置对象。
默认情况下,IE中只有文本框(<input/>或<textarea/>)是网页上唯一有效的放置目标。若想让其他元素变成有效的放置目标,则需要阻止dragenter和dragover事件的默认行为,因为这些只适用于IE。方法是在dragenter和dragover的事件处理函数中将event.returnValue设置为false(适用于IE事件).或调用event.preventDefault方法(适用于标准事件)。
2、dataTransfer数据传输对象
仅仅拖放是没有用的,除非数据通过拖放传递,这就需要dataTransfer对象了。
此对象是event的专属特性,只在事件处理函数中存在。调用方法是event.dataTransfer
2.1 方法setData()、getData()
一个用来设置数据,一个用来获取数据。
setData只能设置两种类型的值:text和URL。如果是文本选用text类型,如果是链接,选用URL类型
注意只有2个空间可以存储这2种类型的值,一个是放text的空间,一个是放URL的空间。每个空间只能放1一个值,所以如果重复调用setData(),会覆盖空间内已经存储的值。
存储在dataTransfer对象中的数据在drop事件发生前才有用,即如果在drop事件处理函数中没有去获取其中的数据,那么dataTransfer就会被销毁,数据就会丢失。
2.2 属性dropEffect和effectAllowed
dataTransfer对象不进可以用来传输数据,还能对被拖动的物体和放置目标定义动作。
dropEffect
作用于被放置目标的dragenter事件,用来设置放置目标上允许那种类型的放置行为,有4种取值:
- “none”:被拖放项不能放在此目标上,除文本框(<input/>或<textarea/>)外所有其他对象的默认值;
- “move”:表示被拖放的项要移动到该放置目标内;
- “copy”:表示被拖放的项要复制到放置目标内;
- “link”:表示被拖动的项(是URL类型的才有效)会在放置对象上打开浏览。
effectAllowed
作用于被拖动项的dragstart事件,设置被拖动项允许哪种类型的dropEffect。如果此属性没有设置,则dropEffect将不会起作用。
可能取值:
- "none":拖动项上不允许任何动作
- "copy":只允许“copy”的dropEffect
- "link":只允许“link”的dropEffect
- "move":只允许“move”的dropEffect
- "copyLink": 只允许“copy”和“link”的dropEffect
- "copyMove":只允许“copy”和“move”的dropEffect
- "linkMove":只允许“link”和“move”的dropEffect
- "all":允许所有类型的dropEffect。
示例代码:可能有错,但可以帮助理解
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <script type="text/javascript"> function handleDragDropEvent(event){ var text=document.getElementById("txt1"); text.value += event.type+"\n"; switch (event.type){ case "dragstart": event.dataTransfer.effectAllowed = "move"; event.dataTransfer.setData("text","hello"); break; case "dragover": event.returnValue = false; break; case "dragenter": event.dataTransfer.dropEffect = "move"; event.returnValue=false; break; case "drop": event.returnValue = false; (event.srcElement?event.srcElement:event.target).innerHTML= event.dataTransfer.getData("text"); } } </script> </head> <body> <form> <p> <img src="image/writer3.png" alt="image" width="100" height="100" ondragstart="handleDragDropEvent(event)" ondrag="handleDragDropEvent(event)" ondragend="handleDragDropEvent(event)" /> </p> <div style="width: 200px;height: 200px;border: 1px solid #ff0000" ondragenter="handleDragDropEvent(event)" ondragover="handleDragDropEvent(event)" ondragleave="handleDragDropEvent(event)" ondrop="handleDragDropEvent(event)"></div> <p> <!--此文本框用来观察事件触发顺序--> <textarea cols="25" rows="10" id="txt1" readonly="readonly"></textarea> </p> </form> </body> </html>
(二)模拟拖放
显然IE中系统拖放很强大,但要想开发在多个浏览器之间运行的拖放程序,系统拖放行不通,因为只有IE支持这个功能,其他浏览器没有开发这个功能。(当然HTML5之后就有所改变了)。那在其他不支持系统拖放的浏览器上就要靠模拟拖放来实现了。
模拟拖放的思想:创建可以跟着鼠标移动的绝对定位层,让用户感觉像是使用拖放。
将被拖放项和放置目标都设置为absolute定位,首先在被拖放项上注册mousedown事件,然后当鼠标在被拖放项上按下时,mousedown事件处理函数在body上注册mousemove和mouseup事件,最后当鼠标被松开时,即mouseup事件发生时,若被拖动项在放置目标边界内,则将被拖放项定位到放置目标上,同时删除body上的mousemove和mouseup事件。
其中要用到鼠标窗口坐标:event.clientX/event.clientY;被拖放项的offsetLeft和offsetTop;放置目标的offsetHeight和offsetWidth。
直接贴源代码了:检测运行正常
<!DOCTYPE html> <html> <head> <title>drag event</title> <style type="text/css"> body{ width: 100%; height: 800px; } #div1{ background-color: #ff0000; height: 100px; width: 100px; position: absolute;/*被拖动项要为绝对定位*/ } #target{ width: 500px ; height: 500px; border: 1px solid #ff0000; position: absolute;/*放置对象也要为决对定位*/ left: 500px; } </style> <script type="text/javascript"> //定义可以拖放的对象 var diffX=0; var diffY=0; var oDiv; var target; window.onload=function(){ oDiv= document.getElementById('div1');//被拖动项 target=document.getElementById("target");//放置目标 } function handleMouseMove(e){ oDiv.style.left=(e.clientX-diffX)+"px"; oDiv.style.top = (e.clientY-diffY)+"px"; } function handleMouseDown(e){ diffX=e.clientX - oDiv.offsetLeft; diffY=e.clientY - oDiv.offsetTop; if(document.body.attachEvent){ document.body.attachEvent("onmousemove",handleMouseMove) document.body.attachEvent("onmouseup",handleMouseUp); } else { document.body.addEventListener("mousemove",handleMouseMove,false); document.body.addEventListener("mouseup",handleMouseUp,false); } } function handleMouseUp(e){ if(document.body.detachEvent){ document.body.detachEvent("onmousemove",handleMouseMove); document.body.detachEvent("onmouseup",handleMouseUp); }else{ document.body.removeEventListener("mousemove",handleMouseMove,false); document.body.removeEventListener("mouseup",handleMouseUp,false); } if(isOverDropTarget(e.clientX,e.clientY)){ oDiv.style.left=target.offsetLeft+"px"; oDiv.style.top=target.offsetTop+"px"; } } //定义放置目标,先判断鼠标的坐标是否位于放置目标内 function isOverDropTarget(x,y){ var x1 = target.offsetLeft; var x2 = x1+target.offsetWidth; var y1 = target.offsetTop; var y2 = y1+target.offsetHeight; var isDragOver=x>=x1&&x<=x2&&y>=y1&&y<=y2; return(isDragOver); } </script> </head> <body> <p>try mocing your mouse</p> <div id="div1" onmousedown="handleMouseDown(event);"></div> <div id="target"></div> </body> </html>