本文首先发表在  码蜂笔记 : http://coderbee.net/index.php/web/20130703/266

html5 文件拖拽上传是个老话题了,网上有很多例子,我一开始的代码也是网上找来改的,只是踩了几个坑之后就想把过程记录下来。

功能实现

下面主要介绍从浏览器外拖拽文件到浏览器进行上传的实现。 首先会介绍一些必须的基础。

拖拽事件

拖拽事件有下面这些:

  • dragstart:当用户开始拖动对象时触发。

  • dragenter: 当鼠标第一次经过目标元素,且有拖动发生时触发。此事件的监听者应指明在这个位置上是否允许drop,或者监听者不执行任何操作,那么drop默认是不允许的。

  • dragover:当鼠标经过一个元素时,且有拖动发生时触发 。

  • dragleave:当鼠标离开一个元素,且有拖动在发生时触发。

  • drag: 当对象被拖动,每次移动鼠标时触发。

  • drop:在drag操作的最后发生drop时,在元素上触发此事件。监听者应该负责检索拖动的数据,并插入drop的位置。

  • dragend: 在拖动对象时放开鼠标按键时触发。

从浏览器外拖拽文件到浏览器时,必须要绑定的事件有 dragover 和 drop,其他的都可以不绑定。dragover 和drop 事件的处理函数内必须调用事件的 preventDefault() 函数,要不然浏览器会进行默认处理,比如文本类型的文件直接打开,非文本的可能弹出一个下载文件框。

DataTransfer对象

拖拽对象用来传递数据的媒介,通过拖拽事件的 event.dataTransfer 获取。

  • dataTransfer.dropEffect [ = value ]:返回当前选择的操作类型,可以设置新的值来修改已选择的操作。可选的值有: none, copy, link, move 。

  • dataTransfer.effectAllowed [ = value ]:返回允许的操作类型,可修改。可选的值有:none, copy, copyLink, copyMove, link, linkMove, move, all, uninitialized 。

  • dataTransfer.types:返回一个DOMString,列出在dragstart事件里设置的所有格式。另外,如果有文件被拖动,那么其中一个类型的字符串将是“Files”。

  • dataTransfer.clearData( [ format ] ):移除指定格式的数据。如果忽略参数则移除所有数据。

  • dataTransfer.setData(format, data):添加指定的数据。

  • data = dataTransfer.getData(format):返回指定的数据。如果没有这样的数据,则返回空字符串。

  • dataTransfer.files:返回被拖拽的FileList,如果有。

  • dataTransfer.setDragImage(element, x, y):用指定的元素来更新drag反馈,替换之前指定的反馈(feedback)。

  • dataTransfer.addElement(element):添加指定元素到用于渲染drag反馈的元素列表。

在这个用例里,最重要的就是 dataTransfer.files 属性,它是用户拖拽进浏览器的文件列表,是个 FileList对象,有 length 属性,可以通过下标访问。

FormData

FormData 代表一个表单,可以通过 append('fieldName', value) 函数往表单里添加参数,参数的只不仅可以是字符串,还可以是File对象,甚至二进制数据。

XMLHttpRequest level 2

新版本的XMLHttpRequest对象,这里说的XMLHttpRequest都是指新版的。

XMLHttpRequest可以向不同域名的服务器发出HTTP请求。这叫做 “跨域资源共享”(Cross-origin resource sharing,简称CORS)。

浏览器有个著名的同源策略,这里浏览器安全的基础,CORS 除了需要浏览器支持外,还要服务器同意。

XMLHttpRequest 支持直接发送FormData,就像浏览器进行表单提交一样。

XMLHttpRequest 还支持进度信息(progress事件),进度分为上传进度和下载进度,上传进度的事件是在XMLHttpRequest.upload 对象上,下载进度的事件是在 XMLHttpRequest 对象。每个进度事件都有三个属性:

  • lengthComputable:可计算的已上传字节 数
  • total:总的字节 数
  • loaded:到目前为止上传的字节 数

除了进度事件,还支持下面五个事件:

  • load事件:传输成功完成。
  • abort事件:传输被用户取消。
  • error事件:传输中出现错误。
  • loadstart事件:传输开始。
  • loadend事件:传输结束,但是不知道成功还是失败。

同 progress事件一样,属于上传操作的事件处理函数绑定在XMLHttpRequest.upload对象上,属性下载的直接绑定在 XMLHttpRequest 对象。

具体代码

本机测试时要注意把下面代码里的路径改为自己本机的。

服务器端

服务器端需要写个Servlet来接收上传的表单。 /html5/FileUploadServlet

用servlet3的 @MultipartConfig 注解就可以很快实现。

客户端代码


<html>
<head>
<title> drag drop upload demo
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
</head>
<body>
<div id= "progressBarZone">请将文件拖拽进浏览器内! <br/></ div>
</body> <script>
var progressBarZone = document.getElementById('progressBarZone'); function sendFile(files) {
if (!files || files.length < 1) {
return;
} var percent = document.createElement('div' );
progressBarZone.appendChild(percent); var formData = new FormData(); // 创建一个表单对象FormData
formData.append( 'submit', '中文' ); // 往表单对象添加文本字段 var fileNames = '' ; for ( var i = 0; i < files.length; i++) {
var file = files[i]; // file 对象有 name, size 属性 formData.append( 'file[' + i + ']' , file); // 往FormData对象添加File对象 fileNames += '《' + file.name + '》, ' ;
} var xhr = new XMLHttpRequest();
xhr.upload.addEventListener( 'progress',
function uploadProgress(evt) {
// evt 有三个属性:
// lengthComputable – 可计算的已上传字节数
// total – 总的字节数
// loaded – 到目前为止上传的字节数
if (evt.lengthComputable) {
percent.innerHTML = fileNames + ' upload percent :' + Math.round((evt.loaded / evt.total) * 100) + '%
' ;
}
}, false); // false表示在事件冒泡阶段处理 xhr.upload.onload = function() {
percent.innerHTML = fileNames + '上传完成。 ' ;
}; xhr.upload.onerror = function(e) {
percent.innerHTML = fileNames + ' 上传失败。 ' ;
}; xhr.open( 'post', 'http://cross.site.com:8080/html5/FileUploadServlet' , true);
xhr.send(formData); // 发送表单对象。
} document.addEventListener("dragover", function(e) {
e.stopPropagation();
e.preventDefault(); // 必须调用。否则浏览器会进行默认处理,比如文本类型的文件直接打开,非文本的可能弹出一个下载文件框。
}, false); document.addEventListener("drop", function(e) {
e.stopPropagation();
e.preventDefault(); // 必须调用。否则浏览器会进行默认处理,比如文本类型的文件直接打开,非文本的可能弹出一个下载文件框。 sendFile(e.dataTransfer.files);
}, false);
</script>
</html>

如果上面的代码都部署在同一个网站下,那是没有问题的。可是我要做的上传操作是要把文件传到另一个网站上,坑也就产生了。

由于一般情况下都不需要跨站点上传文件,所以跨域有关的就不贴这里了,有兴趣的看以看完整的文章:http://coderbee.net/index.php/web/20130703/266

html5 文件拖拽上传的更多相关文章

  1. HTML5文件拖拽上传记录

    JS文件: var FileName = ""; var FileStr = ""; (function () { function $id(id) { ret ...

  2. HTML5应用之文件拖拽上传

    使用HTML5的文件API,可以将操作系统中的文件拖放到浏览器的指定区域,实现文件上传到服务器.本文将结合实例讲解HTML5+jQuery+PHP实现拖拽上传图片的过程,来看下HTML5的魅力吧. H ...

  3. php和js实现文件拖拽上传

    Dropzone.js实现文件拖拽上传 http://www.sucaihuo.com/php/1399.html demo http://www.sucaihuo.com/jquery/13/139 ...

  4. day25—JavaScript实现文件拖拽上传案例实践

    转行学开发,代码100天——2018-04-10 今天记录一个利用JavaScript实现文件拖拽上传到浏览器,后天将文件打开的小案例. 基本功能:1点击添加文件 2 文件拖拽添加 html: < ...

  5. [开源应用]利用HTTPHandler+resumableJs+HTML5实现拖拽上传[大]文件

    前言: 大文件传输一直是技术上的一大难点.文件过大时,一些性提交所有的内容进内存是不现实的.大文件带来问题还有是否支持断点传输和多文件同时传输. 本文以resumableJs为例,介绍了如何在ASP. ...

  6. Nodejs express、html5实现拖拽上传

    一.前言 文件上传是一个比较常见的功能,传统的选择方式的上传比较麻烦,需要先点击上传按钮,然后再找到文件的路径,然后上传.给用户体验带来很大问题.html5开始支持拖拽上传的需要的api.nodejs ...

  7. Dropzone.js实现文件拖拽上传

    dropzone.js是一个开源的JavaScript库,提供 AJAX 异步文件上传功能,支持拖拽文件.支持最大文件大小.支持设置文件类型.支持预览上传结果,不依赖jQuery库. 使用Dropzo ...

  8. html5实现拖拽上传

    <html><head> <meta http-equiv="Content-Type" content="text/html; chars ...

  9. Dropzone.js文件拖拽上传提示Dropzone already attached 解决

    最近收到客户的反馈,在操作上传文件有时会出现没有任何.大部分时间是正常. 重现问题后,f12打开后台控制台发现如下提示: Uncaught Error: Dropzone already attach ...

随机推荐

  1. 接触.net5年了,感觉自己的知识面很狭隘。

    08年毕业找工作期间开始接触网页开发,由于在学校了混了4年时间,我只能从html标记语言开始学习,后来应聘到一个网站建设公司,开始学习ps.Dreamweaver和asp.由于基础薄弱,一个月后离开了 ...

  2. JavaScript学习总结【8】、面向对象编程

    1.什么是面向对象编程 要理解面向对象,得先搞清楚什么是对象,首先需要明确一点这里所说的对象,不是生活中的搞男女朋友对象,面向对象就是面向着对象,换在代码中,就是一段代码相中了另一段代码,自此夜以继日 ...

  3. js 中对象属性的特性

    数据属性: 数据属性包含一个数据值的位置,在这个位置可以读取和写入值. 4个描述的行为特性: writable  表示能否修改属性的值.默认为true Enumerable 表示能否过过for in循 ...

  4. 在Swift中使用libxml2

    // // main.swift // C150805_libxml2r2 // http://git.oschina.net/yao_yu/Swift2015/tree/master/C150805 ...

  5. 从用python自动生成.h的头文件集合和类声明集合到用python读写文件

    最近在用python自动生成c++的类.因为这些类会根据需求不同产生不同的类,所以需要用python自动生成.由于会产生大量的类,而且这些类是变化的.所以如果是在某个.h中要用include来加载这些 ...

  6. JDK下sun.net.www.protocol.http.HttpURLConnection类-----Http客户端实现类的实现分析

    HttpClient类是进行TCP连接的实现类, package sun.net.www.http; import java.io.*; import java.net.*; import java. ...

  7. 转载:如何避免代码中的if嵌套

    http://top.jobbole.com/4960/ http://stackoverflow.com/questions/24430504/how-to-avoid-if-chains 在Sta ...

  8. 领域驱动设计(Domain Driven Design)参考架构详解

    摘要 本文将介绍领域驱动设计(Domain Driven Design)的官方参考架构,该架构分成了Interfaces.Applications和Domain三层以及包含各类基础设施的Infrast ...

  9. 游戏服务器:到底使用UDP还是TCP

    http://blog.jobbole.com/64638/ 在编写网络游戏的时候,到底使用UDP还是TCP的问题迟早都要面对. 一般来说你会听到人们这样说:“除非你正在写一个动作类游戏,否则你就用T ...

  10. Remote Direct Memory Access (RDMA)

    RDMA有三类实现方式,包括RoCE,iWARP和InfiniBand.RDMA的基础是Virtual Interface Architechure (VIA). 参考文档: https://en.w ...