jQuery File Upload是一個非常優(yōu)秀的上傳組件,主要使用了XHR作為上傳方式,并且利用了相當多的現(xiàn)代瀏覽器功能,所以可以實現(xiàn)諸如批量上傳、超大文件上傳、圖片預覽、拖拽上傳、上傳進度顯示、跨域上傳等功能。
美中不足的是jQuery File Upload的默認UI比較復雜,集成了全部功能,讓jQuery File Upload的定制變得比較繁瑣。
嘗試用jQuery File Upload制作了一個類似微博圖片上傳的單文件式上傳Demo,將一些要點記錄下來備忘。最終效果如下圖:
jQuery File Upload包含了一堆文件,首先需要弄清楚的是最核心的部分是哪些,根據(jù)官方的例子可以知道,一個最簡單的jQuery File Upload上傳組件,必須包括以下文件:
此時只需要加載一個上傳按鈕
<input id="fileupload" type="file" name="files[]" data-url="server/php/" multiple>
以及一行代碼
$('#fileupload').fileupload();
就完成了一個最基本的上傳組件。這個最簡單的上傳組件可以將選中的文件以表單形式提交到data-url約定的URL,同時提供了足夠多的設置和基礎事件可供擴展。
對于最簡模型,稍加擴展就可以實現(xiàn)一些比較常用的功能,比如可以在上傳完畢后可以顯示一個簡單的結果:
$('#fileupload').fileupload({ done: function (e, data) { $.each(data.result, function (index, file) { $('<p/>').text(file.name + ' uploaded').appendTo($("body")); }); }});
或者顯示上傳進度,配合一些進度條組件就可以構成一個上傳進度條
$('#fileupload').fileupload('option', { progressall: function (e, data) { var progress = parseInt(data.loaded / data.total * 100, 10); console.log(progress + '%'); }});
等等。只要多閱讀手冊就可以配合項目做更具體的擴展開發(fā)。
這里需要特別注意的是,由于jQuery File Upload都是采用XHR在傳遞數(shù)據(jù),服務器端返回的通常是JSON格式的響應,但是IE會將這些JSON響應誤認為是文件傳輸,然后直接彈出下載框詢問是否需要下載。
解決這個問題的方法是必須將相應的Http Head從
Content-Type: application/json
更改為
Content-Type: text/plain
具體的實現(xiàn)根據(jù)服務端不同有所區(qū)別,比如ZF2中可以在Controller中這樣寫:
$this->getServiceLocator()->get('Application')->getEventManager()->attach(\Zend\Mvc\MvcEvent::EVENT_RENDER, function($event){ $event->getResponse()->getHeaders()->addHeaderLine('Content-Type', 'text/plain'); }, -10000);
這也是我在stackoverflow上的對ZF2更改最終響應類型的一個回答
為了引入更多功能,jQuery File Upload在上面最簡模型的基礎上又實現(xiàn)了一套jQuery File Upload UI,也就是官方給出的最終Demo,這套UI額外提供了以下功能:
等等,同時還增加了一系列新的接口和事件,具體都可以查閱官方手冊。
具體對應到文件為:
也許正是因為附加功能太多,各功能之間耦合非常重,jQuery File Upload UI顯得不夠友好,主要體現(xiàn)在:
所以經(jīng)驗之談是,在定制jQuery File Upload UI時,如果UI無法工作。首先檢查js文件是否全部加載,然后檢查頁面元素是否齊全,再次檢查JS模板標簽是否嚴格配對,最后還可以查看頁面是否有重復調(diào)用fileupload()方法。
UI的部件都是硬編碼的HTML class,無法更改。核心的幾個部件為
<div class="fileupload-buttonbar"> <span class="fileinput-button"><input type="file" name="files[]" multiple></span> <button type="submit" class="start">Start upload</button> <button type="reset" class="cancel">Cancel upload</button> <button type="button" class="delete">Delete</button> <input type="checkbox" class="toggle"> </div>
最外層容器為.fileupload-buttonbar,內(nèi)部包含
<div class="fileupload-progress"> <div class="progress"> <div class="bar" style="width:0%;"></div> </div> <div class="progress-extended"></div></div>
最外層容器為.fileupload-progress,內(nèi)部包含
<div class="files"></div>
.file容器是最重要的UI部件,上傳時的文件預覽模板以及上傳完畢后的文件顯示模板都將顯示在這里。
<script id="template-upload" type="text/x-tmpl">{% for (var i=0, file; file=o.files[i]; i++) { %}<div class="template-upload"> {% if (file.error) { %} <div class="error">{%=file.error%}</div> {% } else { %} <div class="preview"><span class="fade"></span></div> <div class="name"><span>{%=file.name%}</span></div> <div class="size"><span>{%=o.formatFileSize(file.size)%}</span></div> <div class="progress progress-success progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0" style="height:5px;"><div class="bar" style="width:0%;"></div></div> <span class="start"> {% if (!o.options.autoUpload) { %} <button>Start Upload</button> {% } %} </span> {% } %} <span class="cancel"><button>Cancel</button></span></div>{% } %}</script>
這部分邏輯不難讀懂,由于文件選擇是多選的,所以被選擇文件一開始以數(shù)組方式存放,循環(huán)輸出。即使我們加入最大文件只能上傳一個,這里得到的仍然是數(shù)組形式。
當文件有任何錯誤時,如文件類型被禁止,文件大小不符合約定,會得到file.error。文件檢測沒有問題,則可以用以下元素控制當前文件:
<script id="template-download" type="text/x-tmpl">{% for (var i=0, file; file=o.files[i]; i++) { %}<div class="template-download"> {% if (file.error) { %} <div class="error">{%=file.error%}</div> <span class="cancel"><button class="btn btn-block"><i class="icon-ban-circle"></i>Cancel</span> {% } else { %} <div class="preview"><img src="{%=file.thumbnail_url%}"></div> <div class="name"><span>{%=file.name%}</span></div> <div class="size"><span>{%=o.formatFileSize(file.size)%}</span></div> <div class="delete"><button data-type="{%=file.delete_type%}" data-url="{%=file.delete_url%}">Delete</button> </div> {% } %}</div>{% } %}</script>
這一部分的o.files完全來自服務器端的json響應,所以模板內(nèi)容可以自由發(fā)揮。唯一被定制的元素為刪除按鈕.delete。 點擊這個按鈕會向按鈕中指定的url發(fā)送請求,比如
<div class="delete"><button data-type="DELETE" data-url="/file/1">Delete</button></div>
點擊后則會用DELETE方式發(fā)送HTTP請求
DELETE /file/1
有了上面羅列的UI元素,就可以拼湊出一個簡單的jQuery File Upload UI工作流程:
有了上面的基礎,要個性化的定制jQuery File Upload就簡單了很多:
由于沒有使用Flash空間,上傳的文件選擇框是無法限制文件類型的,所以所謂的限制文件類型,只能讓用戶選擇文件之后,用file.error顯示一個錯誤信息。例如本次需要限定可上傳的文件為圖片,那么Options指定:
acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i
即可。
在Google Chrome瀏覽器中,可以用input:file原生支持文件類型限定,可以配合使用:
<input type="file" name="upload[]" accept="image/png, image/gif, image/jpg, image/jpeg">
不過在客戶端做再多的限定也只是提升用戶體驗,不能真正保證安全性,所以不要忘記了在服務器端做同樣的類型檢測。
只需在Options指定
maxNumberOfFiles : 1
即可。jQuery File Upload UI的處理方式是當用戶上傳一個文件后,文件選擇按鈕被置為Disabled。
這同樣只是客戶端的小把戲,真正想要嚴格的約束用戶只能上傳一個文件還是需要在服務器端通過Session做更加復雜的控制。
Options中指定
maxFileSize: 5000000
即只允許單文件最大5MB。
在Firefox環(huán)境下測試是,發(fā)現(xiàn)如果將文件數(shù)量限制為1,選擇一次文件,刷新頁面之后文件選擇按鈕會莫名其妙的被加上一個Disabled屬性,導致無法點擊。所以最終我們的初始化代碼為:
var uploader = $("#fileupload");uploader.fileupload({ dataType: 'json', autoUpload: false, acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i, maxNumberOfFiles : 1, maxFileSize: 5000000 });uploader.find("input:file").removeAttr('disabled');
最后就是界面的一些調(diào)整,完整代碼在EvaEngine的File模塊下,點擊查看.
Tags : jQuery 上傳 jQuery File Upload 插件
Follow :
Donate:Buy me a coffee | 文章有幫助,可以請我喝杯咖啡