4.5 文件拖放API和常用对象
在HTML 4以及之前的版本中,如果要实现文件(例如文本文件、图像文件)的拖放功能,则需要借助mousedown、mousemove和mouseup事件来实现在浏览器内部的拖放操作。而在HTML 5中提供了对文件拖放的支持,下面将介绍常见的拖放API事件,以及常用的DataTransfer对象。
4.5.1 拖放API
HTML 5中直接提供了支持文件拖放操作的API,使用这些API不仅能够实现浏览器内部的拖放操作,也已经支持在浏览器与其他应用程序之间的数据的互相拖动,同时也大大简化了与拖放有关的代码。
HTML 5中支持多个与拖放操作有关的事件,这些事件的说明如表4-5所示。
表4-5 HTML 5中与拖放有关的事件
相关人员可以在JavaScript中编写与元素有关的事件代码,但是,在实现文件的拖放功能之前还需要一步,就是将想要拖放的对象的元素的draggable属性的值设置为true,这表示允许该元素进行拖放。另外,img元素和a元素(必须指定href属性)默认情况下允许拖放。
【练习9】
在本次练习中,页面会显示一些图像,这些图像表示简单的网络配置工具。用户可以在各个区域之间拖放这些资源图像,也可以向区域中添加资源图像,还可以将没有用的资源图像放到垃圾箱中。但是需要注意,实现拖放效果时还有部分图像是不能拖放删除的,其实现步骤如下。
(1)创建新的页面并进行设计,在页面中的合适位置添加两个表格,这两个表格实现布局结构,并且把它当作ondrop事件的目标。第一个表格包含两行三列,第一行表示每张图像的名称,第二行则表示对象的文件。在第二行显示的图像文件中添加代码,将能够拖放的文件的draggable属性的值设置为true,否则设置为false,然后再为能够拖放的td元素添加ondrop、ondragenter和ondragover等事件。代码如下。
<tr> <td width="40%" align="center" id="red" ondrop="dropIt(this, event)" ondragenter="return false" ondragover="return false"><span draggable="true" id="mf" ondragstart="dragIt(this, event)"><img src="leftright_files/n_main.jpg" width="75" height="105"></span></td> <td width="20%" align="center"><img src="leftright_files/n_firewall.jpg" draggable="false"></td> <td width="40%" align="center" id="blue" ondrop="dropIt(this, event)" ondragenter="return false" ondragover="return false"><span draggable="true" id="hub" ondragstart="dragIt(this, event)"><img src="leftright_files/n_hub.jpg"></span></td> </tr>
(2)第二个表格包含两行两列,分别向表格中添加图像,并且设置有关的属性和事件,在表格中还使用了span元素(能够包裹图像)作为拖放对象。代码如下。
<table width="485" border="1" cellspacing=0 cellpadding=5> <tr> <td width="20%" valign="bottom" align="center"><span id="bucket3" ondragenter="return false" ondragover="return false" ondrop="trashIt(this, event)"><img src="leftright_files/n_trash.jpg" draggable="false"></span></td> <td width="80%" valign="bottom" align="left" id="holder" ondrop="dropIt(this, event)" ondragenter="return false" ondragover="return false"> <span draggable="true" id="pc" ondragstart="dragIt(this, event)"><img src="leftright_files/n_pc.jpg"></span><span draggable="true" id="ids" ondragstart="dragIt(this, event)"><img src="leftright_files/n_ids.jpg"></span><span draggable="true" id="lt" ondragstart="dragIt(this, event)"><img src="leftright_files/n_laptop.jpg"></span><span draggable="true" id="srv" ondragstart="dragIt(this, event)"><img src="leftright_files/n_server.jpg"></span> </td> </tr> <tr bgcolor="#F2F2F2"> <td width="20%" class="tableheader" valign="top" align="center"><p>垃圾箱</p></td> <td class="tableheader" width="80%" valign="top" align="left"><p>当前的资源文件</p></td> <tr> </table>
(3)在JavaScript脚本中分别添加名称是dragIt、dropIt和trashIt的函数,并且向这些函数中添加代码。如下所示。
function dragIt(target, e) { e.dataTransfer.setData('SpanImg', target.id); //为元素添加指定的数据 } function dropIt(target, e) { var id = e.dataTransfer.getData('SpanImg'); //返回指定的数据 target.appendChild(document.getElementById(id)); e.preventDefault(); //不执行默认处理,拒绝被拖放 } function trashIt(target, e) { var id = e.dataTransfer.getData('SpanImg'); //返回指定的数据 removeElement(id); //其他元素拖动到该元素时,删除其他元素 e.preventDefault(); //不执行默认处理,拒绝被拖放 } function removeElement(id) { //移除元素 var d_node = document.getElementById(id); d_node.parentNode.removeChild(d_node); }
(4)运行页面查看页面效果,拖动页面中的图像到垃圾箱中,如图4-24和图4-25所示分别为拖动资源图像时的效果。
图4-24 Chrome浏览器拖曳效果
图4-25 Opera浏览器拖曳效果
(5)确定将当前操作的资源图像放到垃圾箱后会删除图像,不会再显示图像到页面中,移除后的效果如图4-26所示。用户也可以拖动某个区域的图像到另一个区域中,完成时的效果如图4-27所示。
图4-26 Chrome浏览器中完成拖放效果
图4-27 在Opera的区域拖放移动图像
4.5.2 认识DataTransfer对象
只有简单的拖放而没有数据的变化是没有什么大作用的,为了在拖放操作时实现数据交换,部分浏览器已经支持DataTransfer对象,它是事件对象的一个属性,用于从拖动元素向放置目标传递字符串格式的数据。细心的读者可以发现,练习9中已经使用到了DataTransfer对象以及它的方法。
DataTransfer对象提供了对于预定义的剪贴板格式的访问,以便在拖放操作中使用,可以通过event对象完成这种功能。由于DataTransfer是事件对象的属性,所以只能在拖放事件的事件处理程序中访问DataTransfer对象。
DataTransfer对象既可以在源对象中使用,也可以在目标对象中使用。该对象可以包含多个属性和方法,在事件处理程序中,可以使用DataTransfer对象的属性和方法来完成拖放功能,HTML 5也提供了对该对象的支持,并且对其加以扩展。
4.5.3 DataTransfer对象的方法
DataTransfer对象有多个方法,其中,getData()和setData()方法最为常用,除了这两个方法外,还提供了其他的方法,如表4-6所示。
表4-6 DataTransfer对象的方法说明
setData()方法用于源事件,以便提供关于将要进行传送的数据。相应地,getData()方法用于目标事件以便确保获取的数据和数据格式。例如,可以通过setData()方法设置一个文本数据,并且通过getData()方法来接收数据。代码如下。
event.dataTransfer.setData("text", "this is a text data"); var text = event.dataTransfer.getData("text");
【练习10】
本次练习中使用了DataTransfer对象的setData()方法和getData()方法,用户拖动超链接到指定的元素,拖放成功后重新显示目标元素span的文本,步骤如下。
(1)在网页中添加源元素和目标元素,其中,源元素是被拖动的元素,使用a元素来表示;目标元素是被放置的元素,通过span元素来表示。代码如下。
<a ID=oSource href="about:config " onclick="return(false)" ondragstart="InitiateDrag()" style="color:red;">测试锚</a> <span id=oTarget ondragenter="FinishDrag()">将链接拖曳到这里</span>
(2)在JavaScript脚本中分别为源元素和目标元素添加函数,在InitiateDrag()函数中设置DataTransfer对象的setData()方法,它告诉源对象将数据传送为URL并且提供路径;FinishDrag()函数中调用getData()方法,它告诉目标对象所期望的数据格式。代码如下。
var sAnchorURL; function InitiateDrag() { event.dataTransfer.setData("URL", oSource.href); } function FinishDrag() { sAnchorURL = event.dataTransfer.getData("URL"); oTarget.innerText = sAnchorURL; }
(3)运行页面,拖动源对象到目标对象,拖动完成后可以发现,目标对象的值更改为“about:config”,具体效果图不再显示。
4.5.4 DataTransfer对象的属性
使用DataTransfer对象不仅能够传输数据,还能够通过它来确定被拖动元素以及作为放置目标的元素能够接受什么操作,这就需要使用到它的属性,具体说明如表4-7所示。
表4-7 DataTransfer对象的属性说明
dropEffect属性只有与effectAllowed属性搭配时才有用,如果它所设置的效果与effectAllowed属性设置的效果不符,则拖放操作失败。dropEffect属性的可能值有4个,具体说明如下。
(1)none:不能把拖动的元素放在这里。这是除文本框之外所有元素的默认值。
(2)move:应该把拖动的元素移动到放置目标。
(3)copy:应该把拖动的元素复制到放置目标。
(4)link:表示放置目标会打开拖动的元素(但拖动的元素必须是一个链接,存在URL)。
与dropEffect属性相比,effectAllowed属性的值有多个,除了上面4个外,还包含其他的值,具体说明如下。
(1)none:被拖动的元素不能有任何行为。
(2)move:只允许值为“move”的dropEffect。
(3)copy:只允许值为“copy”的dropEffect。
(4)link:只允许值为“link”的dropEffect。
(5)linkMove:允许值为“link”和“move”的dropEffect。
(6)copyMove:允许值为“copy”和“link”的dropEffect。
(7)copyLink:允许值为“copy”和“link”的dropEffect。
(8)uninitialized:没有该被拖动元素放置行为。
(9)all:允许任意dropEffect。
注意
如果要使用dropEffect属性,必须在ondraggenter事件处理程序中针对目标元素来进行设置;如果要使用effectAllowed属性,必须在ondraggstart事件处理程序中进行设置。
如下代码演示了属性的简单使用。
source.addEventListener("dragstart", function(ev){ var dt = ev.dataTransfer; //向dataTransfer对象中追加数据 dt.effectAllowed = "all"; dt.setData("text", "拖动文本"); //设置拖动元素的值 }, false); dest.addEventListener("dragend", function(ev){ ev.preventDefault(); //不执行默认处理(拒绝被拖放) })
dropEffect属性与effectAllowed属性的值设置必须合法,如下总结了一些常用的规则。
(1)如果effectAllowed属性设置为none,则不允许拖放要拖放的元素。
(2)如果dropEffect属性设置为none,则不允许被拖放到目标元素中。
(3)如果effectAllowed属性设置为all或不设置,则dropEffect属性允许被设置为任何值,并且按其指定的值进行显示。
(4)如果effectAllowed属性设置为具体效果值(不为none和all)时,dropEffect属性也设置了具体效果值,则两个值必须完全相等,否则不允许被拖放元素拖放到目标元素中。