文件上传的几个例子
项目中用到的几个文件上传的例子,记录下,免得以后重复查找。
1、html5文件上传
以前上传文件需要提交Form表单。
HTML5方式上传文件,可以通过使用FormData类模拟Form表单提交,从而实现无刷新上传文件。
假设有一个文件选择框
<input id="chooseImage" type="file" style="display: none">
可以在html中另外写一个dom来触发文件选择,或者直接使用文件选择也可以(丑一点)
<style> .upload_img { width: 80px; height: 80px; background-color: #fff; color: green; border: 1px solid green; border-radius: 5px; text-align: center; line-height: 80px; font-size: 40px; background-position: center; background-size: contain; cursor: pointer; } </style> <div class="form-group cell_upload"> <label class="col-sm-4 control-label no-padding-right" for="pname"><span class="lbl-warning">*</span> 转让文件 </label> <div class="col-sm-4"> <div class="upload_img" style="background-image: url("");">+</div> </div> <div class="col-sm-4"> <div class="upload_ready"></div> </div> </div> $(function () { $('.cell_upload .upload_img').click(function () { $('#chooseImage').click();//激活图片上传 }); })
选择XMLHttpRequest方式上传(有进度事件)
//图片上传 $("#chooseImage").change(function () { var file = $(this)[0].files[0];//获取files对象 //禁用提交按钮 $('.btn-primary-transfer').attr('disabled', true); $('.btn-primary-transfer').css('background-color', '#ccc'); //显示进度条 $('.cell_upload').after($('.progressbar')); $('.progressbar #sliderTrack').width('0%'); $('.progressbar #sliderHandler').css('left', '0%'); $('.progressbar #sliderValue').html('0%'); $('.progressbar').show(); var files = document.getElementById('chooseImage').files; //files是文件选择框选择的文件对象数组 if (files.length == 0) return; var form = new FormData(), url = '/DC/File/patent_transferUpload', //服务器上传地址 file = files[0]; form.append('file', file); var xhr = new XMLHttpRequest(); xhr.open("post", url, true); //上传进度事件 xhr.upload.addEventListener("progress", function (progress) { if (progress.lengthComputable) { //上传进度 var prog = parseInt(progress.loaded / progress.total * 100); $('.progressbar #sliderTrack').width(prog + '%'); $('.progressbar #sliderHandler').css('left', prog + '%'); $('.progressbar #sliderValue').html(prog + '%'); } }, false); xhr.addEventListener("readystatechange", function () { var result = xhr; if (result.status != 200) { //error console.log('上传失败', result.status, result.statusText, result.response); } else if (result.readyState == 4) { //finished console.log('上传成功', result); $('#btnSubmit').removeAttr('disabled'); $('#btnSubmit').css('background-color', '#1AAD19'); $('.progressbar').slideUp(); let resp = JSON.parse(result.response); if (resp.state) { $('#filepath').val(resp.filepath); $('#filename').val(resp.filename); let vfile = `<a href="${resp.filePath}" download="${resp.fileName}" target="_blank">${resp.fileName}</a>`; $('.cell_upload .upload_ready').html(vfile); $('.cell_upload .upload_img').html('✔'); } } }); xhr.send(form); //开始上传 })
@*图片上传工具*@ <input id="chooseImage" type="file" style="display: none"> @*进度条*@ <div class="weui-cell progressbar"> @*<div class="weui-cell__hd"><label class="weui-label">进度</label></div>*@ <div class="weui-cell__bd"> <div class="weui-slider-box"> <div class="weui-slider"> <div id="sliderInner" class="weui-slider__inner" style="background-color: #aaa;"> <div id="sliderTrack" style="width: 0%;" class="weui-slider__track"></div> <div id="sliderHandler" style="left: 0%;" class="weui-slider__handler"></div> </div> </div> <div id="sliderValue" class="weui-slider-box__value">50</div> </div> </div> </div>
附加:另外一种网友提供的方式,自己木有使用
var form = new FormData(), url = 'http://.......', //服务器上传地址 file = files[0]; form.append('file', file); fetch(url, { method: 'POST', body: form }).then(function(response) { if (response.status >= 200 && response.status < 300) { return response; } else { var error = new Error(response.statusText); error.response = response; throw error; } }).then(function(resp) { return resp.json(); }).then(function(respData) { console.log('文件上传成功', respData); }).catch(function(e) { console.log('文件上传失败', e); }); --------------------- 作者:神秘_博士 来源:CSDN 原文:https://blog.csdn.net/lovelyelfpop/article/details/71421123 版权声明:本文为博主原创文章,转载请附上博文链接!
后台接收程序(项目使用的是.net mvc)
public JsonResult patent_transferUpload() { string physicalFolderPath = string.Empty;//物理文件夹路径 HttpFileCollection hfc = System.Web.HttpContext.Current.Request.Files; if (string.IsNullOrEmpty(this.demandFolderPath)) { // physicalFolderPath = Server.MapPath(@"\Files\DemandFiles"); physicalFolderPath = "/Files/patent_transfer"; } else { physicalFolderPath = this.demandFolderPath; } return Upload(hfc, physicalFolderPath, ""); } /// <summary> /// 保存文件 /// </summary> /// <param name="hfc">文件信息</param> /// <param name="physicalFolderPath">物理文件存储文件夹绝对路径</param> /// <returns></returns> private JsonResult Upload(HttpFileCollection hfc, string physicalFolderPath,string guid) { try { string msg = "位置错误!"; string physicalFullPath = string.Empty; string fileName = string.Empty; bool isSuccess = false; var files = Request.Files; if (guid == "") { guid = Guid.NewGuid().ToString(); } if (hfc != null && hfc.Count > 0) { try { fileName = hfc[0].FileName; if (!string.IsNullOrEmpty(fileName)) { string save_dir= Server.MapPath(physicalFolderPath); if (!Directory.Exists(save_dir)) { Directory.CreateDirectory(save_dir); } physicalFullPath = physicalFolderPath + "/" + guid + Path.GetExtension(fileName); string savepath = Server.MapPath(physicalFullPath) ; hfc[0].SaveAs(savepath); isSuccess = true; msg = "上传成功!"; } else { msg = "未识别任何有效文件!"; } } catch (Exception e) { msg = e.Message; } } return Json(new { state = isSuccess, message = msg,guid= guid, fileName = fileName, filePath = physicalFullPath }, JsonRequestBehavior.AllowGet); } catch { return Json(new { state = false, message = "上传文件失败!" }, JsonRequestBehavior.AllowGet); } }
引用:
https://blog.csdn.net/lovelyelfpop/article/details/71421123
*************************************************************** 华丽丽的分割线 ***************************************************************
2 移动端的图片压缩上传(使用二进制数据流)
这是一个在微信公众号开发中用到的图片上传
同1,在html中添加一个文件上传的控件
<input id="chooseImage" type="file" style="display: none">
然后在写一个控件来触发文件上传,同时为上传添加进度条显示.progressbar
<style> .upload_img { width: 80px; height: 80px; background-color: #fff; color: green; border:1px solid green; border-radius: 5px; text-align: center; line-height: 80px; font-size: 40px; background-position:center; background-size:contain; } .upload_delete { display:none; width: 30px; height: 30px; background-color: orangered; color: #fff; border-radius: 50%; text-align: center; line-height: 30px; font-size: 24px; margin-left: 20px; } </style> <div > <div class="weui-cell__hd"><label class="weui-label"></label></div> <div class="weui-cell__bd cell_upload box-space-between" tag="2e89acb0-b36e-4934-9c31-f718aea815f9"> <div tag="" class="upload_img" style="background-image: url("");">+</div> <div tag="" class="upload_delete" style="display: none;">-</div> <input class="upload_save" id="" type="text" style="display:none;"> </div> </div> @*图片上传工具*@ <input id="chooseImage" type="file" style="display: none"> @*进度条*@ <div class="weui-cell progressbar"> @*<div class="weui-cell__hd"><label class="weui-label">进度</label></div>*@ <div class="weui-cell__bd"> <div class="weui-slider-box"> <div class="weui-slider"> <div id="sliderInner" class="weui-slider__inner" style="background-color: #aaa;"> <div id="sliderTrack" style="width: 0%;" class="weui-slider__track"></div> <div id="sliderHandler" style="left: 0%;" class="weui-slider__handler"></div> </div> </div> <div id="sliderValue" class="weui-slider-box__value">50</div> </div> </div> </div>
上传限制了图片的类型和大小
//图片上传 $("#chooseImage").change(function () { var file = $(this)[0].files[0];//获取files对象 var rFilter = /^(image\/jpeg|image\/png)$/i; // 检查图片格式 if (!rFilter.test(file.type)) { wxAlert.showMsg('只可以上传.jpg/.jpeg/.png格式的图片!'); return false; } if (file.size > 5000000) { wxAlert.showMsg('上传图片最大为5M,请重新上传!'); return false; } //禁用提交按钮 $('#btnSubmit').attr('disabled', true); $('#btnSubmit').css('background-color', '#ccc'); //显示进度条 $('.cell_upload').parent().after($('.progressbar')); $('.progressbar #sliderTrack').width('0%'); $('.progressbar #sliderHandler').css('left', '0%'); $('.progressbar #sliderValue').html('0%'); $('.progressbar').show(); //0.5为当前压缩比 var ratio = 1; if (file.size > 500000 && file.size <= 1000000) { ratio = 0.8;//0.5-1M压缩比 } else if (file.size > 1000000 && file.size <= 2000000) { ratio = 0.7;//1-2M压缩比 } else if (file.size > 2000000 && file.size <= 5000000) { ratio = 0.5;//2-5M压缩比 } else if (file.size > 5000000 && file.size <= 10000000) { ratio = 0.4;//5-10M压缩比 } file_compress(file, ratio); }) //压缩文件并上传 function file_compress(file, ratio) { $.compress(file, ratio).then((url) => { $('.upload_img').css({ "background-image": "url(" + url + ")" }); /*----------------上传到服务器-----------------*/ var posturl = '/wechatPage/health_record/health_recordFile'; var filename = hr_type_selected + '_' + health_record_id + '_' + templateID_active;//文件名定义为typeID+’_’+hrID+’_’+templateID.jpg var para = { imgbase: url, filename: filename }; $.ajax({ type: "POST", url: posturl, data: para, //这里上传的数据使用了formData 对象 xhr: function () { var xhr = $.ajaxSettings.xhr(); if (xhr.upload) { xhr.upload.onprogress = function (progress) { if (progress.lengthComputable) { //上传进度 var prog = parseInt(progress.loaded / progress.total * 100); $('.progressbar #sliderTrack').width(prog + '%'); $('.progressbar #sliderHandler').css('left', prog + '%'); $('.progressbar #sliderValue').html(prog + '%'); } }; xhr.upload.onloadstart = function () { console.log('started...'); }; } return xhr; } }).done(function (resp) { //上传完成 $('#btnSubmit').removeAttr('disabled'); $('#btnSubmit').css('background-color', '#1AAD19'); $('.progressbar').slideUp(); if (resp.state) { //do something } }).fail(function (err) { alert('无法连接服务器!') }); }) }
压缩处理图片(需将此compress.js文件引用到html中)
compress.js 先创建了一块画布canvas,然后根据需要压缩的程度,使用canvas进行画图,然后再将画好的压缩过的图片转化为数据流返回,
resolve关键字可理解为Promise的正确执行后的返回值。
Promise的then关键字即是接收resolve传回的参数
(function ($) { $.extend({ //压缩图片,参数1:file对象,参数2:压缩比例 compress(file, scale) { return new Promise(function (resolve, reject) { let _scale = scale || 1; let cvs = document.createElement('canvas'); let ctx = cvs.getContext('2d'); let img = new window.Image(); let imgType = file.type; img.src = URL.createObjectURL(file); img.onload = function () { cvs.width = img.width * _scale; cvs.height = img.height * _scale; EXIF.getData(img, function () { EXIF.getAllTags(this); var orient = EXIF.getTag(this, 'Orientation'); //alert('orient:' + orient); switch (orient) { case 3: ctx.rotate(180 * Math.PI / 180); ctx.drawImage(img, -cvs.width, -cvs.height, cvs.width, cvs.height); break; case 6: cvs.width = img.height * _scale; cvs.height = img.width * _scale; ctx.rotate(90 * Math.PI / 180); ctx.drawImage(img, 0, -cvs.width, cvs.height, cvs.width); break; case 8: ctx.rotate(270 * Math.PI / 180); ctx.drawImage(img, -cvs.height, 0, cvs.height, cvs.width); break; case 2: ctx.translate(cvs.width, 0); ctx.scale(-1, 1); ctx.drawImage(img, 0, 0, cvs.width, cvs.height); break; case 4: ctx.translate(cvs.width, 0); ctx.scale(-1, 1); ctx.rotate(180 * Math.PI / 180); ctx.drawImage(img, -cvs.width, -cvs.height, cvs.width, cvs.height); break; case 5: ctx.translate(cvs.width, 0); ctx.scale(-1, 1); ctx.rotate(90 * Math.PI / 180); ctx.drawImage(img, 0, -cvs.width, cvs.height, cvs.width); break; case 7: ctx.translate(cvs.width, 0); ctx.scale(-1, 1); ctx.rotate(270 * Math.PI / 180); ctx.drawImage(img, -cvs.height, 0, cvs.height, cvs.width); break; default: ctx.drawImage(img, 0, 0, cvs.width, cvs.height); } resolve(cvs.toDataURL(imgType)); }); } }); } }); })(jQuery)
期间遇到iphone手机直接拍摄图片后上传,图片反转90度的问题,在compress.js 获取了文件的Orientation属性
var orient = EXIF.getTag(this, 'Orientation');
可以根据图片的翻转类型对图片的反转度进行调整。
后台接收程序
/// <summary> /// 上传健康档案文件 /// </summary> /// <param name="imgbase">图片数据流</param> /// <param name="filename">保存的图片名</param> /// <returns></returns> [HttpPost] public ActionResult health_recordFile(string imgbase, string filename) { try { //保存目录 string dir = "/Files/health_record"; //站点文件目录 string fileDir = Server.MapPath("~" + dir); //保存文件所在站点位置 string filePath = Path.Combine(fileDir, filename); if (!System.IO.Directory.Exists(fileDir)) System.IO.Directory.CreateDirectory(fileDir); //将Base64String转为图片并保存 // byte[] arr2 = Convert.FromBase64String(imgbase); byte[] arr2 = Convert.FromBase64String(imgbase.Substring(imgbase.IndexOf(',') + 1)); using (MemoryStream ms2 = new MemoryStream(arr2)) { System.Drawing.Bitmap bmp2 = new System.Drawing.Bitmap(ms2); bmp2.Save(filePath + ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg); bmp2.Dispose(); } var msg = new { state = true, msg = "上传图片成功!", imgsrc = dir + "/" + filename + "" + ".jpg" }; return Json(msg); } catch { var msg = new { state = false, msg = "上传图片失败!", imgsrc = "" }; return Json(msg); } }
附:js中使用了Promise函数的简介说明
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h4>Promise:把原来的回调写法分离出来,在异步操作执行完后,用链式调用的方式执行回调函数</h4> <h5>resolve:将Promise的状态置为fullfiled,可理解为成功回调</h5> <h5>reject:将Promise的状态置为rejected,可理解为失败回调</h5> <h5>then:then接收一个参数,是函数,并且会拿到我们在runAsync中调用resolve时传的的参数</h5> <h5>catch:catch接收一个参数,是函数,并且会拿到我们在runAsync中调用reject时传的的参数</h5> <h5>all:提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调「谁跑的慢,以谁为准执行回调」</h5> <pre>all的使用场景1:一些游戏类的素材比较多的应用,打开网页时,预先加载需要用到的各种资源如图片、flash以及各种静态文件。所有的都加载完后,我们再进行页面的初始化。</pre> <pre>all的使用场景2:在较复杂的页面,等所有的异步加载全部完成后,再渲染页面。</pre> <h5>race:同all一样提供并行操作的能力,区别是race执行标准是:[谁跑的快,以谁为准执行回调]</h5> <pre>race使用场景:用race给某个异步请求设置超时时间,并且在超时后执行相应的操作(比如请求图片时设置超时时间)</pre> <script type="text/javascript" src="../../script/jquery-1.8.3.min.js"></script> <script type="text/javascript"> $(function () { fun_01(); fun_02(); fun_03(); }) let fun_01=()=>{ console.log('---------- Promise01 ----------'); new Promise(test).then(function (result) { console.log('Success:'+result); }).catch(function (result) { console.log('Fail:'+result); }) }; function test(resolve,reject) { let timeout=Math.random()*2; console.log('set timeout to:'+timeout+' seconds'); setTimeout(function () { if(timeout<1){ console.log('call resolve()...'); resolve('200 OK'); }else{ console.log('call reject()...'); reject('timeout in '+timeout+' seconds'); } },timeout*1000); } let fun_02=()=>{ console.log('---------- Promise02 ----------'); runAsync().then(function (data) { console.log(data); }); runAsync1().then(function (data) { console.log(data); return runAsync2(); }).then(function (data) { console.log(data); return runAsync3(); }); setTimeout(runAll,5*1000); }; function runAll() { console.log('----------Promise.all----------'); //Promise的all方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调 Promise.all([runAsync1(),runAsync2(),runAsync3()]).then(function (result) { console.log(result); }) } function runAsync() { let p=new Promise(function (resolve,reject) { setTimeout(function () { console.log('timeout done!'); resolve(' anythind you want'); }) }) return p; } function runAsync1(){ var p = new Promise(function(resolve, reject){ //做一些异步操作 setTimeout(function(){ console.log('异步任务1执行完成'); resolve('随便什么数据1'); }, 1000); }); return p; } function runAsync2(){ var p = new Promise(function(resolve, reject){ //做一些异步操作 setTimeout(function(){ console.log('异步任务2执行完成'); resolve('随便什么数据2'); }, 1000); }); return p; } function runAsync3(){ var p = new Promise(function(resolve, reject){ //做一些异步操作 setTimeout(function(){ console.log('异步任务3执行完成'); resolve('随便什么数据3'); }, 1000); }); return p; } let fun_03=()=>{ console.log('---------- Promise03 ----------'); Promise .race([requestImg(), timeout()]) .then(function(results){ console.log(results); }) .catch(function(reason){ console.log(reason); }); }; //请求某个图片资源 function requestImg(){ var p = new Promise(function(resolve, reject){ var img = new Image(); img.onload = function(){ resolve(img); } img.src = 'xxxxxx'; }); return p; } //延时函数,用于给请求计时 function timeout(){ var p = new Promise(function(resolve, reject){ setTimeout(function(){ reject('图片请求超时'); }, 5000); }); return p; } </script> </body> </html>
*************************************************************** 华丽丽的分割线 ***************************************************************
3.dropzone文件上传
官网:https://www.dropzonejs.com/
中文文档:http://wxb.github.io/dropzonejs.com.zh-CN/dropzonezh-CN/#configuration
个人觉得比较好的一个上传工具,常用的配置项和事件都很清楚,自带多文件上传和进度条,很赞。
不好的地方时,每个页面只能初始化一个dropzone,如遇到页面嵌套的dom也需要上传文件的情况就处理不了了,目前木有解决,官方也木有闻文档说明。
下面是需要引用的css文件(由于在上传单文件的时候,dropzone原来的上传框页面尺寸太大,我对css又做了一点调整,使其适合单独放在页面的dom中,所以自己记录下)
当然原始文件官网都可以下载到
/* * The MIT License * Copyright (c) 2012 Matias Meno <m@tias.me> */ @-webkit-keyframes passing-through { 0% { opacity: 0; -webkit-transform: translateY(40px); -moz-transform: translateY(40px); -ms-transform: translateY(40px); -o-transform: translateY(40px); transform: translateY(40px); } 30%, 70% { opacity: 1; -webkit-transform: translateY(0px); -moz-transform: translateY(0px); -ms-transform: translateY(0px); -o-transform: translateY(0px); transform: translateY(0px); } 100% { opacity: 0; -webkit-transform: translateY(-40px); -moz-transform: translateY(-40px); -ms-transform: translateY(-40px); -o-transform: translateY(-40px); transform: translateY(-40px); } } @-moz-keyframes passing-through { 0% { opacity: 0; -webkit-transform: translateY(40px); -moz-transform: translateY(40px); -ms-transform: translateY(40px); -o-transform: translateY(40px); transform: translateY(40px); } 30%, 70% { opacity: 1; -webkit-transform: translateY(0px); -moz-transform: translateY(0px); -ms-transform: translateY(0px); -o-transform: translateY(0px); transform: translateY(0px); } 100% { opacity: 0; -webkit-transform: translateY(-40px); -moz-transform: translateY(-40px); -ms-transform: translateY(-40px); -o-transform: translateY(-40px); transform: translateY(-40px); } } @keyframes passing-through { 0% { opacity: 0; -webkit-transform: translateY(40px); -moz-transform: translateY(40px); -ms-transform: translateY(40px); -o-transform: translateY(40px); transform: translateY(40px); } 30%, 70% { opacity: 1; -webkit-transform: translateY(0px); -moz-transform: translateY(0px); -ms-transform: translateY(0px); -o-transform: translateY(0px); transform: translateY(0px); } 100% { opacity: 0; -webkit-transform: translateY(-40px); -moz-transform: translateY(-40px); -ms-transform: translateY(-40px); -o-transform: translateY(-40px); transform: translateY(-40px); } } @-webkit-keyframes slide-in { 0% { opacity: 0; -webkit-transform: translateY(40px); -moz-transform: translateY(40px); -ms-transform: translateY(40px); -o-transform: translateY(40px); transform: translateY(40px); } 30% { opacity: 1; -webkit-transform: translateY(0px); -moz-transform: translateY(0px); -ms-transform: translateY(0px); -o-transform: translateY(0px); transform: translateY(0px); } } @-moz-keyframes slide-in { 0% { opacity: 0; -webkit-transform: translateY(40px); -moz-transform: translateY(40px); -ms-transform: translateY(40px); -o-transform: translateY(40px); transform: translateY(40px); } 30% { opacity: 1; -webkit-transform: translateY(0px); -moz-transform: translateY(0px); -ms-transform: translateY(0px); -o-transform: translateY(0px); transform: translateY(0px); } } @keyframes slide-in { 0% { opacity: 0; -webkit-transform: translateY(40px); -moz-transform: translateY(40px); -ms-transform: translateY(40px); -o-transform: translateY(40px); transform: translateY(40px); } 30% { opacity: 1; -webkit-transform: translateY(0px); -moz-transform: translateY(0px); -ms-transform: translateY(0px); -o-transform: translateY(0px); transform: translateY(0px); } } @-webkit-keyframes pulse { 0% { -webkit-transform: scale(1); -moz-transform: scale(1); -ms-transform: scale(1); -o-transform: scale(1); transform: scale(1); } 10% { -webkit-transform: scale(1.1); -moz-transform: scale(1.1); -ms-transform: scale(1.1); -o-transform: scale(1.1); transform: scale(1.1); } 20% { -webkit-transform: scale(1); -moz-transform: scale(1); -ms-transform: scale(1); -o-transform: scale(1); transform: scale(1); } } @-moz-keyframes pulse { 0% { -webkit-transform: scale(1); -moz-transform: scale(1); -ms-transform: scale(1); -o-transform: scale(1); transform: scale(1); } 10% { -webkit-transform: scale(1.1); -moz-transform: scale(1.1); -ms-transform: scale(1.1); -o-transform: scale(1.1); transform: scale(1.1); } 20% { -webkit-transform: scale(1); -moz-transform: scale(1); -ms-transform: scale(1); -o-transform: scale(1); transform: scale(1); } } @keyframes pulse { 0% { -webkit-transform: scale(1); -moz-transform: scale(1); -ms-transform: scale(1); -o-transform: scale(1); transform: scale(1); } 10% { -webkit-transform: scale(1.1); -moz-transform: scale(1.1); -ms-transform: scale(1.1); -o-transform: scale(1.1); transform: scale(1.1); } 20% { -webkit-transform: scale(1); -moz-transform: scale(1); -ms-transform: scale(1); -o-transform: scale(1); transform: scale(1); } } .dropzone, .dropzone * { box-sizing: border-box; } .dropzone { width:110px; min-height: 90px; border: 2px solid rgba(0, 0, 0, 0.3); background: white; padding: 0px 0px; } .dropzone.dz-clickable { cursor: pointer; } .dropzone.dz-clickable * { cursor: default; } .dropzone.dz-clickable .dz-message, .dropzone.dz-clickable .dz-message * { cursor: pointer; } .dropzone.dz-started .dz-message { display: none; } .dropzone.dz-drag-hover { border-style: solid; } .dropzone.dz-drag-hover .dz-message { opacity: 0.5; } .dropzone .dz-message { text-align: center; } .dropzone .dz-preview { position: relative; display: inline-block; vertical-align: top; margin: 2px; min-height: 100px; } .dropzone .dz-preview:hover { z-index: 1000; } .dropzone .dz-preview:hover .dz-details { opacity: 1; } .dropzone .dz-preview.dz-file-preview .dz-image { border-radius: 20px; background: #999; background: linear-gradient(to bottom, #eee, #ddd); } .dropzone .dz-preview.dz-file-preview .dz-details { opacity: 1; } .dropzone .dz-preview.dz-image-preview { background: white; } .dropzone .dz-preview.dz-image-preview .dz-details { -webkit-transition: opacity 0.2s linear; -moz-transition: opacity 0.2s linear; -ms-transition: opacity 0.2s linear; -o-transition: opacity 0.2s linear; transition: opacity 0.2s linear; } .dropzone .dz-preview .dz-remove { font-size: 14px; text-align: center; display: block; cursor: pointer; border: none; } .dropzone .dz-preview .dz-remove:hover { text-decoration: underline; } .dropzone .dz-preview:hover .dz-details { opacity: 1; } .dropzone .dz-preview .dz-details { z-index: 20; position: absolute; top: 0; left: 0; opacity: 0; font-size: 13px; min-width: 100%; max-width: 100%; padding: 2em 1em; text-align: center; color: rgba(0, 0, 0, 0.9); line-height: 150%; } .dropzone .dz-preview .dz-details .dz-size { margin-bottom: 1em; font-size: 16px; } .dropzone .dz-preview .dz-details .dz-filename { white-space: nowrap; } .dropzone .dz-preview .dz-details .dz-filename:hover span { border: 1px solid rgba(200, 200, 200, 0.8); background-color: rgba(255, 255, 255, 0.8); } .dropzone .dz-preview .dz-details .dz-filename:not(:hover) { overflow: hidden; text-overflow: ellipsis; } .dropzone .dz-preview .dz-details .dz-filename:not(:hover) span { border: 1px solid transparent; } .dropzone .dz-preview .dz-details .dz-filename span, .dropzone .dz-preview .dz-details .dz-size span { background-color: rgba(255, 255, 255, 0.4); padding: 0 0.4em; border-radius: 3px; } .dropzone .dz-preview:hover .dz-image img { -webkit-transform: scale(1.05, 1.05); -moz-transform: scale(1.05, 1.05); -ms-transform: scale(1.05, 1.05); -o-transform: scale(1.05, 1.05); transform: scale(1.05, 1.05); -webkit-filter: blur(8px); filter: blur(8px); } .dropzone .dz-preview .dz-image { border-radius: 20px; overflow: hidden; width: 100px; height: 100px; position: relative; display: block; z-index: 10; } .dropzone .dz-preview .dz-image img { display: block; } .dropzone .dz-preview.dz-success .dz-success-mark { -webkit-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); -moz-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); -ms-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); -o-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); } .dropzone .dz-preview.dz-error .dz-error-mark { opacity: 1; -webkit-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); -moz-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); -ms-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); -o-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); } .dropzone .dz-preview .dz-success-mark, .dropzone .dz-preview .dz-error-mark { pointer-events: none; opacity: 0; z-index: 500; position: absolute; display: block; top: 50%; left: 50%; margin-left: -27px; margin-top: -27px; } .dropzone .dz-preview .dz-success-mark svg, .dropzone .dz-preview .dz-error-mark svg { display: block; width: 54px; height: 54px; } .dropzone .dz-preview.dz-processing .dz-progress { opacity: 1; -webkit-transition: all 0.2s linear; -moz-transition: all 0.2s linear; -ms-transition: all 0.2s linear; -o-transition: all 0.2s linear; transition: all 0.2s linear; } .dropzone .dz-preview.dz-complete .dz-progress { opacity: 0; -webkit-transition: opacity 0.4s ease-in; -moz-transition: opacity 0.4s ease-in; -ms-transition: opacity 0.4s ease-in; -o-transition: opacity 0.4s ease-in; transition: opacity 0.4s ease-in; } .dropzone .dz-preview:not(.dz-processing) .dz-progress { -webkit-animation: pulse 6s ease infinite; -moz-animation: pulse 6s ease infinite; -ms-animation: pulse 6s ease infinite; -o-animation: pulse 6s ease infinite; animation: pulse 6s ease infinite; } .dropzone .dz-preview .dz-progress { opacity: 1; z-index: 1000; pointer-events: none; position: absolute; height: 16px; left: 50%; top: 50%; margin-top: -8px; width: 80px; margin-left: -40px; background: rgba(255, 255, 255, 0.9); -webkit-transform: scale(1); border-radius: 8px; overflow: hidden; } .dropzone .dz-preview .dz-progress .dz-upload { background: #333; background: linear-gradient(to bottom, #666, #444); position: absolute; top: 0; left: 0; bottom: 0; width: 0; -webkit-transition: width 300ms ease-in-out; -moz-transition: width 300ms ease-in-out; -ms-transition: width 300ms ease-in-out; -o-transition: width 300ms ease-in-out; transition: width 300ms ease-in-out; } .dropzone .dz-preview.dz-error .dz-error-message { display: block; } .dropzone .dz-preview.dz-error:hover .dz-error-message { opacity: 1; pointer-events: auto; } .dropzone .dz-preview .dz-error-message { pointer-events: none; z-index: 1000; position: absolute; display: block; display: none; opacity: 0; -webkit-transition: opacity 0.3s ease; -moz-transition: opacity 0.3s ease; -ms-transition: opacity 0.3s ease; -o-transition: opacity 0.3s ease; transition: opacity 0.3s ease; border-radius: 8px; font-size: 13px; top: 130px; left: -10px; width: 110px; background: #be2626; background: linear-gradient(to bottom, #be2626, #a92222); padding: 0.5em 1.2em; color: white; } .dropzone .dz-preview .dz-error-message:after { content: ''; position: absolute; top: -6px; left: 64px; width: 0; height: 0; border-left: 6px solid transparent; border-right: 6px solid transparent; border-bottom: 6px solid #be2626; }
》需要引用的文件
<link rel="stylesheet" href="~/assets/dropzone/dist/dropzone.css" />
<script type="text/javascript" src="~/assets/dropzone/dist/dropzone.js"></script>
html中定义class为dropzone的dom,作为上传控件
<div class="dropzone" id="my-dropzone"></div>
//Dropzone的初始化 Dropzone.options.myDropzone = { //指定上传图片的路径 url: '/DC/File/ReportFileUpload', method: "post", //也可用put paramName: "file", //默认为file maxFiles: 1,//一次性上传的文件数量上限 maxFilesize: 10, //文件大小,单位:MB acceptedFiles: "*", //上传的类型 addRemoveLinks: true, //添加上传取消和删除预览图片的链接,默认不添加 autoProcessQueue: true,//关闭自动上传功能,默认会true会自动上传 uploadMultiple: false,//允许上传多个照片 parallelUploads: 1,//每次上传的最多文件数,经测试默认为2,坑啊,记得修改web.config 限制上传文件大小的节 dictDefaultMessage: '拖动文件至此或者点击上传', dictMaxFilesExceeded: "您最多只能上传1个文件!", dictResponseError: '文件上传失败!', dictInvalidFileType: "", dictFallbackMessage: "浏览器不受支持", dictFileTooBig: "文件过大上传文件最大支持.", dictRemoveLinks: "删除", dictCancelUpload: "取消", init: function () { myDropzone = this; // closure this.on("addedfile", function () { this.options.headers = { "id": $('#ID').val() }; $('.modal-dialog .btn-primary').attr("disabled", true); }); //当上传完成后的事件,接受的数据为JSON格式 this.on("complete", function (data) { $('.modal-dialog .btn-primary').removeAttr("disabled"); if (this.getUploadingFiles().length === 0 && this.getQueuedFiles().length === 0) { // var res = eval('(' + data.xhr.responseText + ')'); var res = JSON.parse(data.xhr.responseText) if (res.state) { //do something } else { CM.showMsg('上传文件失败!'); } } }); //删除图片的事件,当上传的图片为空时,使上传按钮不可用状态 this.on("removedfile", function () { if (this.getAcceptedFiles().length === 0) { $("#filename").val(''); $("#filepath").val(''); } }); } }; function removeDropzoneFile() { //去除Dropzone已经存在的图片 if (!CM.isNull(myDropzone) && myDropzone.files.length != 0) { for (var i = 0; i < myDropzone.files.length; i++) { myDropzone.removeFile(myDropzone.files[0]); } } }
后台的接收方法
public JsonResult ReportFileUpload() { string physicalFolderPath = string.Empty;//物理文件夹路径 HttpFileCollection hfc = System.Web.HttpContext.Current.Request.Files; if (string.IsNullOrEmpty(this.reportFolderPath)) { // physicalFolderPath = Server.MapPath(@"\Files\ReportFiles"); physicalFolderPath = "/Files/ReportFiles"; } else { physicalFolderPath = this.reportFolderPath; } return Upload(hfc, physicalFolderPath,""); } /// <summary> /// 保存文件 /// </summary> /// <param name="hfc">文件信息</param> /// <param name="physicalFolderPath">物理文件存储文件夹绝对路径</param> /// <returns></returns> private JsonResult Upload(HttpFileCollection hfc, string physicalFolderPath,string guid) { try { string msg = "位置错误!"; string physicalFullPath = string.Empty; string fileName = string.Empty; bool isSuccess = false; var files = Request.Files; if (guid == "") { guid = Guid.NewGuid().ToString(); } if (hfc != null && hfc.Count > 0) { try { fileName = hfc[0].FileName; if (!string.IsNullOrEmpty(fileName)) { string save_dir= Server.MapPath(physicalFolderPath); if (!Directory.Exists(save_dir)) { Directory.CreateDirectory(save_dir); } physicalFullPath = physicalFolderPath + "/" + guid + Path.GetExtension(fileName); string savepath = Server.MapPath(physicalFullPath) ; hfc[0].SaveAs(savepath); isSuccess = true; msg = "上传成功!"; } else { msg = "未识别任何有效文件!"; } } catch (Exception e) { msg = e.Message; } } return Json(new { state = isSuccess, message = msg,guid= guid, fileName = fileName, filePath = physicalFullPath }, JsonRequestBehavior.AllowGet); } catch { return Json(new { state = false, message = "上传文件失败!" }, JsonRequestBehavior.AllowGet); } }
附:dropzone常用配置项
url : 必要参数,文件的上传地址; maxFiles : 默认为null,可以指定为一个数值,限制最多文件数量。 maxFilesize : 限制文件的大小,单位是MB; acceptedFiles : 允许上传的文件类型,文件扩展名以逗号隔开,格式见实例; autoProcessQueue : 默认为true,即拖入文件立即自动上传;如果需要在上传之前有一些选择的操作,然后手动上传,可以把该属性设置为false,然后手动点击按钮上传; paramName : 相当于<input>元素的name属性,默认为file。 提示文本: dictDefaultMessage : 没有任何文件被添加时的提示文本; dictFallbackMessage:Fallback 情况下的提示文本。 dictInvalidInputType:文件类型被拒绝时的提示文本。 dictFileTooBig:文件大小过大时的提示文本。 dictCancelUpload:取消上传链接的文本。 dictCancelUploadConfirmation:取消上传确认信息的文本。 dictRemoveFile:移除文件链接的文本。 dictMaxFilesExceeded:超过最大文件数量的提示文本。
附:dropzone常用事件
addedfile : 添加文件是发生
removefile : 手动从服务器删除文件时发生
success : 上传成功后发生
complete:当文件上传成功或失败之后发生。
canceled:当文件在上传时被取消的时候发生。
maxfilesreached:当文件数量达到最大时发生。
maxfilesexceeded:当文件数量超过限制时发生。
totaluploadprogress : 文件上传中的返回值,第一个参数为总上传进度(0到100),第二个为总字节数,第三个为总上传字节数,利用这几个参数,可计算出上传速度,和剩余上传时间;