HTML5 的拖拽介绍

jopen 12年前

本文主要介绍与拖拽操作相关的对象及事件信息,但并不涉及太多的源码演示。

一个简单的示例

在html5中要实现拖放操作,相对于以前通过鼠标操作实现,要简单得多,数据安全性也更有保障。只需要以下几步即可。

  1. 给被拖拽元素添加draggable属性,如果是文件拖放。
  2. 为目标元素添加一个dropzone属性,这一步也不是必须的,可以省略。
  3. 在拖拽元素的dragstart中初始化相关的数据信息,主要是DataTransfer对象。
  4. 在目标元素的dragover事件中,取消其默认操作。
  5. 在目标元素的drop事件中,处理接受到的数据。
  6. 在被拖拽元素的dragend事件中,做善后工作。若没有则可以省略。

大致代码如下:

    <div id="source" draggable="draggable">source</div>      <div id="target">target</div>      <script type="text/javascript">      var target = document.getElementById('target');      var source = document.getElementById('source');      source.ondragstart = function(e){        e.dataTransfer.effectAllowed = 'copyMove';        e.dataTransfer.setData('test', 'testData');      };      target.ondragover = function(e){        e.dataTransfer.dropEffect = 'move';        e.preventDefault(); // 不能少      };      target.ondrop = function(e){        var elem = document.createElement('a');        elem.innerHTML = e.dataTransfer.getData('test');        e.target.appendChild(elem);      };      </script>

draggable属性

draggable是一个枚举属性,用于指定一个标签是否可以被拖拽。有以下四种取值:

  1. true:表示此元素可拖拽。
  2. false:表示此元素不可拖拽。
  3. auto:除img和带href的标签a标签表示可拖拽外,其它标签均表示不可拖拽。
  4. 其它任何值:表示不可拖拽。

dropzone属性

这个属性用于接受拖拽元素的目标元素上,表示能接受的数据类型及操作方式。多个值用空格分开,不区分大小写。其值有以下类型组成:

  • copy:表示将允许的元素放到该元素上时,会将拖拽数据复制到目标元素上。
  • link:表示将允许的元素放到该元素上时,将链接数据到目标元素上。
  • move:表示将允许的元素放到该元素上时,会将数据移动到目标元素上。
  • string:开头的字符串,长度不能小于8个字符:表示能接受DataTransferItem.kind值为stringdata对象。
  • file:开头的字符串,长度不能小于6个字符:表示能接受DataTransferItem.kind值为fileDataTransferItem.type的值匹配file:之后的字符的DataTransferItem的对象。

相关的事件

DragEvent接口定义

DragEventMouseEvent接口继承,其定义如下,与MouseEvent相比,只是多了个DataTransfer对象。所有针对拖拽的操作也是通过控制此对象来完成的。

    [Construct(DOMString type, optional DragEventInit eventInitDict)]      interface DragEvent : MouseEvent      {        readonly attribute DataTransfer? dataTransfer;      };      /* 这是用于初始事件的参数定义 */      dictionary DragEventInit : EventInit      {        // 从UIEvent继承的属性:        Window? view = null;        long detail = 0;        // 从MouseEvent继承的属性:        long screenX = 0;        long screenY = 0;        long clientX = 0;        long clientY = 0;        boolean ctrlKey = false;        boolean shiftKey = false;        boolean altKey = false;        boolean metaKey = false;        unsigned short button = 0;        unsigned short buttons = 0;        EventTarget? relatedTarget = null;        // DragEvent添加的新属性:        DataTransfer? dataTransfer;      }

事件描述

拖拽相关事件
事件名称 事件目标 可撤消? 存储模式1 dropEffect值 默认操作 备注
1.存储模式是针对于DataTransfer对象的操作,具体数据见后表。
dragstart 被拖拽元素 读、写 none 初始化操作 若调用preventDefault()函数取消此事件的默认行为,则拖拽功能将被取消。
drag 被拖拽元素 保护模式 none
在dragstart之后,释放鼠标之前,不管鼠标是否移动,此事件不停地被触发。
dragenter 目标元素 保护模式 effectAllowed限定的值。 更换目标元素。 进入目标元素时,触发一次。
dragleave 离开前的目标元素 保护模式 none
离开时触发一次。
dragover 目标元素 保护模式 effectAllowed限定的值 重置dropEffect为none,并中断后续事件执行。 在dragenter之后,dragleave之前,不管是否移动,此事件都将不停地触发。
drop 目标元素 只读模式 当前设定的值
释放鼠后,由目标元素触发。
dragend 被拖拽元素 保护模式 当前设定的值
释放鼠标后,由被拖拽元素触发,顺序在drop之后。

目标元素是指当前鼠停留的元素,如要将A元素拖放到F元素上,中间经过的所有元素,在鼠标经过期间都是一个目标素,相应的事件都会被触发,A元素本身就是第一个目标元素。

DataTransfer接口

在HTML5中,为了实现在拖放过程中的数据交换,给所有的拖拽事件提供了一个DataTransfer属性。通过此对象的方法和属性来完善拖放功能。

    interface DataTransfer      {        attribute DOMString dropEffect;        attribute DOMString effectAllowed;        void setDragImage(Element image, long x, long y);        readonly attribute DOMString[] types;        DOMString getData(DOMString format);        void setData(DOMString format, DOMString data);        void clearData(optional DOMString format);        readonly attribute DataTransferItemList items;        readonly attribute FileList files;      }

effectAllowed和dropEffect

这两个属性用于描述在拖拽过程中,鼠标显示的样式,受浏览器和操作系统的影响,鼠标显示的图标并不一致。

effectAllowed表示此次拖拽允许显示的鼠标样式,可以是以下值:nonecopycopyLinkcopyMovelinklinkMovemovealluninitialized。只能在dragstart事件中更改此值。

dropEffect表示此次拖拽过程中显示的样式,可以是以下几个值:copymovelinknone。在具体的拖拽过程中,还受effectAllowed值限定,具体限定内容见下表,当dropEffect的值被设置为一个不属于effectAllowed限定的值时,整个事件链将被中止,即后续事件都将不会被触发,但不会发生任何错误提示。

effectAllowed与dropEffect对照表
effectAllowed dropEffect
1:根据用户所使用的平台不同,可能会出现的值,如在windows下,copyMove的effectAllowed值,默认为copy操作,在按shift键时,则会变成move操作。
none none
copy copy
copyLink copy或是link1
copyMove copy或是move1
all copy、link1或是move1
link link
linkMove link或是move1
move move
uninitialized,被拖拽为一个文本框中选中的内容? move或是copy1,link1
uninitialized,被拖拽对象为一个普通选中项? copy或是link1,move1
uninitialized,被拖拽对象为一个带链接的a元素 link或是copy1,move1
其它情况 copy或是link1,move1

setDragImage(image, x, y)

这个函数用于设置鼠标移动过程中随鼠标一起移动的效果图,而不是鼠标指针的显示效果。xy参数用于指定图像相对于鼠标指针的位置;image参数用于指定图像元素,若是一个img元素,则显示图像元素,否则将给定的元素转换成一张图像并显示。

该函数只能在读写模式(也就是dragstart事件)下有用,在其它事件中调用无效。若不调用此函数,则在拖拽时,被拖拽元素被转换成一个图处并当作一个效果图显示。

items属性

items的接口定义如下:

    interface DataTransferItemList      {        readonly attribute unsigned long length;        getter DataTransferItem(unsigned long index); // items[index]        deleter void(unsigned long index); // delete items[index]        void clear();        DataTransferItem? add(DOMString data, DOMString type);        DataTransferItem? add(File data);      }      interface DataTransferItem      {        readonly attribute DOMString kind;        readonly attribute DOMString type;        void getAsString(FunctionStringCallback? _callback);        File? getAsFile();      }      [Callback, NoInterfaceObject]      interface FunctionStringCallback      {        void handleEvent(DOMString data);      }

从上面的定义不难看出:DataTransfer.items就是DataTransferItem的一个数组。DataTransferItemList仅仅是定义一套以数组形式存取DataTransferItem对象的接口。我们主要看一下DataTransferItem类的定义:

  • kind:表示数据的类型,只能是stringFile。单从字面就很好理解这两个值代表的是什么意思。
  • type:实际数据的类型或是格式,一般用mimetype表示,但并不是强制mimetype格式。
  • getAsString(callback):当kind属性为string时,在只读或是读写模式下,可以通过回调函数处理此对象关联的实际数据。
  • getAsFile():当kindfile是,通过此函数能获取真实的数据,否则返回null,只在只读或是读写模式下有效。

在非读写模式下删除DataTransferItemList中的数据,会返回InvalidStateError错误。若是在非读写模式下添加数据,则不执行任何操作。DataTransfer.setData则是对这两个函数的封装(根据第二个参数决定是删除还是添加)。

types属性

返回根据下列步骤产生的字符串集合(DOMStringList):

  1. 产生一个空的DOMStringList对象L。
  2. 遍历DataTransfer.items对象。
  3. DataTransfer.items的子项的kind的值为string,则将该项的type值添加到L对象中。
  4. DataTransfer.items的子项的kind的值为file,则向L对象添加"Files"字符串。
  5. 返回L对象

getData(format)

getData是从DataTransfer.items中查找数据。返回符合以下条件的数据:

  1. DataTransferItem.kindstring
  2. DataTransferItem.type的值等于format参数

如果没有找到匹配的或是处于保护模式下,则返回一个空字符串。

参数format在传递到函数内部之前,都会被转换成小写字符,且如果参数值为text或是url,则会被转换成text/plaintext/uri-list

setData(format, data)

setData用于向DataTransfer.items中添加或删除一条数据:

当没有指定第二个参数data时,则是从DataTransfer.items中删除符合以下条件的数据:

  1. kind等于string
  2. type等于参数format

当指定第二个参数data时,则是向DataTransfer.items中添加数据,新添加的数据格式如下:

  1. kind的值为string
  2. type的值为format
  3. data参数作为DataTransferItem的实际值。

参数format在传递到函数内部之前,都会被转换成小写字符,且如果参数值为text或是url,则会被转换成text/plaintext/uri-list

如果不处于读写模式下,则不做任何操作。

clearData()

清除所有kind值为string的项。只在读写模式下起作用。

</section>

存储模式

存储模式决定了DataTransfer各项内容是否可用。下表列出相关的信息,其中Y表示可用,N表示不可用。

存储模式与DataTransfer各项的关系

读写 只读 保护
dropEffect 只在dragenterdragover事件中可更改,其它事件中只可读取。
effectAllowed 只在dragstart事件中起作用
items 对items的操作详细情况参考后面的setData函数
types 仅在dragenterdragoverdrop三个事件中可获取此值
setData Y N N
getData Y Y N
clearData Y N N
DataTransferItem.getAsString Y Y N
DataTransferItem.getAsFile Y Y N
来自:http://blog.830725.com/post/html5-drag-and-drop-intro.html