拖拽(Drag/Drop)是个非常普遍的功能。你可以抓住一个对象,并且拖动到你想放置的区域。 很多javascript都类似实现了相关的功能,例如,jQueryUI的drag and drop组件。在HTML5中,拖拽(drag and drop)成为了标准操作,任何元素都支持。正因为这个功能太普遍了,所有的主流浏览器都支持这个操作。
启用拖拽 - draggable属性
非常简单,只需要将一个元素的拖动属性修改为draggable,这个元素就支持拖动了,如下所示:
<
img
draggable
="true"
/>
拖动中数据的传递
拖动的过程中,我们往往需要传递相应的逻辑数据来完成转换的过程,这里主要是使用dataTransfer对象进行数据传递,下面先看看它的成员:
方法成员:
setData(format, data):把被拖动的数据赋值给dataTransfer对象。
format:一个String型参数,指定被拖动数据的类型。该参数取值可以是“Text”(文本类型)和“URL”(URL类型)。该参数是大小写无关的,所以传入"text"与"Text"是一样的。
data:一个变体类型参数,指定被拖动的数据。该数据可以是文本,图片路径,URL等等。
该函数有Boolean类型的返回值,true表示数据成功加到dataTransfer中,false代表不成功。如果需要,可以通过这个参数来决定是否应该继续执行某些逻辑。
getData(format):获取dataTransfer中存放的拖动数据。
format意义与setData中的一样,取值可以是"Text"(文本类型)和"URL"(URL类型)。
clearData(format):移除指定类型的数据。
这里的format除了上面可以指定的"Text"(文本类型)和"URL"(URL类型)外,还可以取下列值:file - 文件,html - html元素,image - 图片。
这个方法可以用于去选择性的处理拖动的数据类型。
属性成员:
effectAllowed:设置或获取数据源元素中的数据可以执行的操作。
属性类型为字符串,取值范围如下:
"copy"-复制数据.
"link"-链接数据.
"move"-移动数据
"copyLink"-复制或链接数据,由目标对象来确定。
"copyMove"-复制或移动数据,由目标对象来确定。
"linkMove"-链接或移动数据,由目标对象来确定。
"all"-所有的操作都是支持的。
"none"-禁止拖动。
"uninitialized"-默认值,采用默认的行为。
注意设置effectAllowed为none以后,拖动是禁止的,但是鼠标形状还是显示没有可拖动的对象的形状,如果想不显示这个鼠标形状,则需要将window的event事件的属性returnValue设置为false。
dropEffect:设置或获取拖动的目标上允许的操作以及相关的鼠标形状。
属性类型为字符串,取值范围如下:
"copy"-鼠标显示为复制时的形状;
"link"-鼠标显示为连接的形状;
"move"-鼠标显示为移动的形状。
"none"(默认值)-鼠标显示为没有拖动的形状。
effectAllowed指定了数据源支持的操作,所以通常在ondragstart事件中指定。dropEffect指定了拖动放置的目标支持的操作,所以与effectAllowed配合,通常在拖动的目标上的 ondragenter, ondragover和ondrop等事件中使用。
files:返回拖动的文件的列表FileList。
types:ondragstart中发送的数据(被拖动的数据)类型的列表。
dataTransfer对象的存在,使得在拖动的数据源和目标元素之间传递逻辑数据变成了可能。通常我们使用setData方法在数据源元素的ondragstart事件中提供数据,然后再目标元素中,使用getData方法获取数据。
拖动中触发的事件
下面是一次拖拽会发生的事件,基本上事件的触发顺序也就是下面的顺序:
dragstart:要被拖拽的元素开始拖拽时触发,这个事件对象是被拖拽元素。
drag:拖拽元素时触发,这个事件对象是被拖拽元素。
dragenter:拖拽元素进入目标元素时触发,这个事件对象是目标元素。
dragover:拖拽某元素在目标元素上移动时触发,这个事件对象是目标元素。
dragleave:拖拽某元素离开目标元素时触发,这个事件对象是目标元素。
drop:将被拖拽元素放在目标元素内时触发,这个事件对象是目标元素。
dragend:在drop之后触发,就是拖拽完毕时触发,这个事件对象是被拖拽元素。
基本上事件的参数event都会传入相关的元素,可以很方便的进行一些修改。这里,我们并不需要处理每个事件,通常只需要挂接主要的几个事件即可。
拖动开始 - ondragstart事件
从这个事件传入的参数含有的信息非常丰富,从中可以很方便的获取到被拖动的元素(event.Target);从中可以设置被拖动数据(event.dataTransfer.setData);所以你可以很方便实现拖动的背后逻辑(当然你绑定的时候也可以传递其他的参数)。
拖动过程中 - ondrag,ondragover,ondragenter和ondragleave事件
ondrag事件的对象是被拖拽元素,通常这个事件处理的比较少。ondragenter事件是当拖动进入当前元素时发生,ondragleave事件是在当拖动离开当前元素时发生,ondragover事件是在拖动在当前元素中移动时发生。
这里只需要注意一点,因为默认情况下,浏览器是禁止元素drop的,所以为了让元素可以drop,需要在这个函数中返回false或者调用event.preventDefault()方法。如下面的例子所示。
拖动结束 - ondrop,ondragend事件
当可拖动的数据被drop的时候,drop事件触发。drop结束后,dragend事件被触发,这个事件使用的也相对少一点。
看一个简单的例子:
<!
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){
var
data
=
ev.dataTransfer.getData(
"
Text
"
);
ev.target.appendChild(document.getElementById(data));
ev.preventDefault();
}
</
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
>
文件拖拽
上面的例子已经使用了dataTransfer的各种方法和属性,下面再看网上的另外一个有趣的应用:拖拽一个图片到网页上,然后在网页上显示。这个应用用到了dataTransfer的files属性。
<!
DOCTYPE HTML
>
<
html
>
<
head
>
<
meta
charset
="utf-8"
>
<
title
>HTML5拖放文件
</
title
>
<
style
>
#section
{
font-family
:
"Georgia", "微软雅黑", "华文中宋"
;
}
.container
{
display
:
inline-block
;
min-height
:
200px
;
min-width
:
360px
;
color
:
#f30
;
padding
:
30px
;
border
:
3px solid #ddd
;
-moz-border-radius
:
10px
;
-webkit-border-radius
:
10px
;
border-radius
:
10px
;
}
.preview
{
max-width
:
360px
;
}
#files-list
{
position
:
absolute
;
top
:
0
;
left
:
500px
;
}
#list
{
width
:
460px
;
}
#list .preview
{
max-width
:
250px
;
}
#list p
{
color
:
#888
;
font-size
:
12px
;
}
#list .green
{
color
:
#09c
;
}
</
style
>
</
head
>
<
body
>
<
div
id
="section"
>
<
p
>把你的图片拖到下面的容器内:
</
p
>
<
div
id
="container"
class
="container"
>
</
div
>
<
div
id
="files-list"
>
<
p
>已经拖进过来的文件:
</
p
>
<
ul
id
="list"
></
ul
>
</
div
>
</
div
>
<
script
>
if
(window.FileReader) {
var
list
=
document.getElementById(
'
list
'
),
cnt
=
document.getElementById(
'
container
'
);
//
判断是否图片
function
isImage(type) {
switch
(type) {
case
'
image/jpeg
'
:
case
'
image/png
'
:
case
'
image/gif
'
:
case
'
image/bmp
'
:
case
'
image/jpg
'
:
return
true
;
default
:
return
false
;
}
}
//
处理拖放文件列表
function
handleFileSelect(evt) {
evt.stopPropagation();
evt.preventDefault();
var
files
=
evt.dataTransfer.files;
for
(
var
i
=
0
, f; f
=
files[i]; i
++
) {
var
t
=
f.type
?
f.type :
'
n/a
'
,
reader
=
new
FileReader(),
looks
=
function
(f, img) {
list.innerHTML
+=
'
<li><strong>
'
+
f.name
+
'
</strong> (
'
+
t
+
'
) -
'
+
f.size
+
'
bytes<p>
'
+
img
+
'
</p></li>
'
;
cnt.innerHTML
=
img;
},
isImg
=
isImage(t),
img;
//
处理得到的图片
if
(isImg) {
reader.onload
=
(
function
(theFile) {
return
function
(e) {
img
=
'
<img class="preview" src="
'
+
e.target.result
+
'
" title="
'
+
theFile.name
+
'
"/>
'
;
looks(theFile, img);
};
})(f)
reader.readAsDataURL(f);
}
else
{
img
=
'
"o((>ω< ))o",你传进来的不是图片!!
'
;
looks(f, img);
}
}
}
//
处理插入拖出效果
function
handleDragEnter(evt){
this
.setAttribute(
'
style
'
,
'
border-style:dashed;
'
); }
function
handleDragLeave(evt){
this
.setAttribute(
'
style
'
,
''
); }
//
处理文件拖入事件,防止浏览器默认事件带来的重定向
function
handleDragOver(evt) {
evt.stopPropagation();
evt.preventDefault();
}
cnt.addEventListener(
'
dragenter
'
, handleDragEnter,
false
);
cnt.addEventListener(
'
dragover
'
, handleDragOver,
false
);
cnt.addEventListener(
'
drop
'
, handleFileSelect,
false
);
cnt.addEventListener(
'
dragleave
'
, handleDragLeave,
false
);
}
else
{
document.getElementById(
'
section
'
).innerHTML
=
'
你的浏览器不支持啊,同学
'
;
}
</
script
>
</
body
>
</
html
>
这个例子中使用了html5中的文件读取API:FileReader对象;该对象提供了下列异步方法用于读取文件:
1. FileReader.readAsBinaryString(fileBlob)
以二进制的方式读取文件,result 属性会包含一个文件的二进制的格式
2. FileReader.readAsText(fileBlob, opt_encoding)
以文本的方式读取文件, result 属性将会包含一个文件的文本格式,默认解码参数是 “utf-8”。
3. FileReader.readAsDataURL(file)
以URL形式读取文件result 将会包含一个文件的 DataURL 格式(图片通常用这种方式)。
当使用上面的方法读取文件后,会触发下列事件:
onloadstart,onprogress,onabort,onerror,onload,onloadend
这些事件都很简单,需要的时候挂接就可以了。看下面的代码示例:
function startRead() {
//
obtain input element through DOM
var file = document.getElementById('file').files[0];
if(file){
getAsText(file);
}
}
function getAsText(readFile) {
var reader =
new FileReader();
//
Read file into memory as UTF-16
reader.readAsText(readFile, "UTF-16");
//
Handle progress, success, and errors
reader.onprogress = updateProgress;
reader.onload = loaded;
reader.onerror = errorHandler;
}
function updateProgress(evt) {
if (evt.lengthComputable) {
//
evt.loaded and evt.total are ProgressEvent properties
var loaded = (evt.loaded / evt.total);
if (loaded < 1) {
//
Increase the prog bar length
//
style.width = (loaded * 200) + "px";
}
}
}
function loaded(evt) {
//
Obtain the read file data
var fileString = evt.target.result;
//
Handle UTF-16 file dump
if(utils.regexp.isChinese(fileString)) {
//
Chinese Characters + Name validation
}
else {
//
run other charset test
}
//
xhr.send(fileString)
}
function errorHandler(evt) {
if(evt.target.error.name == "NotReadableErr") {
//
The file could not be read
}
}
这里也简单说一下:普通的文件下载使用的就是window.open方法,例如:
window.open('http://aaa.bbbb.com/ccc.rar','_blank')
实用参考:
官方文档:http://www.w3schools.com/html5/
一个不错的教程网站:http://html5.phphubei.com/html5/features/DrapAndDrop/
MSDN帮助:http://msdn.microsoft.com/en-us/library/ms535861(v=vs.85).aspx
文件拖拽详述:http://www.html5rocks.com/zh/tutorials/file/dndfiles/
文件拖拽并上传:http://www.chinaz.com/design/2010/0909/131984.shtml
文件拖拽上传完整例子:http://www.cnblogs.com/liaofeng/archive/2011/05/18/2049928.html
文件下载的例子:http://hi.baidu.com/guo_biru/item/2d7201c012b6debd0c0a7b05
window.open攻略:http://www.cnblogs.com/liulf/archive/2010/03/01/1675511.html
window.open参数:http://www.koyoz.com/blog/?action=show&id=176