需求
有這么一個需求,一個form有多個文件要上傳,但又不是傳統的圖片批量上傳那種,是類似下圖這種需求,一開始是用的swfupload做的上傳,但是問題是如果有多個按鈕的話,就要寫很多重復的代碼,於為了代碼的簡潔所以就開始尋求其他的方法,期間試過uploadify,但是由於樣式始終調不出來,最后就放棄了,直到發現這么個小巧的玩意,jQuery File Upload。
本文包含了upload的js實現,html的分析,css的實現等內容,文章末尾有git地址
最簡運行時
官網下載的demo有N多js文件,一大堆js文件中只有幾個才是必要的,其他的文件都是一些用不到的功能,只有在你需要的時候才需要引用。
<script src="http://libs.baidu.com/jquery/1.10.2/jquery.min.js" type="text/javascript"></script> <script src="JS/jquery/jquery.iframe-transport.js"></script> <script src="JS/jquery/jquery.ui.widget.js"></script> <script src="JS/jquery/jquery.xdr-transport.js"></script> <script src="JS/jquery/jquery.fileupload.js"></script>
其中iframe那個文件是為了進行iframe上傳,ui文件是能選完文件自動上傳的必要文件,xdr那個是在ie下才需要的,最后一個文件是主體
后台代碼
新建一個ashx的文件,這里建立一個uploadHandler.ashx,然后寫入如下代碼,用於保存。
public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/plain"; context.Response.Charset = "utf-8"; HttpPostedFile file = context.Request.Files["files"]; string uploadPath = HttpContext.Current.Server.MapPath(@context.Request["folder"]) + "\\"; if (file != null) { if (!Directory.Exists(uploadPath)) { Directory.CreateDirectory(uploadPath); } file.SaveAs(uploadPath + file.FileName); //下面這句代碼缺少的話,上傳成功后上傳隊列的顯示不會自動消失 string newName = file.FileName; string oldName = file.FileName; context.Response.Write("{\"newName\": \"" + newName + "\", \"oldName\": \"" + oldName + "\"}"); } else { context.Response.Write("0"); } }
前台HTML
預覽效果
最終的效果如上圖所示,為了實現這個我們一步一步來分析。
DIV結構
如上圖
- 作為整個控件的最外層
- 是按鈕
- 是上傳完成后顯示的文件名(上傳開始前隱藏)
- 上傳進度百分比(上傳開始前隱藏)
- 上傳進度條(上傳開始前隱藏)
上圖后4個div按照順序寫在最外層里面,然后考慮通過浮動來解決位置的問題,當然也可以用絕對定位等方法來實現,這里選擇了浮動。
因為要用到浮動,這里簡單解釋一下浮動的原理
首先設置0的寬度是280px
所以1的寬度就是70+margin-right:8 右側還有202寬度,左浮動
2的寬度是150px,左浮動
3的寬度不設置,右浮動
4的寬度是200+border:2 一共202寬度,左浮動
然后再設置上傳按鈕,如果不設置樣式,上傳按鈕是這樣的
這樣顯然是老套的樣式了,在網上找了一個解決方案是這樣的
配合這樣的樣式
就可以做出這個效果了
所以html的代碼如下:

<style> body{padding:10px} /* 上傳控件 */ .upload { margin-top:10px; width:280px; height:30px; } .upload .uploadbtnBox { float:left; height:30px; width:70px; margin-right:8px; } .upload .progress { height:4px; line-height:4px; *zoom:1; background:#fff; float:left; width:200px; border:1px #ccc solid; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; display:none; } .upload .filestate { float:left; height:20px; text-align:left; width:150px; line-height:20px; display:none; color:#333; overflow:hidden; } .upload .progresspercent { float:right; padding-top:5px; height:15px; text-align:right; font-size:9px; line-height:15px; color:#333; } .upload .uploadbtnBox .a-upload { height:28px; background:#4090c0; border:1px solid #dddddd;color:#ffffff; line-height:28px; padding:0 6px; font-size:0.9em; overflow: hidden; display: inline-block; text-decoration:none; *display: inline; *zoom: 1 } .upload .uploadbtnBox .a-upload input { position: absolute; width:70px; height:30px; overflow:hidden; margin-left:-10px; opacity: 0; filter: alpha(opacity=0); cursor: pointer } .upload .progress .bar { height:4px; line-height:4px; background:#4090c0; *zoom:1; } .clearfix:after { content: "."; display: block; height: 0; visibility: hidden; clear: both; } .clearfix { _zoom: 1; } .clearfix { *zoom:1; } </style> <div class="upload clearfix"> <div class="uploadbtnBox clearfix"> <a href="javascript:;" class="a-upload"> <input type="file" data-url="uploadHandler.ashx" name="files" value="" id="file7" onchange="CheckFile(this)" />點擊上傳 </a> </div> <div class="filestate"> 文件名</div> <div class="progresspercent"> </div> <div class="progress" style="height: 4px;"> <div class="bar" style="width: 0%;"> </div> </div> </div>
JS部分
基本的upload直接這樣就可以了,
$("input[type=file]").fileupload();
上傳的后台頁面通過input的data-url來設置,如下圖
接下來要處理的是上傳進度
通過計算上傳的百分比設置bar的寬度就可以了
這里用到的是內置的progressall的方法,傳遞2個參數,第一個是e就是sender,通過他找到觸發的input,然后再用jquery去找其他的兄弟元素進行操作,這里是找到了progress和bar然后設置他們的寬度
第二個參數是data,里面包含兩個內置的變量,一個是total,一個是loaded,所以就可以計算出百分比了
上傳完成后顯示文件名,還有給隱藏input賦值,
使用的是內置的函數done,done會提供2個參數,第一個是e就是sender,我們通過他找到對應的input,然后找到其他元素進行操作
另一個參數就是result,在注釋里已經說明了result如何使用了
所以最后的js就是這樣
<script type="text/javascript"> function CheckFile(obj) { var array = new Array('gif', 'jpeg', 'png', 'jpg'); //可以上傳的文件類型 if (obj.value == '') { alert("讓選擇要上傳的圖片!"); return false; } else { var fileContentType = obj.value.match(/^(.*)(\.)(.{1,8})$/)[3]; //這個文件類型正則很有用:) var isExists = false; for (var i in array) { if (fileContentType.toLowerCase() == array[i].toLowerCase()) { isExists = true; return true; } } if (isExists == false) { obj.value = null; alert("上傳圖片類型不正確!"); return false; } return false; } } $(function () { $("input[type=file]").fileupload({ done: function (e, result) { //done方法就是上傳完畢的回調函數,其他回調函數可以自行查看api //注意result要和jquery的ajax的data參數區分,這個對象包含了整個請求信息 //返回的數據在result.result中,假設我們服務器返回了一個json對象
//但是由於IE10以下存在bug,會將XHR的內容識別錯誤,所以第一需要返回Content-Type: text/plain
//其次,及時轉成text/plain還存在取不到result.result的內容,取到的是其他的東西
//需要用這個方法來接值,var jmsg = result.result[0].body ? result.result[0].body.innerHTML : result.result;
//最后接到值后,發現還有<pre></pre>包着需要通過字符串處理去掉這個東西
//json對象{"newName": "sss", "oldName": "sdf"}
var resultJson;
var jmsg = result.result[0].body ? result.result[0].body.innerHTML : result.result;
var startIndex = jmsg.indexOf("{");
var lastIndex = jmsg.lastIndexOf("}");
jmsg = jmsg.substring(startIndex, lastIndex+1);
try { resultJson = $.parseJSON(jmsg); }
catch (e) { resultJson = jmsg; }
var uploadDiv = $(e.target).parent().parent().parent();
uploadDiv.find(".filehidden").val(resultJson.newName);
uploadDiv.find(".filestate").show().text(resultJson.oldName);
}, progressall: function (e, data) { var maxWidth = 200; var percent = (data.loaded / data.total * 100).toFixed(2); var progress = parseInt(data.loaded / data.total * maxWidth, 10); var uploadDiv = $(e.target).parent().parent().parent(); uploadDiv.find(".progress").show(); uploadDiv.find(".bar").css("width", progress); uploadDiv.find(".progresspercent").show().text(percent + "%"); } }) }); </script>
ps:
但是由於IE10以下存在bug,會將XHR的內容識別錯誤,所以第一需要返回Content-Type: text/plain
其次,及時轉成text/plain還存在取不到result.result的內容,取到的是其他的東西
需要用這個方法來接值,var jmsg = result.result[0].body ? result.result[0].body.innerHTML : result.result;
最后接到值后,發現還有<pre></pre>包着需要通過字符串處理去掉這個東西
git地址:https://git.oschina.net/jangojing/jqueryfileuploadDemo.git