再说说文件上传客户端的问题。阮一峰大神这篇解释挺清楚文件上传的渐进式增强 。所以原理就不再赘述,就在这记录下实现的方法。
form表单上传是最简单的文件上传,只需要一个form标签,把enctype设为multipart/form-data。action设置为上传路径。缺点是提交后会跳转。基本不会再用。
1 2 3 4 <form enctype ="multipart/form-data" method ="POST" > <input id ="file1" type ="file" name ="file1" > ... </form >
把form表单的action值指向一个同页面隐藏的iframe。此方法页面不会跳转,也不会阻塞页面(传统form上传是同步上传),甚至可以获取到服务器的返回信息。
ajax上传 ajax上传是现在的主流方法,但是只能兼容IE10以上的高级浏览器。IE8呵呵
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 var formData = new FormData ();formData.append ('name1' , $('#upload' ).files [0 ]) formData.append ('name2' , $('#upload' ).files [1 ]) formData.append ('name3' , $("#text" ).val ()) $.ajax ({ url : url, method : "POST" , data : formData, processData : false , contentType : false , xhr : function (e ) { var myXhr = $.ajaxSettings.xhr (); console .log (myXhr) if (myXhr.upload ) { myXhr.upload .onprogress = function (e ) { if (e.lengthComputable ) { progress (e.loaded , e.total , myXhr) } } } return myXhr }, success : function (res ){ console .log (res) } });
有几点需要注意的。
文件上传需要用到FormData对象来包装文件,模拟表单提交
1 2 3 4 5 var formData = new FormData ();formData.append ('name1' , $('#upload' ).files [0 ]) formData.append ('name2' , $('#upload' ).files [1 ]) formData.append ('name3' , $("#text" ).val ())
用append
方法给formData
添加数据。
dom.files[index]
方法来获取input标签内的文件数据。
console.log(dom.files[index])也许打印出来的内容看起来是个普通的对象,好像并没有包含文件内容。但是事实上这样的确可以把文件上传上去。
用jQuery上传。有两个参数是必须的: processData: false
和contentType: false;
processData设置为false。因为data值是FormData对象,不需要对数据做处理。默认情况下,通过data选项传递进来的数据,如果是一个对象(技术上讲只要不是字符串),都会处理转化成一个查询字符串,以配合默认内容类型 “application/x-www-form-urlencoded”。如果要发送 DOM 树信息或其它不希望转换的信息,请设置为 false。
contentType设置为false。因为是由form表单构造的FormData对象,且已经声明了属性enctype=”multipart/form-data”,所以这里设置为false。发送信息至服务器时内容编码类型。默认值是”application/x-www-form-urlencoded; charset=UTF-8”,适合大多数情况。
cache设置为false,上传文件不需要缓存。
ajax进度条 一切要说的话都在代码里
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 xhr : function ( ) { var myXhr = $.ajaxSettings.xhr (); if (myXhr.upload ) { myXhr.upload .onprogress = function (ev ) { if (ev.lengthComputable ) { progress (ev.loaded , ev.total ) } } } return myXhr }, success : function (res ){ console .log (res) }
原生的方法,需要在new一个xhr对象和open、send之间给xhr.upload绑定progress事件即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 function upload ( ) { var xhr = new XMLHttpRequest (); var fd = new FormData (); fd.append ("fileName" , file); xhr.upload .addEventListener ("progress" , uploadProgress, false ); xhr.open ("POST" , "../UploadServlet" ,true ); xhr.send (fd); } function uploadProgress (evt ){ if (evt.lengthComputable ) { progress (ev.loaded , ev.total ) } }
拖拽方法封装 拖拽方法相关的事件有 dragenter、dragleave、dragover、drop。一般情况下都要配合起来用才能完成一次完整的退拽操作
需要说明的有几点:
1、 可以读取到文件路径和文件内容的事件对象在drop事件下。 2、 如果在绑定拖拽方法的对象下还有子元素,鼠标进入该子元素范围内也会触发dragleave、dragenter、dragover等事件。所以会导致一些奇怪的事情,比如提前移除高亮样式等。解决办法是添加一个计数器。当dragleave次数等于dragenter次数就可以触发真正的dragleave回调。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 function initDrag ( selector, callback ) { let $elem = $(selector); $elem.counter = 0 ; $(selector).on ('dragenter' , function (e ) { e.preventDefault (); e.stopPropagation (); $elem.counter ++; $elem.addClass ( 'highLight' ) }) $(selector).on ('dragleave' , function (e ) { e.preventDefault (); e.stopPropagation (); $elem.counter --; if ($elem.counter === 0 ) { $elem.removeClass ( 'highLight' ) } }) $(selector).on ('dragover' , function (e ) { e.preventDefault (); e.stopPropagation (); }) $(selector).on ('drop' , function (e ) { e.preventDefault (); e.stopPropagation (); $elem.counter --; if ($elem.counter === 0 ) { $elem.removeClass ( 'highLight' ) } if ($.isFunction (callback)) callback (e); }) }