原网址:http://blog.163.com/mongying_net/blog/static/35112712012345352226/

拖拽上传应用主要使用了以下HTML5技术:

  • Drag&Drop : HTML5基于拖拽的事件机制.
  • File API :  可以很方便的让Web应用访问文件对象,File API包括FileList、Blob、File、FileReader、URI scheme,本文主要讲解拖拽上传中用到的FileList和FileReader接口。
  • FormData : FormData是基于XMLHttpRequest Level 2的新接口,可以方便web应用模拟Form表单数据,最重要的是它支持文件的二进制流数据,这样我们就能够通过它来实现AJAX向后端发送文件数据了。

HTML5 Drag&Drop 拖拽事件

  关于Drag&Drop拖拽事件,之前我写过一篇专门介绍的文章《给力的 Google HTML5 训练营(HTML5 Drag&Drop 拖拽、FileReader实例教程)》,那篇文章详细讲解了Drag & Drap事件的原理和代码实例,这里的拖拽上传实现原理基本上是一样的,大家有兴趣或不太了解的话可以先看看那篇文章,我在这里就不再过多啰嗦了~下面直接出拖拽上传简要代码实例:

var oDragWrap = document.body;//拖进
oDragWrap.addEventListener(‘dragenter’, function(e) {e.preventDefault();
}, false);//拖离
oDragWrap.addEventListener(‘dragleave’, function(e) {dragleaveHandler(e);
}, false);//拖来拖去 , 一定要注意dragover事件一定要清除默认事件
//不然会无法触发后面的drop事件
oDragWrap.addEventListener(‘dragover’, function(e) {e.preventDefault();
}, false);//扔
oDragWrap.addEventListener(‘drop’, function(e) {dropHandler(e);
}, false);var dropHandler = function(e) {
//将本地图片拖拽到页面中后要进行的处理都在这
}

获取文件数据 HTML5 File API

  在之前那篇文章中我也有介绍过关于File API中的FileReader接口,作为 File API 的一部分,FileReader 专门用于读取文件,根据 W3C 的定义,FileReader 接口 “提供一些读取文件的方法与一个包含读取结果的事件模型”。关于FileReader的详细介绍和代码实例大家可以先去看看那篇文章。

  今天我着重介绍一下File API中的FileList接口,它主要通过两个途径获取本地文件列表,一是<input type=”file”>的表单形式,另一种则是e.dataTransfer.files拖拽事件传递的文件信息。很显然,我们这里会用到后者。

var fileList = e.dataTransfer.files;

  使用files方法将会获取到拖拽文件的数组形势的数据,每个文件占用一个数组的索引,如果该索引不存在文件数据,将返回null值。可以通过length属性获取文件数量.

var fileNum = fileList.length;

  拖拽上传需要注意的是需要判断两个条件,1:拖拽的是文件不是页面中的元素; 2:拖拽的是图片而不是其它文件,可以通过file.type属性获取文件的类型

//检测是否是拖拽文件到页面的操作
if (fileList.length === 0) {return;};
//检测文件是不是图片
if (fileList[0].type.indexOf(‘image’) === -1) {return;}

  下面让我们来看看如何结合之前的拖拽事件来实现拖拽图片并在页面中进行预览:

var dropHandler = function(e) {e.preventDefault();//获取文件列表var fileList = e.dataTransfer.files;//检测是否是拖拽文件到页面的操作if (fileList.length == 0) {return;};//检测文件是不是图片if (fileList[0].type.indexOf(‘image’) === -1) {return;}//实例化file reader对象var reader = new FileReader();var img = document.createElement(‘img’);reader.onload = function(e) {img.src = this.result;oDragWrap.appendChild(img);}reader.readAsDataURL(fileList[0]);}

  这里有一个简单的拖拽图片预览的Demo

   这时你如果用FireBug等类似调试工具查看DOM的话,会看到<img>标签的src属性是一个超长的文件二进制数据,所以如果DOM 有很多这类图片,那就要当心浏览器性能了,因为这些数据极大地扩充的页面的代码量,而每次页面的reflow都会对浏览器形成很大的负担,So,如果这些 图片还在DOM中,那就尽量不要做动画或任何重绘操作,如果真的要做就尽量让图片脱离文档流,让其绝对定位比较靠谱。

补充:可以使用window.URL.createObjectURL(file)来获取文件的URL(Chrome下用window.webkitURL.createObjectURL(file)),这种方式获取的URL要比上面说的readAsDataURL简短很多。而且可以省去使用FileReader。这里感谢BinBinLiao的留言建议:) 下面是使用readAsDataURL与createObjectURL生成的人人网首页拖拽上传详解(HTML5 DragDrop、FileReader API、FormData)-小贝_无处安放的青春代码对比:

优化后的代码:(黄色为优化的代码)

var dropHandler = function(e) {e.preventDefault();var fileList = e.dataTransfer.files;  //获取文件列表var img = document.createElement(‘img’);//检测是否是拖拽文件到页面的操作if (fileList.length == 0) {return;};//检测文件是不是图片if (fileList[0].type.indexOf(‘image’) === -1) {return;}if (window.URL.createObjectURL) {//FF4+img.src = window.URL.createObjectURL(fileList[0]);} else if (window.webkitURL.createObjectURL) {//Chrome8+img.src = window.webkitURL.createObjectURL(fileList[0]);} else {//实例化file reader对象var reader = new FileReader();reader.onload = function(e) {img.src = this.result;oDragWrap.appendChild(img);}reader.readAsDataURL(fileList[0]);}}

   需要注意的是,window.URL.createObjectURL是有生命周期的,也就意味着你每用此方法获取URL,其生命周期都会和DOM一 样,它会单独占用内存,所以当删除图片或不再需要它是,记得用window.URL.revokeObjectURL(file)来释放其内存。当然,如 果你没有释放,刷新页面也是可以释放的。

AJAX上传图片(file.getAsBinary & FormData)

  既然已经获取到了拖拽到web页面中图片的数据,下一步就是将其发送到服务器端了。

  话说HTML5时代之前,AJAX传输文件二进制流数据是不可能完成的事情,而现在我们完全可以通过file.getAsBinary获取文件的二进制数据流,进而将其当做XHR的data数据传送到后端,8过由于Chrome不支持file的getAsBinary方法,FF3.6+支持此方法。所以Chrome就要另寻它法了,这时我们发现XMLHttpRequest Level 2中的FormData接口完美解决了这个问题,它可以很快捷的模拟Form表单数据并通过AJAX发送至后端,FormData的支持情况是FF5及以上支持,Chrome12及以上支持。

   file.getAsBinary获取文件流很简单,但是要想上传数据,就要模拟一下表单的数据格式了,首先看看模拟表单的js代码, FormData模拟表单数据时更是简洁,不用麻烦的去拼字符串,而是直接将数据append到formdata对象中即可:

var xhr = new XMLHttpRequest();
var url = ‘http://upload.renren.com/……’;
var boundary = ‘———————–’ + new Date().getTime();
var fileName = file.name;xhr.open(“post”, url, true);
xhr.setRequestHeader(‘Content-Type’, ‘multipart/form-data; boundary=’ + boundary);if (window.FormData) {//Chrome12+var formData = new FormData();formData.append(‘file’, file);formData.append(‘hostid’, userId);formData.append(‘requestToken’, t);data = formData;
} else if (file.getAsBinary) {//FireFox 3.6+data = “–” +boundary +crlf +”Content-Disposition: form-data; ” +”name=\”" +’file’ +”\”; ” +”filename=\”" +unescape(encodeURIComponent(file.name)) +”\”" +crlf +”Content-Type: image/jpeg” +crlf +crlf +file.getAsBinary() +crlf +”–” +boundary +crlf +”Content-Disposition: form-data; ” +”name=\”hostid\”" +crlf +crlf +userId +crlf +”–” +boundary +crlf +”Content-Disposition: form-data; ” +”name=\”requestToken\”" +crlf +crlf +t +crlf +”–” +boundary +’–’;
}xhr.send(data);首先表单数据headers头信息需要以下两项:Content-Type : 设置其为multipart/form-data来模拟表单数据boundary : 表单数据中的分隔符,用于分隔不同的文件或表单项,这是服务器端设置的格式。发送时的post数据类似这样:
————————-1323611763556
Content-Disposition: form-data; name=”file”; filename=”4.jpg”
Content-Type: image/jpeg???à?JFIF?…这里是文件二进制流…~iúo??5P%-v??Hü 4QHg??
————————-1323611763556
Content-Disposition: form-data; name=”hostid”229421603
—————————–1323612996486Content-Disposition: form-data; name=”requestToken”369009193
————————-1323611763556–

好了,现在文件上传成功后你就可以按照平常AJAX的操作来进行后续处理了。

最后,再来总结一下拖拽上传的技术要点:

  1. 监听拖拽:监听页面元素的拖拽事件,包括:dragenter、dragover、dragleave和drop,一定要将dragover的默认事件取消掉,不然无法触发drop事件。如需拖拽页面里的元素,需要给其添加属性draggable=”true”;
  2. 获取拖拽文件:在drop事件触发后通过e.dataTransfer.files获取拖拽文件列表,.length属性获取文件数量,.type属性获取文件类型。
  3. 读取图片数据并添加预览图:实例化FileReader对象,通过其readAsDataURL(file)方法获取文件二进制流,并监听其onload事件,将e.result赋值给img的src属性,最后将图片append到DOM中。
  4. 发送图片数据:使用file.getAsBinary 和 FormData分别模拟表单数据AJAX提交文件流。

OK,拖拽上传就讲到这里,欢迎大家一起探讨。

bbl 说道:

文 章写得很好,有个优化的建议,就是在图片显示的时候不必使用dataURl,可以使用object URL,以提高性能。webkit可以用window.webkitURL.createObjectURL(file),FireFox可以用 window.URL.createObjectURL(file)来实现,详见:https://developer.mozilla.org/en /DOM/window.URL.createObjectURL

[回复]

谢谢你的建议,用objectURL的确能提升很大的性能问题,也解决了FF7不支持dataURL的问题~

转载于:https://www.cnblogs.com/KrystalNa/p/4431525.html

拖拽上传技术-----html5[转载]相关推荐

  1. html ajax打包成app,利用HTML5与ajax完成拖拽上传文件

    前言 基于ajax的异步模式的上传控件,基本功能如下: 拖拽上传(利用HTML5新增特定 拖拽事件 以及 event的dataTransfer属性) 单文件/多文件切换(利用php实现单/多文件上传) ...

  2. Nodejs express、html5实现拖拽上传(转载)

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

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

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

  4. html5 上传超大文件,HTML5教程 如何拖拽上传大文件

    本篇教程探讨了HTML5教程 如何拖拽上传大文件,希望阅读本篇文章以后大家有所收获,帮助大家HTML5+CSS3从入门到精通 . < 前言: 大文件传输一直是技术上的一大难点.文件过大时,一些性 ...

  5. 使用jQuery开发一个基于HTML5的漂亮图片拖拽上传web应用

    昨天我们介绍了一款HTML5文件上传的jQuery插件:jQuery HTML5 uploader,今天我们将开发一个简单的叫upload center的图片上传程序,允许用户使用拖拽方式来上传电脑上 ...

  6. html5之多文件拖拽上传预览

    最近对于html5预览功能很是感兴趣,特地拿出来研究一小下,并以一个小项目举例讲解. h5中的input有个type=file 就是文件上传控件,有个属性multiple就是h5新增的支持多选上传文件 ...

  7. dropzonejs中文翻译手册 DropzoneJS是一个提供文件拖拽上传并且提供图片预览的开源类库....

    http://wxb.github.io/dropzonejs.com.zh-CN/dropzonezh-CN/ 由于项目需要,完成一个web的图片拖拽上传,也就顺便学习和了解了一下前端的比较新的技术 ...

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

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

  9. 拖拽上传及读取文件实现

    1.拖拽上传相关事件 2.拖拽上传简单实现 3.拖拽上传完整实现 4.读取文件实现 1.拖拽上传相关事件 相关事件: ondragenter 拖着东西进入 ondragleave 拖着东西离开 ond ...

最新文章

  1. 高德地图自定义点标记大小_Vue:如何在地图上添加自定义覆盖物(点)
  2. python自动卸载win程序_朋友说:能不能用python,帮我写一个“制作工资条”的自动化程序...
  3. Qt, Python(一)
  4. 19级、20级:班级日常分享,一天一瞬间
  5. linux 查看防火墙状态_每天五分钟学习Linux系列之 - 系统安全配置
  6. 1号店案例html源码_手把手教一起写jQuery版mini源码,分析jQuery的优势
  7. SpringMVC表单标签
  8. JS拖动技术--- 关于setCapture
  9. Spark服务启动的一些总结
  10. Windows添加.NET Framework 3.0 NetFx3 失败 - 状态为:0x800f0950
  11. Hive分区修复msck repair
  12. MATLAB2018simulink打不开MATLAB2019b的simulink,低版本simulink模型出现
  13. Reactive简介
  14. java 实现一个杨辉三角
  15. 电脑死机故障解决方法全面汇总
  16. MATLAB安装时为英文如何切换中文
  17. CentOS7设置共享目录
  18. 想知道会议录音转文字怎么转吗?这篇文章告诉你
  19. Java开源生鲜电商平台-支付模块的设计与架构(源码可下载)
  20. 世界上哪个国家最友好?

热门文章

  1. python三天速成_python学习第三天
  2. npm ERR! code ERR_STREAM_WRITE_AFTER_END npm install 报错实力踩坑npm,自从用了npm之后项目构建和插件管理确实方便了很多,但也是被坑的不要不要的
  3. mysql多实例访问代理_一台MySQL数据库启动多个实例
  4. websphere 启动出错 检查节点 上服务器的日志_启动Redis Sentinel哨兵
  5. python对文件操作的相关函数_第六章、Python文件操作
  6. java bundle类_java ResourceBundle介绍
  7. 到底什么是集群分布式
  8. 安装完MySQL后启动报错_MySQL数据库之mysql编译安装完成后,启动时报错The server quit without updating PID file...
  9. dorado 刷新_dorado BDF常见问题
  10. 寄存器和存储器的区别_汇编语言 第二章 寄存器