记录小文件上传的几个例子(含进度条效果,附源码下载)
1、简单原生上传
- 无javascript脚本、无进度条;
- 借助iframe实现post提交后的无刷新效果;
- jquery插件ajaxFileUpload.js的实现原型。
Html代码
<form enctype="multipart/form-data" action="UploadFile_1" method="post" target="frameResult"> <div class="item"> <input id="File1" name="UserPhoto" type="file" value="" /> <input type="submit" value="提交上传" /> <iframe src="about:blank" id="frameResult" name="frameResult"></iframe> </div> </form>
后台代码(ASP.NET MVC)
[HttpPost] public ActionResult UploadFile_1() { string result = "上传成功"; HttpPostedFileBase file= Request.Files["UserPhoto"]; file.SaveAs(Server.MapPath("~/Upload/")+ file.FileName); return Content(result); }
要点说明
- 为<form>标签的action、method设值,以POST方式请求UploadFile_1方法;
- 为<form>标签的enctype属性设值multipart/form-data,让POST请求带上<input type="file">的文件内容;
- 为<form>标签的target属性设值frameResult,让表单的请求响应结果放到名为frameResult的iframe中显示。
2、纯JavaScript异步上传
- 借助HTML5特性实现进度条、上传速度计算;
- 无需<form>标签;
- 不支持IE8、IE9等低版本浏览器。
JavaScript代码,因为不需要<form>标签,html也没什么内容可贴的了。
var btnUpload = document.getElementById('btnUpload'); btnUpload.onclick = function () { var fileInput = document.getElementById('File2'); if (!fileInput.value) { return; } var feature = {}; feature.fileapi = fileInput.files !== undefined; feature.formdata = (typeof window.FormData !== 'undefined'); if (!feature.fileapi || !feature.formdata) { showMessage('当前浏览器不支持Html5,请更换高级浏览器'); return; } var xhr = new XMLHttpRequest(); var formData = new FormData(); formData.append("UserPhoto", fileInput.files[0]); xhr.open("post", './UploadFile_2'); //超时时间,单位是毫秒 xhr.timeout = 60 * 1000; //请求结束 xhr.onload = function (event) { if (xhr.status == 200) { showMessage("上传成功"); return; } if (xhr.status == 404) { showMessage("请求路径错误"); setProgressBar(0, 'kb/s', 'hide', '0%'); return; } if (xhr.status == 500) { console.error('xhr.status == 500'); showMessage("服务器异常"); } }; //请求异常(不包括404) xhr.onerror = function () { console.error('xhr.onerror'); showMessage("请求发生异常"); }; //上传开始事件 xhr.upload.onloadstart = function () { setProgressBar(0, 'kb/s', 'hide', '0%'); lastTime = new Date().getTime(); loadSize = 0; } //上传过程事件,间歇调用该方法用来获取上传过程中的信息 xhr.upload.onprogress = function (event) { //ProgressEvent.lengthComputable:boolean类型,表示能否计算出文件长度;如果为false,那么ProgressEvent.total则为0. //简而言之,lengthComputabl等于true就可以做进度计算 if (!event.lengthComputable) { return; } //计算上传速度,event.loaded是已发送的大小 var now = new Date().getTime(); var timeInterval = (now - lastTime) / 1000; lastTime = now; var sizeInterval = event.loaded - loadSize; loadSize = event.loaded; var speed = sizeInterval / timeInterval; // 单位b/s var bspeed = speed; var units = "b/s"; if (speed / 1024 > 1) { speed = speed / 1024; units = 'kb/s'; } if (speed / 1024 > 1) { speed = speed / 1024; units = 'mb/s'; } speed = speed.toFixed(1); //计算剩余时间 var resttime = ((event.total - event.loaded) / bspeed).toFixed(1); //单位 秒 //计算进度百分比 var precent = (100 * event.loaded / event.total); pre = Math.floor(precent); if (bspeed == 0) { //setProgressBar方法是控制进度条的, //这里代码没贴,在最后源码下载里有 //四个参数:上传速度、单位、剩余时间、进度百分比 setProgressBar(0, "b/s", 'infinity', 'noChange'); } else { setProgressBar(speed, units, resttime, precent + '%'); } }; //上传终止 xhr.upload.onabort = function () { console.info('xhr.upload.onabort'); } //上传异常事件 //当网络环境正常时,XMLHttpRequest.status等于404、500并不能触发upload.onerror事件 //当网络环境异常时(offline),会触发upload.onerror事件 xhr.upload.onerror = function () { console.error('xhr.upload.onerror'); } //文件发送完毕事件 //当网络环境正常时,即使XMLHttpRequest.status等于404、500,仍会被触发upload.onload事件 //当网络环境异常时(offline),不会触发upload.onload事件 xhr.upload.onload = function () { console.info('xhr.upload.onload'); } //上传超时 xhr.upload.ontimeout = function () { console.error('xhr.upload.ontimeout'); } //发送请求 xhr.send(formData); }
后台接收代码
[HttpPost] public ActionResult UploadFile_2() { HttpPostedFileBase file = Request.Files["UserPhoto"]; file.SaveAs(Server.MapPath("~/Upload/") + file.FileName); return Json("success"); }
要点说明
- 无需 <form> 标签
- 通过判断document.getElementById('File2').files 及 window.FormData 对象是否为 undefined ,得出当前浏览器是否具备我们所需的HTML5特性;
- FormData对象如同其名称一样以键值对形式存储表单数据;
- 主要借助 xhr.upload 对象的两个事件 onloadstart、onprogress 实现进度条。
3、JQuery异步上传
- 上个例子的Jquery版;
- 同样需要HTML5特性支持,无法在低版本浏览器使用。
$('#btnUpload3').click(function () { var $fileInput = $('#File3'); if (!$fileInput.val()) { return; } var feature = {}; //检查是否支持html5 api feature.fileapi = $fileInput.get(0).files !== undefined; feature.formdata = (typeof window.FormData !== 'undefined'); if (!feature.fileapi || !feature.formdata) { showMessage('当前浏览器不支持Html5,请更换高级浏览器'); return; } var formData = new FormData(); formData.append("UserPhoto", $fileInput[0].files[0]); $.ajax({ type: 'post', url: './UploadFile_2', data: formData, processData: false,//设置为false。因为data值是FormData对象,不需要对数据做处理。 contentType: false, //设置为false。告诉jQuery不要去设置Content-Type请求头 xhr: function () { var xhr = $.ajaxSettings.xhr(); if (xhr.upload) { xhr.upload.onloadstart = uploadStart; xhr.upload.onprogress = uploadProgress; return xhr; } }, success: function (data, textStatus, jqXHR) { showMessage("上传成功"); }, error: function (jqXHR, textStatus, errorThrown) { showMessage("上传失败"); } }); });
要点说明
- processData、contentType 设置为 false;
- $.ajax()方法中需要为请求设置xhr赋值一个function,用于加工$.ajax()的XmlHttpRequest对象,为xhr.upload 对象的两个事件 onloadstart、onprogress 绑定处理方法,处理方法同例子2一样。最后的源码下载中会有。
4、异步表单插件jquery.form.js
- 前三个例子的集成版,需要 <form> 标签做兼容;
- 当浏览器不支持H5,使用例子1的方式;
- 当浏览器支持H5,使用例子2、3的方式。
html代码
<form id="form4" enctype="multipart/form-data" action="UploadFile_2" method="post"> <div class="item"> <h3> 4、异步表单插件jquery.form.js </h3> <input id="File4" name="UserPhoto" type="file" value="" /> <input id="btnUpload4" type="button" value="提交上传" /> </div> </form>
js代码
$('#btnUpload4').click(function () { var $fileInput = $('#File4'); if (!$fileInput.val()) { return; } var options = { type: 'post', url: './UploadFile_2', success: function (data, textStatus, jqXHR) { showMessage("上传成功"); }, error: function (jqXHR, textStatus, errorThrown) { showMessage("上传失败"); } } var feature = {}; //检查是否支持html5 api feature.fileapi = $fileInput.get(0).files !== undefined; feature.formdata = (typeof window.FormData !== 'undefined'); //如果支持html5,那么就使用进度条 if (feature.fileapi && feature.formdata) { options = $.extend(options, { xhr: function () { var xhr = $.ajaxSettings.xhr(); if (xhr.upload) { xhr.upload.onloadstart = uploadStart; xhr.upload.onprogress = uploadProgress; return xhr; } } }); } $("#form4").ajaxSubmit(options); });
要点说明
- jquery.form.js 仍然需要<form>标签作为兼容基础;
- ajaxSubmit(options)方法中的options参数与$.ajax(options)的参数其实是同一个对象,本质就是 ajaxSubmit为 $.ajax 批了一件外套;
- 根据上一点,我们可以使用例子3中同样的手段实现进度条。
源码下载:https://pan.baidu.com/s/1eWiOzvio9EVW2WlYeaKUGA
代码是用VS2015 ASP.NET MVC5写的,我把bin目录内的dll都删了,通过还原 nuget 程序包应该就能运行了。