赵工的个人空间


专业技术部分转网页计算转业余爱好部分


  网站建设

首页 > 专业技术 > 网站建设 > HTML5拖放API
HTML5拖放API

以前,可以使用mousedown、mouseover和mouseup实现页内的拖放操作。HTML5标准引入了拖放API,可以实现拖放,范围已经超出浏览器的边界,能支持拖放多个文件上传。

1.新增的draggable属性:

Draggable属性用于定义元素是否允许用户拖放,有true、false和auto三个可选值。通常,大部分的页面元素是不可拖放的,如果要把元素变成可拖放的,设置draggable属性:
<div draggable="true"></div>
另外,img元素和a元素(指定href)默认是可以拖放的。

2.新的鼠标拖放事件:

HTML5提供了7种新的与拖放相关的鼠标事件,其中有一些事件由源元素(拖动的元素)触发,另一些事件则由目标元素触发(源元素投放的元素)。
当用户执行拖放操作时,就会触发以下三种事件:
·dragstart:当拖动操作开始时触发该事件,这时系统会设置与源元素相关的数据。
·drag:这个事件与mousemove事件类似,但是它是在源元素发生拖动时触发的。
·dragend:当拖动操作结束(无论是否成功)时,源元素就会触发这个事件。
下面是执行相同操作时,目标元素触发的事件:
·dragenter:在拖动操作过程中,当鼠标指针进入可能的目标元素区域内部时,就会触发这个事件。
·dragover:这个事件与mouseover事件类似,但是它是由可能的目标元素在拖动操作执行时触发的。
·drop:当拖动操作执行投放时,目标元素就会触发这个事件。
·dragleave:在拖动操作时,当鼠标离开元素时,就会触发这个事件。与dragenter一起,这个事件可以提供反馈信息,帮助用户确定目标元素。
浏览器在拖放操作中会默认执行这些操作,为了得到预期的效果,可能需要停止默认行为,然后定制一些特殊操作。对于其中一些事件,如dragenter、dragover和drop,即使指定了定制的操作,也有必要停止它们的默认事件处理。示例:
<!DOCTYPE html>
<html lang="en">
<head>
  <title>Drag and Drop</title>
  <link rel="stylesheet" href="dragdrop.css">
  <script src="dragdrop.js"></script>
</head>
<body>
<section id="dropbox">
  Drag and drop the image here
</section>
<section id="picturesbox">
  <img id="image" src="http://www.dwenzhao.cn/content/monster1.gif">
</section>
</body>
<html>
代码中引入了样式文件dragdrop.css,代码为:
    #dropbox {
      float: left;
      width: 500px;
      height: 300px;
      margin: 10px;
      border: 1px solid #999999;
    }
    #picturesbox {
      float: left;
      width: 320px;
      margin: 10px;
      border: 1px solid #999999;
    }
    #picturesbox > img {
      float: left;
      padding: 5px;
    }
实际上,所有拖放操作都由JavaScript代码完成。文件dragdrop.js的代码为:
function initiate() {
  source1=document.getElementById('image');
  source1.addEventListener("dragstart", dragged, false);
  drop=document.getElementById('dropbox');
  drop.addEventListener("dragenter", function(e) {
      e.preventDefault();}, false);
  drop.addEventListener("dragover", function(e) {
      e.preventDefault();}, false);
  drop.addEventListener("drop", dropped, false);
}
function dragged(e) {
  var code='<img src="'+source1.getAttribute('src')+'">';
  e.dataTransfer.setData('Text', code);
}
function dropped(e) {
  e.preventDefault();
  drop.innerHTML=e.dataTransfer.getData('Text');
}
window.addEventListener("load", initiate, false);
代码中有三个函数,initiate()负责添加操作的事件监听器,dragged()和dropped()负责生成和接收拖放过程中传输的信息。
在一般的拖放操作过程中,必须准备在源与目标元素之间共享的信息。为此,需要添加dragstart事件的监听器。当事件触发时,监听器会调用dragged()函数,然后使用setData()准备该函数所需要的信息。
通常,文档中大多数元素默认都不支持投放操作,必须阻止默认行为。通过添加dragenter和dragover事件监听器,在匿名函数中执行preventDefault()方法就可以实现这个操作。
最后,添加drop事件监听器,在其中调用dropped()函数,接收和处理源元素产生的数据。
当拖动操作开始时,就会触发dragstart事件,然后调用dragged()函数,这个函数会获取所拖动元素的src属性,使用dataTransfer对象的setData()方法设置传输数据。当把元素投放到投放框时,就会触发drop事件,然后调用dropped()函数。这个函数仅仅将通过getData()方法获取的信息更新到投放框的内容中。在事件发生时,浏览器还会执行一些默认操作,必须使用preventDefault()方法停止这个行为。

3.dataTransfer对象:

这个对象保存了拖放操作的信息。使用拖放的目的,是希望在拖放过程中有数据交换,而dataTransfer就充当了这种媒介。dataTransfer对象有一些相关方法:
·setData(type, data):这个方法可用于声明所传送的数据与类型。这个方法可接受一些常规数据类型(如text/plain、text/html或text/uri-list)、特殊类型(如URL或Text)或自定义类型。在操作中,所传输的每一种数据类型都必须通过setData()方法进行处理。
·getData(type):这个方法返回源元素发送的指定类型数据,可取值Text、URL。
·clearData(type):这个方法可以删除指定类型的数据,类型有Text、URL、File、HTML、Image。如果省略参数,则清除全部数据。
·addElement():添加一起跟随拖放的元素,如果想让某个元素跟随被拖放元素一同被拖放,则使用此方法。语法:addElement([element])
·setDragImage(element,x,y):有一些浏览器会显示拖动元素的缩略图。这个方法可用于定制一幅图像和使用x与y属性选择鼠标指针所在的位置。
dataTransfer对象还有以下一些适用于应用程序的属性:
·types:这个属性会返回一个数组,其中包含dragstart事件中设置的数据类型。可以将这个数组保存在一个变量中(list=dataTransfer.types),然后使用for循环遍历这个数组。
·files:这个属性会返回一个数组,其中包含关于所拖动文件的信息。
·effectAllowed:这个属性会返回允许执行的操作类型。设置这个属性,可以修改所选择的操作,支持的值包括none、copy、copyLink、copyMove、link、linkMove、move、all和uninitialized。
·dropEffect:设置或获取拖放操作的类型和要显示的光标类型。如果该操作效果与起初设置的effectAllowed效果不符,则拖放操作失败。设置这个属性可以修改所选择的操作,支持的值包括none、copy、link和move。

4.Dragenter、dragleave与dragend:

dragenter、dragleave和dragend事件都是重要的事件,可用于提供反馈信息,告诉用户元素在屏幕上的移动过程。
示例:
function initiate() {
  source1=document.getElementById('image');
  source1.addEventListener("dragstart", dragged, false);
  source1.addEventListener("dragend", ending, false);
  drop=document.getElementById('dropbox');
  drop.addEventListener("dragenter", entering, false);
  drop.addEventListener("dragleave", leaving, false);
  drop.addEventListener("dragover", function(e) {
      e.preventDefault();}, false);
  drop.addEventListener("drop", dropped, false);
}
function entering(e) {
  e.preventDefault();
  drop.style.background='rgba(0,150,0,.2)';
}
function leaving(e) {
  e.preventDefault();
  drop.style.background='#FFFFFF';
}
function ending(e) {
  elem=e.target;
  elem.style.visibility='hidden';
}
function dragged(e) {
  var code='<img src="'+source1.getAttribute('src')+'">';
  e.dataTransfer.setData('Text', code);
}
function dropped(e) {
  e.preventDefault();
  drop.style.background='#FFFFFF';
  drop.innerHTML=e.dataTransfer.getData('Text');
}
window.addEventListener("load", initiate, false);
上述代码中,增加了两个函数,分别处理投放框和源元素。每当鼠标拖动元素、进入或离开所占区域,函数entering()和leaving()都会修改投放框的背景颜色。此外,当投放元素时,dragend事件监听器会调用ending()函数。
使用这些函数,每当鼠标拖动元素和进入投放框区域时,投放框就会变成绿色,而当投放元素时,源图像就会隐藏起来。这些可见的变化效果并不影响整个拖放过程,而是提供一些反馈信息,指导用户完成操作。

5.选择有效的源:

dataTransfer对象有一个属性types,会返回一个数组,其中包含dragstart事件所设置的类型列表,但也无法保证验证过程的有效。
选择和验证拖放操作中所传输数据的方法有很多变化。示例:
<!DOCTYPE html>
<html lang="en">
<head>
  <title>Drag and Drop </title>
  <link rel="stylesheet" href="dragdrop.css">
  <script src="dragdrop.js"></script>
</head>
<body>
<section id="dropbox">
  拖放图像到此
</section>
<section id="picturesbox">
  <img id="image1" src="http://www.dwenzhao.cn/content/monster1.gif">
  <img id="image2" src="http://www.dwenzhao.cn/content/monster2.gif">
  <img id="image3" src="http://www.dwenzhao.cn/content/monster3.gif">
  <img id="image4" src="http://www.dwenzhao.cn/content/monster4.gif">
</section>
</body>
<html>
上述模板中,可通过检查图像的id属性,从而对源元素过滤。JavaScript代码为:
function initiate() {
  var images=document.querySelectorAll('#picturesbox > img');
  for (var i=0;i<=images.length;i++) {
    images[i].addEventListener('dragstart', dragged, false);
  }
  drop=document.getElementById('dropbox');
  drop.addEventListener("dragenter",  function(e) {
      e.preventDefault();}, false);
  drop.addEventListener("dragover", function(e) {
      e.preventDefault();}, false);
  drop.addEventListener("drop", dropped, false);
}
function dragged(e) {
  elem=e.target;
  e.dataTransfer.setData('Text', elem.getAttribute('id'));
}
function dropped(e) {
  e.preventDefault();
  var id=e.dataTransfer.getData('Text');
  if (id!="image4")
    var src=document.getElementById(id).src;
    drop.innerHTML='<img src="'+src+'">';
  } else {
    drop.innerHTML='not admitted';
  }
}
window.addEventListener("load", initiate, false);
上述代码使用querySelectorAll()方法,在picturesbox元素中的所有图像上添加dragstart事件监听器,每当图像拖动时,就使用setData()发送id属性,然后在dropped()函数中检查id值,防止用户手动设置id=”image4”的图像(如果用户试图拖动这幅图像,投放框就会显示not admitted的消息)。

6.setDragImage():

通常,浏览器会为源元素自动生成缩略图,但是缩略图相对于鼠标指针的位置取决于开始拖动时的鼠标位置。setDragImage()方法可用于指定具体的位置,使其在所有拖放操作中保持一致。示例:
<!DOCTYPE html>
<html lang="en">
<head>
  <title>Drag and Drop </title>
  <link rel="stylesheet" href="dragdrop.css">
  <script src="dragdrop.js"></script>
</head>
<body>
<section id="dropbox">
  <canvas id="canvas" width="500" height="300"></canvas>
</section>
<section id="picturesbox">
  <img id="image1" src="http://www.dwenzhao.cn/content/monster1.gif">
  <img id="image2" src="http://www.dwenzhao.cn/content/monster2.gif">
  <img id="image3" src="http://www.dwenzhao.cn/content/monster3.gif">
  <img id="image4" src="http://www.dwenzhao.cn/content/monster4.gif">
</section>
</body>
<html>
上述HTML5代码使用<canvas>元素作为投放框。所引用的JavaScript代码为:
function initiate() {
  var images=document.querySelectorAll('#picturesbox > img');
  for (var i=0;i<=images.length;i++) {
    images[i].addEventListener('dragstart', dragged, false);
    images[i].addEventListener('dragend', ending, false);
  }
  drop=document.getElementById('canvas');
  canvas=drop.getContext('2d');
  drop.addEventListener("dragenter",  function(e) {
      e.preventDefault();}, false);
  drop.addEventListener("dragover", function(e) {
      e.preventDefault();}, false);
  drop.addEventListener("drop", dropped, false);
}
function ending(e) {
  elem=e.target;
  elem.style.visibility='hidden';
}
function dragged(e) {
  elem=e.target;
  e.dataTransfer.setData('Text', elem.getAttribute('id'));
  e.dataTransfer.setDragImage(e.target, 0, 0);
}
function dropped(e) {
  e.preventDefault();
  var id=e.dataTransfer.getData('Text');
  var elem=document.getElementById(id);
  var posx=e.pageX-drop.offsetLeft;
  var posy=e.pageY-drop.offsetTop;
  canvas.drawImage(elem,posx,posy);
}
window.addEventListener("load", initiate, false);
在拖动图像时,代码会执行dragged()函数,并且使用setDragImage()方法设置自定义的拖动图像。这段代码还可以获取画面上下文,使用drawImage()方法及源元素引用绘制所投放的图像。最后,ending()函数会隐藏源元素。
拖动元素创建自定义缩略图,其位置设置为(0,0),即能够准确知道缩略图与鼠标的相对位置。Dropped()函数也使用这些信息,就可以准确计算源元素投放到画布的位置,从而将图像绘制到准确的位置上。在支持setDragImage()方法的浏览器上测试,可以看到,图像会绘制到画布中与缩略图对应的位置上,用户可以很方便地确定图像的投放位置。

7.文件拖放API:

HTML5提供了文件操作的API,可以通过编程的方式选择和访问文件数据,使得从Web上访问本地文件系统变得非常简单。

1)新增标记属性:

HTML5借助file类型的表单元素来实现文件上传,为file类型的表单元素新增了属性。
①multiple属性:
可允许同时选择多个上传文件。语法:
<input type="file" multiple />
同时选择多个文件上传,得到的是一个FileList对象,该对象是一个File对象列表。
②accept属性:
规定了可通过文件上传提交的文件类型。目前浏览器并没有限制上传文件的类型,仅实现了在打开文件窗口时默认选择指定的文件类型。语法:
<input type="file" accept="image/gif" />
实际在选择上传文件时,默认仅显示gif格式的文件,也可以选择其他类型的上传文件。

2)FileList对象和File对象:

当用户在file类型的表单元素中同时选择多个文件时,可通过编程的方式获得一个文件列表,即FileList对象。FileList对象里的每一个文件又是一个File对象。
FileList对象是File对象的一个集合,可以使用数组的方式遍历FileList对象里的每一个File对象。示例:
function showFiles() {
   var fileList=document.getElementById("files").files;
   var msg=document.getElementById("msg");
   var file;
   for (var i=0;i<fileList.length;i++) {
      file=fileList[i];
      msg.innerHTML+=file.name+";<br />";
   }
}
对应的file元素为:
<form action="" method="post">
   <input type="file" id="files" multiple />
   <input type="button" value="显示文件" onclick="showFiles()" />
   <p id="msg"></p>
</form>

3)Blob对象:

Blob代表原始二进制数据,通过Blob对象的slice()方法可以访问里面的字节数据。
①size属性:
Blob对象的size属性表示其字节长度。
②type属性:
Blob对象的type属性表示其MIME类型,如果是未知类型,则返回一个空字符串。
③slice()方法:
使用slice()方法可以实现文件的切割,并返回一个新的Blob对象。
File对象继承了Blob对象,所以File对象也可以使用Blob对象的属性和方法。示例:
function showType() {
   var files=document.getElementById("files").files;
   var msg=document.getElementById("msg");
   var file;
   for (var i=0;i<files.length;i++) {
      file=files[i];
      msg.innerHTML+="字节长度:"+file.size+";<br />";
      msg.innerHTML+="文件类型:"+file.type+";<br />";
   }
}
对应的file元素为:
<form action="" method="post">
   <input type="file" id="files" multiple accept="image/*" />
   <input type="button" value="显示文件数据" onclick="showType()" />
   <p id="msg"></p>
</form>

4)FileReader接口:

FileReader接口提供了一些读取文件的方法与一个包含读取结果的事件模型。FileReader接口主要是把文件读入内存,并读取文件中的数据。
因为一些浏览器版本没有实现FileReader接口,因此使用前需要检测一下:
if (typeof FileReader=="undefined") {
   alert("浏览器未实现FileReader接口");
} else {
   var reader=new FileReader();
}
①FileReader的属性:
FileReader接口有3个属性,分别用于返回读取文件状态、数据和读取时发生的错误。
·readyState属性:只读,获取读取文件的状态。状态有3个值,见下表:

状态

说明

EMPTY

0

表示新的FileReader接口已经构建,且没有调用任何读取方法时的默认状态

LOADING

1

表示有读取文件的方法正在读取File对象或Blob对象,且没有错误发生

DONE

2

表示读取文件结束,可能完全读入内存,或发生了错误,或使用abort强行中断

·result属性:只读,获取已经读取文件的数据,如果是图片,将返回base64格式的数据。
·error属性:只读,获取文件过程中出现的错误。错误包含如下4种类型:

类型

说明

NotFoundError

找不到读取的资源文件

SecurityError

发生安全错误

NotReadableError

无法读取的错误

EncodingError

编码限制的错误,通常是数据的URL表示的网址长度受到限制

发生错误时,FileReader接口会返回错误,同时读取文件的方法也会抛出错误。
②FileReader的方法:
FileReader接口有5个方法,其中4个用于读取文件,一个用来中断读取过程。
·readAsArrayBuffer()方法:将文件读取为数组缓存区,语法:
readAsArrayBuffer(<blob>);
参数表示一个Blob对象的文件。
·readAsBinaryString()方法:将文件读取为二进制字符串。语法:
readAsBinaryString(<blob>);
·readAsText()方法:将文件读取为文本字符串。语法:
readAsBinaryString(<blob>,<encoding>);
参数<encoding>表示文本的编码方法,默认为UTF-8。
·readAsDataURL()方法:将文件读取为DataURL字符串。
·abort()方法:用于中断读取操作,没有参数。
③FileReader的事件:
·loadstart事件:开始读取数据时触发的事件。
·progress事件:正在读取数据时触发的事件。
·load事件:成功完成数据读取时触发的事件。
·abort事件:中断读取数据时触发的事件。
·error事件:读取数据发生错误时触发的事件。
·loadend事件:结束读取数据时触发的事件,数据读取可能成功也可能失败。

Copyright@dwenzhao.cn All Rights Reserved   备案号:粤ICP备15026949号
联系邮箱:dwenzhao@163.com  QQ:1608288659