创建 HTML5 拖拽的源容器和目标容器
在 HTML5 中,我们需要给指定的节点来绑定一些事件来使之成为具有源容器或目标容器的功能。在 HTML5 的拖拽过程中的事件有 7 个,分别是应用在目标容器或拖动节点上的 dragstart,drag,dragend 等 3 个事件,以及应用在目标容器节点上的dragenter,dragover,dragleave 和 drop 等 4 个事件。表 1 中对这些事件的触发机制和常见的操作进行了描述。
表 1. HTML5 拖拽过程中可以绑定的事件
事件名称@H_403_222@
| 触发机制@H_403_222@
| 绑定节点@H_403_222@
| 对应的 dojo 事件方法@H_403_222@
| 常见操作@H_403_222@
|
dragstart |
当鼠标左键点击某个可拖动节点开始拖拽时。 |
拖动的节点或源容器上。 |
onDndStart * |
对 DataTransfer 的数据进行初始化。初始化一些资源。 |
drag |
当拖拽进行时,在拖拽结束之前,在 dragstart 之后。 |
onMouseMove |
对拖动节点的位置信息进行处理。 |
dragenter |
拖动节点进入目标容器时。 |
目标容器上。 |
onOverEvent |
对目标容器的样式进行修改。 |
dragover |
拖动节点在目标容器上方时。 |
onDraggingOver |
判断拖动的节点是否被目标节点接受。 |
dragleave |
拖动节点离开目标容器上方时。 |
onDraggingOut |
drop |
拖动节点在目标容器上方松开鼠标左键时。 |
onDrop |
对 DataTransfer 的数据进行处理。对 DOM 节点进行操作。 |
dragend |
松开鼠标左键时,如 drop 事件触发,则在 drop 事件之后。 |
onDndCancel |
释放在 dragstart 中创建的资源。 |
备注 : 在 Dojo 中所有 dnd 源容器或目标容器在拖拽开始时都会调用 onDndStart 事件方法,而在 HTML5 中只有拖动的节点及源容器可以触发 dragstart 事件,其他容器包括目标容器在拖动开始时不会感知源容器及拖动节点的 dragstart 事件。
清单 4 展示给目标容器绑定 dragenter,dragleave,drop 事件的示例代码。在 dragenter 和 dragleave 事件中,我们对目标容器的背景样式进行修改使得用户感知目标容器的状态(如图 2 所示)。在 dragover 事件中我们对清单 3 中的链接元素(id 属性值为 item3)的节点进行了限制。drop 事件中我们要把拖动的节点插入到目标节点的 DOM 结构中。
清单 4. 创建目标容器的事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
var target = dojo.byId('target');
dojo.connect(target, 'dragover'function(e){
// doesn't allows link item (id = “item3”) to drop
if (e.dataTransfer.getData'id') != "item3"{
e.preventDefault(;
}
};
dojo.'dragenter'//add style
dojo.addClass"over";
'dragleave'//remove style
dojo.removeClass'drop'//remove style if drop is successful
dojo.;
// stops the browser from redirecting
stopPropagation) e.var itemId = e.var dragItem (itemId;
e.target.appendChild(dragItem;
} |
图 2. 当拖动节点到目标容器是时对目标容器进行高亮显示
从清单 4 中我们在目标容器上对事件对象的 dataTransfer 属性进行了 getData 操作——取出了关键字 id 对应的数据。在 HTML5 拖拽过程中,用户可以在表 1 定义的事件里通过 event.dataTransfer 得到 DataTransfer 对象 ( 详见 W3C 网站上的接口定义)并对其进行定制传输数据、定制拖拽影像等操作。例如我们可以在 dragstart 事件中通过 setData 方法初始化数据(代码详见附件)。表 2 中列出了这各数据对象的方法及常用的用途。
与桌面进行交互
除了在网页中对一些页面上的元素进行拖拽以外,HTML5 扩充的 API 还允许网页与文件系统进行交互,比如从文件系统拖一个或几个文件到网页中,或是从网页拖到文件系统中。以前者为例,当我们从桌面或其它文件夹拖动文件到网页上某个目标结点时,我们可以通过 DataTransfer 的 files 属性得到这些文件数量以及文件的属性及内容。DataTransfer.files.length 的大小即为拖动文件的数量,当没有拖动文件时,files.length 的大小即为 0,可用来判断是否有文件拖动。
清单 5. 通过 dataTransfer.files 拿到文件对象
1
2
3
4
5
6
7
8
9
10
var files filesvar msg = ""for var i = 0; i < files.length; i++) {
console.log "Name: " + files[i].name + ",fileSize: " ].size;
var dataReader = new FileReader;
dataReader.onload {
msg += "content: " + dataReader.result}
dataReader.readAsText(files] 从清单 5 中的代码中我们可以看到 files 中存储了若干 file 对象,通过这个对象可以获取文件名,文件大小等。然后我们可以通过 FileReader 获取文件的内容。获取内容的 FileReader 并不是 HTML5 拖拽的功能,而是借助了 File API ( 详见 W3C 的 File API 文档)。它可以以文本,二进制,以及 dataURL 的形式读取,实现读取文件内容实现文件上传等,在我们的示例代码 html5dndfile.html 中我们演示了通过 readAsText 方法读取文本文件和通过 readAsDataURL 方法读取图像文件的使用。
与桌时行交互时,我们只需要对将清单 5 中给出的代码稍加修改加到目标容器的 drop 事件中,其它事件不用修改。例如清单 6 所示。
清单 6. 在目标容器的 drop 事件读取文本文件的内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
dojo.(textdiv; }
{
msg fileName fileSize;
;
dataReader.{
msg ;
textdiv.textContent = msg}
dataReader.; |
这样当我们拖动一个文本文件到指定的目标区域时,我们就可以看到文件内容。
Dojo 和 HTML5 拖拽功能的比较和选择
Dojo 实现了一套完整的拖拽框架和事件机制,并提供了默认的实现,用户可以通过声明的方式快速实现拖拽,而且还可以通过继承默认的 Source、Target 以及 Avatar 实现拖拽定制化。从使用经验上来看,Dojo 更倾向于完整的 DOM 节点操作,而数据的传输往往是通过绑在 DOM 节点上的属性实现的。
HTML5 的拖拽现在还在规范的定制和完善中,各个主流浏览器对该规范的支持也是各有千秋,基本上还处于发展的阶段。本文中提供的示例仅在 Firefox 3.6 以上版本测试通过。HTML5 作为新时代的 HTML 协议,拖拽事件中的 DataTransfer 接口体现了拖拽过程中以数据传输为中心的发展前景。与此同时,跟 File API 的结合可以使得 Web 应用的数据交互通过拖拽操作延伸到最终用户的桌面及文件系统上。另外 HTML5 还可以实现在不同浏览器窗口之间的拖拽操作,也是拖拽过程传输数据的一种应用。
小结
对比 Dojo 和 HTML5,我们不难发现在使用 Dojo 比 HTML5 可以更容易地开发出体验效果非常好的拖拽应用;而 HTML5 作为 HTML 的新规范,注重了拖拽过程中数据传输的重要性。两者如果可以融合则可以互补其短。通过实验,笔者发现 Dojo dnd 与 HTML5 拖拽暂时不能在同一结点上同时使用,由于 Dojo 是在 HTML4 规范基础上的工具包,它们之间可能因在事件上的冲突会导致 HTML5 拖拽不可用。但是我们有理由相信,随着 HTML5 规范的发展,将会有支持 HTML5 拖拽的工具包出现,届时开发者可以更为便捷的开发出更为丰富的 Web 应用。
代码下载:
原文链接:http://www.ibm.com/developerworks/cn/web/1102_guoqing_draganddrop/index.html