拖放(Drag 和 drop)是 HTML5 标准的组成部分。
拖放
拖放是一种常见的特性,即抓取对象以后拖到另一个位置。
在 HTML5 中,拖放是标准的一部分,任何元素都能够拖放。
拖放事件
1.拖动某元素时,将依次触发下列事件:
(1)dragstart:按下鼠标并开始移动时,会在被拖放的元素上触发dragstart事件
(2)drag:触发dragstart事件后,随即就会触发drag事件,而且爱元素被拖动期间会持续触发该事件
(3)dragend:当拖动停止时(无论是把该元素放到了有效的放置目标上还是放到了无效的放置目标上),会触发dragend事件
上面这三个事件的目标都是被拖动元素,大多数浏览器会为正在被拖动的元素创建一个半透明的副本,这个副本始终跟随着光标移动。
2.当某个元素被拖动到一个有效的放置目标上时,下列事件会依次触发:
(1)dragenter:只要有拖动元素被拖动到放置目标上,就会触发dragenter事件
(2)dragover:在被拖动元素爱放置目标的范围内移动时,就会持续触发改事件
(3)dragleave 或drop:当被拖动元素拖出了放置目标,将触发dragleave事件,如果元素被放到了放置目标中,则会触发drop,而不会触发dragleave事件。
什么是有效的的放置目标呢?在拖动元素经过某些无效放置目标时,可以看到一种特殊的光标(圆环中有一条反斜杠),表示不能放置。虽然所有元素都支持放置目标事件,但这些元素默认是不允许放置的,所有要想把任何元素变成有效的放置目标,方法是重写dragenter 和dragover事件的默认行为,也就是event.preventDefault()。这样,当被拖动元素移动到放置目标上时,光标变成了允许放置的符号,释放鼠标时,也会触发drop事件。但是drop事件的默认行为是打开被放盗放置目标上的URL,当吧文本拖放到放置目标上,则会导致无效的URL错误,因此为了让Firfox致辞正常的拖放,还要取消drop事件的默认行为。
其它需要关注的属性:
- DataTransfer 对象:退拽对象用来传递的媒介,使用一般为Event.dataTransfer。
- draggable 属性:就是标签元素要设置draggable=true,否则不会有效果,例如:
<div title="拖拽我" draggable="true">列表1</div>
- event.preventDefault() 方法:阻止默认的些事件方法等执行。在ondragover中一定要执行preventDefault(),否则ondrop事件不会被触发。另外,如果是从其他应用软件或是文件中拖东西进来,尤其是图片的时候,默认的动作是显示这个图片或是相关信息,并不是真的执行drop。此时需要用用document的ondragover事件把它直接干掉。
- event.dataTransfer.effectAllowed 属性:就是拖拽的效果。
- evetn.dataTransfer.setDragImage(img, x, y) 方法:指定图片或者文档元素做拖动时的视觉效果。该函数主要用在ondragstart事件中,用来设置拖拽时显示的图片,该方法有三个参数,需要显示的图片元素,光标相对图片的横向和纵向的偏移。
DnD总是基于事件且Javascript API包含两个事件集,一个是在拖放源上触发,另一个在拖放目标上触发。所有传递给DnD事件处理程序的事件对象都类似鼠标事件对象,另外他拥有dataTransfer属性。这个属性引用DataTransfer对象,该对象定义DnD API的方法和属性。
拖放源时间相当简单,我们就从他们开始。任何有HTML draggable属性的文档元素都是拖放源。当用户开始用鼠标在拖放源上拖动时,浏览器并没有选择元素内容,相反,它在这个元素上触发dragstart事件,这个事件的处理程序就调用dataTransfer.setData()指定当前可用的拖放源数据(和数据类型)。这个时间处理程序也可以设置dataTransfer.effectAllowed来指定支持“移动”、“复制”和“链接”传输操作中的集中,同时他可以调用dataTransfer.setDragImage()指定图片或者文档元素做拖动时的视觉效果。
当放置数据发生时会触发dragend事件。如果拖放源支持“移动”操作,它就会检查dataTransfer.dropEffect去看看是否实际执行了移动操作。如果执行了,数据就被传输到其他地方,你就应该从拖放源中删除它。
事件对象dataTransfer
dataTransfer是事件对象的一个属性,用于从被拖动元素向放置目标传递字符串格式的数据,因为它是事件对象的属性,所以只能在拖放事件的事件处理程序中访问dataTransfer对象。在事件处理程序中,可以使用这个对象的属性和方法,来完善拖放功能,
dataTransfer对象主要有两个方法:setData() 和 getData(),getData()可以取得由setData()保存的值,setData()方法的第一个参数,也是getData()方法的唯一一个参数,是一个字符串,表示保存的数据类型,取值为"text"或"URL"。
例如:
//设置和接收文本数据
event.dataTransfer.setData("text","some text");
var text=event.dataTransfer.getData("text");
//设置和接收URL
event.dataTransfer.setData("URL","http://www.blog.com/");
event.dataTransfer.getData("URL");
IE只定义了"text"和"URL"两种有效的数据类型,而HTML5则对此加以扩展,允许指定各种MIME类型,考虑到向后兼容,H5也支持"text"和"URL",但这两种类型会被映射为"text/plain"和"text/uri-list"。实际上,dataTransfer对象可以为每种MIME类型都保存一个值,保存在dataTransfer对象中的数据只能在drop事件处理程序中读取,如果没有在onDrop处理程序中读到数据,那就是dataTransfer对象已被销毁,数据也丢失了。
将数据保存为文本和保存为URL是有区别的,如果将数据保存为文本格式,那么数据不会得到任何特殊处理,而如果将数据保存为URL,浏览器会将其当成网页中的链接,,也就是如果你把它放置到另一个浏览器窗口中,浏览器就会打开该URL。
由于Firfox在其第5个版本之前不能正确的将"url"和"text"映射为"text/uri-list"和"text/plain",但是却能把"Text"(T大写)映射为"text/plain",为了更好的在跨浏览器的情况下从dataTransfer对象取得数据,最好在取得URL数据是检测两个值,而在取得文本数据时使用"Text"。
//读取URL
var url=event.dataTransfer.getData("url")||event.dataTransfer.getData("text/uri-list");
//读取文本
vat text=dataTransfer.getData("Text");
注意。一定要把端数据类型放在前面,因为IE10及之前的版本仍然不支持扩展的MIME类型名。在遇到无法识别的数据类型时,会报错。
dropEffect 和 effectAllowed属性
dataTranfer 对象的两个属性:dropEffect 和 effectAllowed,这两个属性用来确定被拖动元素以及作为放置目标的元素能够接收什么操作。
通过dropEffect属性可以知道被拖动元素能够执行哪种放置行为,这个属性有4个可能的值:
(1)"none":不能把拖动的元素放在这里,这是除文本框之外所有元素的默认值
(2)"move":应该把拖动的元素移动到放置目标
(3)"copy":应该把拖动的元素复制到放置目标
(4)"link":表示放置目标会打开拖动的元素(但拖动的元素必须是一个链接,有URL)
把元素拖动到放置目标上时,以上每一个值都会导致光标显示为不同的符号。要使用dropEffect属性,必须在ondragenter事件处理程序中针对放置目标来设置它。
dropEffect属性只有搭配effectAllowed属性才有用。effectAllowed属性表示允许拖动的元素的哪种dropEffect,effectAllowed属性可能的值有:
(1)"uninitialized":没有给被拖动元素设置任何放置行为
(2)"none":被拖动的元素不能有任何行为
(3)"copy":只允许值为"copy"的dropEffect
(4)"link":只允许值为"link"的dropEffect
(5)"move":只允许值为"move"的dropEffect
(6)"copyLink":只允许值为"copy"和"link"的dropEffect
(7)"copyMove":只允许值为"copy"和"move"的dropEffect
(8)"linkMove":只允许值为"link"和"move"的dropEffect
(9)"all":允许任意dropEffect
注意,必须在ondragstart事件处理程序中设置effectAllowed属性。
浏览器支持
Internet Explorer 9、Firefox、Opera 12、Chrome 以及 Safari 5 支持拖放。
注释:在 Safari 5.1.2 中不支持拖放。
HTML5 拖放实例
下面的例子是一个简单的拖放实例:
实例
<!DOCTYPE HTML> <html> <head> <script type="text/javascript"> function allowDrop(ev) { ev.preventDefault(); } function drag(ev) { ev.dataTransfer.setData("Text",ev.target.id); } function drop(ev) { ev.preventDefault(); var data=ev.dataTransfer.getData("Text"); ev.target.appendChild(document.getElementById(data)); } </script> </head> <body> <div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)"></div> <img id="drag1" src="img_logo.gif" draggable="true" ondragstart="drag(event)" width="336" height="69" /> </body> </html>
设置元素为可拖放
首先,为了使元素可拖动,把 draggable 属性设置为 true :
<img draggable="true" />
拖动什么 - ondragstart 和 setData()
然后,规定当元素被拖动时,会发生什么。
在上面的例子中,ondragstart 属性调用了一个函数,drag(event),它规定了被拖动的数据。
dataTransfer.setData() 方法设置被拖数据的数据类型和值:
function drag(ev) { ev.dataTransfer.setData("Text",ev.target.id); }
在这个例子中,数据类型是 "Text",值是可拖动元素的 id ("drag1")。
放到何处 - ondragover
ondragover 事件规定在何处放置被拖动的数据。
默认地,无法将数据/元素放置到其他元素中。如果需要设置允许放置,我们必须阻止对元素的默认处理方式。
这要通过调用 ondragover 事件的 event.preventDefault() 方法:
event.preventDefault()
进行放置 - ondrop
当放置被拖数据时,会发生 drop 事件。
在上面的例子中,ondrop 属性调用了一个函数,drop(event):
function drop(ev) { ev.preventDefault(); var data=ev.dataTransfer.getData("Text"); ev.target.appendChild(document.getElementById(data)); }
代码解释:
- 调用 preventDefault() 来避免浏览器对数据的默认处理(drop 事件的默认行为是以链接形式打开)
- 通过 dataTransfer.getData("Text") 方法获得被拖的数据。该方法将返回在 setData() 方法中设置为相同类型的任何数据。
- 被拖数据是被拖元素的 id ("drag1")
- 把被拖元素追加到放置元素(目标元素)中