视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
html5文件拖拽上传的示例代码分享
2020-11-27 15:10:19 责编:小采
文档



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

功能实现

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

拖拽事件

拖拽事件有下面这些:

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

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

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

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

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

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

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

  • 从浏览器外拖拽文件到浏览器时,必须要绑定的事件有 dragoverdrop,其他的都可以不绑定。dragoverdrop 事件的处理函数内必须调用事件的 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>
     <p id= "progressBarZone">请将文件拖拽进浏览器内! <br/></ p>
    </body>
    
    <script>
    var progressBarZone = document.getElementById('progressBarZone');
    
    function sendFile(files) {
     if (!files || files.length < 1) {
     return;
     }
     
     var percent = document.createElement('p' );
     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>

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

    下载本文
    显示全文
    专题