在HTML5中你可以拖拽页面中指定的HTML元素。通过使用javascript事件监听,你可以决定元素在拖拽元素之后所发生的事情。
用于拖放的HTML元素中可以是以下两个角色:
- Draggable(可拖动元素)
- Drop target / drop zone(放置目标/放置区域)
可拖动的元素是指用户可以在页面中拖动并放置在其它地方的元素。它可以是一个或多个元素。
放置目标或放置区域是可拖动元素被放置的区域。
拖放事件
为了控制HTML元素的拖放,你需要执行3个步骤:
- 选择一个HTML元素来拖动
- 为拖动的HTML元素添加事件监听
- 为放置HTML元素的区域添加事件监听
下图列出了拖放的事件和属性:
首先,你需要在准备进行拖动的元素上设置draggable="true"
,使它可以被拖动。
接着你需要为拖动元素设置dragstart
和dragend
事件监听。在这些事件中,你可以设置元素在开始拖动和结束拖动时发生的事情。
然后你需要在放置区域元素上添加事件监听,你可以监听的事件有:dragenter
,dragover
,dragleave
和drop
。
dragenter
事件在你拖动元素到放置区域上方时被触发。这个事件只有在拖动元素从放置区域外部进入放置区域时被触发,这里通常是由鼠标的位置来决定的。
当拖动元素经过放置区域的时候,dragover
事件会被触发。并会在拖动元素在放置区域内移动时持续触发。
如果你将拖动元素移到放置区域之外,dragleave
事件将被触发。
如果你将拖动元素放置在放置区域之内,drop
事件将被触发。
拖放事件的例子
下面是一个拖放事件的例子。你可以将HTML5的logo拖拽到放置区域中,看看右边的数据统计,还可以打开浏览器的控制台看看拖动元素被放下后的信息。
dragend:
dragenter:
dragover:
dragleave:
drop:
元素拖放代码
下面让我们来看一下如何处理拖放事件。我们首先创建一个可以拖拽的图片元素。下面是它的HTML代码:
<img id="draggagle1" src="img/html5.png" draggable="true">
然后我们需要一个放置的区域。这里使用一个<div>
来制作。
<div id="droptarget1">放置区域</div>
在完成上面的步骤之后,我们需要为它们添加事件监听。事件监听的代码如下:
<script> var draggable = document.getElementById("draggable1"); draggable.addEventListener('dragstart', dragStart, false); draggable.addEventListener('dragend' , dragEnd , false); var droptarget = document.getElementById("droptarget1"); droptarget.addEventListener('dragenter', dragEnter , false); droptarget.addEventListener('dragover' , dragOver , false); droptarget.addEventListener('dragleave', dragLeave , false); droptarget.addEventListener('drop' , drop , false); /* Draggable event handlers */ function dragStart(event) { event.dataTransfer.setData('text/html', "You dragged the image!"); } function dragEnd(event) { } /* Drop target event handlers */ function dragEnter(event) { } function dragOver(event) { event.preventDefault(); return false; } function dragLeave(event) { } function drop(event) { var data = event.dataTransfer.getData('text/html'); event.preventDefault(); return false; } </script>
为了在拖放操作时实现数据交换,IE5引入了dataTransfer
对象,它是事件对象的一个属性,用于从被拖动元素向放置目标传递字符串格式的数据。因为它是事件对象的属性,所以只能在拖放事件的事件处理程序中访问dataTransfer对象。在事件处理程序中,可以使用这个对象的属性和方法来完善拖放功能。目前,HTML5规范草案也收入了dataTransfer对象。
dataTransfer
对象有两个主要方法: getData()
和setData()
。getData()
可以取得由setData()
保存的值。setData()
方法的第一个参数,也是getDAta()
方法唯一的一个参数,是一个字符串,表示保存的数据类型,取值为”text”或“URL”,例如:
//设置和接收文本数据 event.dataTransfer.setDAta("text", "some text"); var text = event.dataTransfer.getData("text"); //设置和接收URL event.dataTransfer.setData("URL", "HTML://www.htmleaf.com/");
IE浏览器只定义了“text”和“URL”两种有效的数据类型,而HTML5则对此加以扩展,允许指定各种MIME类型。考虑到向后兼容,HTML5也支持“text”和“URL”,但这两种类型会被映射为“text/plain”和“text/uri-list”。
实际上,dataTransfer
对象可以为每种MIME类型都保存一个值。换句话说,同时在这个对象中保存了一段文本和一个URL不会有任何问题。不过,保存在dataTransfer
对象中的数据只能在drop事件处理程序中读取。如果在ondrop
处理程序中没有读到数据,那就是dataTransfer
对象已经被销毁,数据也丢失了。
在拖动文本框中的文本时,浏览器会调用setData()
方法,将拖动的文本以“text”格式保存在dataTransfer
对象中。类似地,在拖放链接或图像时,会调用setData()
方法并保存URL。然后,在这些元素被拖放到放置目标时,就可以通过getData()
读到这些数据。当然,作为开发人员,你也可以在dragstart
事件处理程序中调用setData()
,手工保存自己要传输的数据,以便将来使用。
将数据保存为文本和保存为URL是有区别的。如果将数据保存为文本格式,那么数据不会得到任何特殊处理。而如果将数据保存为URL,浏览器会将其当成网页中的链接。换句话说,如果你把它放置到另一个浏览器窗口中,浏览器就会打开该URL。
Firefox在其第5个版本之前不能正确地将“URL”和“text”映射为“text/uri-list”和“text/plain”。但是却能把“Text”映射为“text/plain”。为了更好地在跨浏览器的情况下从dataTransfer
对象取得数据,最好在取得URL数据时检测两个值,而在取得文本数据时使用“text”。
var dataTransfer = event.dataTransfer; //读取URL var url = dataTransfer.getData("url") || dataTransfer.getData("text/uri-list"); //读取文本 var text = dataTransfer.getData("Text");
注意,一定要把短数据类型放在前面,因为IE10及之前的版本仍然不支持扩展的MIME类型名,而它们在遇到无法识别的数据类型时,会抛出错误。
DataTransfer对象、effectsAllowed、dropEffect和setDragImage()
在上面我们已经介绍了一些关于DataTransfer
对象的知识。DataTransfer
能够在拖放元素的过程中给用户提供一些视觉效果。DataTransfer
对象有两个属性和一个方法可以使用。它们是:
effectsAllowed
dropEffect
setDragImage()
你可以在dragstart
和drop
事件中访问DataTransfer
对象。在下面的例子中,dragstart
监听事件中在DataTransfer
对象上设置了effectsAllowed
属性。
function dragStart(event) { event.dataTransfer.effectsAllowed = "copy"; event.dataTransfer.setData('text/html', "You dragged the image!"); event.target.style.border = "1px solid #cccccc"; }
effectsAllowed
属性用于在元素拖放的过程中显示鼠标的样式。典型的例子是拖动一个元素经过放置区域时,鼠标会发生变化。effectsAllowed
属性的可选值有:
none
copy
move
copyMove
link
linkMove
copyLink
all
uninitialized
dropEffect
属性是拖动一个元素经过放置区域时,鼠标的样式。(似乎目前的浏览器还不支持这个属性)。它的可选值有:
none
copy
link
move
setDragImage(image, x, y)
函数可以在用户拖动元素时显示指定的图片。默认情况下,在拖动元素的时候显示的是一个半透明的元素副本,可以通过这个函数来设置不同的图片。x
和y
属性用于设置显示图片位置的偏移。
下面是一个使用dragStart()
函数的示例代码:
function dragStart(event) { event.dataTransfer.effectAllowed = "all"; event.dataTransfer.dropEffect = "copy"; var dragImage = document.createElement('img'); dragImage.src = dragImageUrl; dragImage.width = 75; event.dataTransfer.setDragImage(dragImage, 0, 0); event.dataTransfer.setData('text/html', "You dragged the image!"); event.target.style.border = "1px solid #cccccc"; }
拖动文件到浏览器中
我们还可以将操作系统中的文件拖拽到浏览器中,并通过HTML5 File API来查看文件的名称和内容。下面是一个示例代码:
var droptarget2 = document.getElementById("droptarget2"); droptarget2.addEventListener('drop', drop , false); function drop(event) { // Files - array of dragged files. var files = event.dataTransfer.files; for(var i= 0; i < files.length; i++){ var file = files[i]; console.log("file: " + file.name); } event.preventDefault(); return false; }
注意这里drop()
方法中不是调用getData()
函数,而是访问DataTransfer
的files
属性。files
属性包含被拖动到浏览器中的文件列表。HTML5 File API将在后面的文章中详细介绍。