jQuery File Upload是一個(gè)非常優(yōu)秀的上傳組件,主要使用了XHR作為上傳方式,并且利用了相當(dāng)多的現(xiàn)代瀏覽器功能,所以可以實(shí)現(xiàn)諸如批量上傳、超大文件上傳、圖片預(yù)覽、拖拽上傳、上傳進(jìn)度顯示、跨域上傳等功能。
美中不足的是jQuery File Upload的默認(rèn)UI比較復(fù)雜,集成了全部功能,讓jQuery File Upload的定制變得比較繁瑣。
嘗試用jQuery File Upload制作了一個(gè)類似微博圖片上傳的單文件式上傳Demo,將一些要點(diǎn)記錄下來備忘。最終效果如下圖:
jQuery File Upload包含了一堆文件,首先需要弄清楚的是最核心的部分是哪些,根據(jù)官方的例子可以知道,一個(gè)最簡(jiǎn)單的jQuery File Upload上傳組件,必須包括以下文件:
此時(shí)只需要加載一個(gè)上傳按鈕
<input id="fileupload" type="file" name="files[]" data-url="server/php/" multiple>
以及一行代碼
$('#fileupload').fileupload();
就完成了一個(gè)最基本的上傳組件。這個(gè)最簡(jiǎn)單的上傳組件可以將選中的文件以表單形式提交到data-url約定的URL,同時(shí)提供了足夠多的設(shè)置和基礎(chǔ)事件可供擴(kuò)展。
對(duì)于最簡(jiǎn)模型,稍加擴(kuò)展就可以實(shí)現(xiàn)一些比較常用的功能,比如可以在上傳完畢后可以顯示一個(gè)簡(jiǎn)單的結(jié)果:
$('#fileupload').fileupload({ done: function (e, data) { $.each(data.result, function (index, file) { $('<p/>').text(file.name + ' uploaded').appendTo($("body")); }); }});
或者顯示上傳進(jìn)度,配合一些進(jìn)度條組件就可以構(gòu)成一個(gè)上傳進(jìn)度條
$('#fileupload').fileupload('option', { progressall: function (e, data) { var progress = parseInt(data.loaded / data.total * 100, 10); console.log(progress + '%'); }});
等等。只要多閱讀手冊(cè)就可以配合項(xiàng)目做更具體的擴(kuò)展開發(fā)。
這里需要特別注意的是,由于jQuery File Upload都是采用XHR在傳遞數(shù)據(jù),服務(wù)器端返回的通常是JSON格式的響應(yīng),但是IE會(huì)將這些JSON響應(yīng)誤認(rèn)為是文件傳輸,然后直接彈出下載框詢問是否需要下載。
解決這個(gè)問題的方法是必須將相應(yīng)的Http Head從
Content-Type: application/json
更改為
Content-Type: text/plain
具體的實(shí)現(xiàn)根據(jù)服務(wù)端不同有所區(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上的對(duì)ZF2更改最終響應(yīng)類型的一個(gè)回答
為了引入更多功能,jQuery File Upload在上面最簡(jiǎn)模型的基礎(chǔ)上又實(shí)現(xiàn)了一套jQuery File Upload UI,也就是官方給出的最終Demo,這套UI額外提供了以下功能:
等等,同時(shí)還增加了一系列新的接口和事件,具體都可以查閱官方手冊(cè)。
具體對(duì)應(yīng)到文件為:
也許正是因?yàn)楦郊庸δ芴?,各功能之間耦合非常重,jQuery File Upload UI顯得不夠友好,主要體現(xiàn)在:
所以經(jīng)驗(yàn)之談是,在定制jQuery File Upload UI時(shí),如果UI無法工作。首先檢查js文件是否全部加載,然后檢查頁面元素是否齊全,再次檢查JS模板標(biāo)簽是否嚴(yán)格配對(duì),最后還可以查看頁面是否有重復(fù)調(diào)用fileupload()方法。
UI的部件都是硬編碼的HTML class,無法更改。核心的幾個(gè)部件為
<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部件,上傳時(shí)的文件預(yù)覽模板以及上傳完畢后的文件顯示模板都將顯示在這里。
<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)輸出。即使我們加入最大文件只能上傳一個(gè),這里得到的仍然是數(shù)組形式。
當(dāng)文件有任何錯(cuò)誤時(shí),如文件類型被禁止,文件大小不符合約定,會(huì)得到file.error。文件檢測(cè)沒有問題,則可以用以下元素控制當(dāng)前文件:
<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完全來自服務(wù)器端的json響應(yīng),所以模板內(nèi)容可以自由發(fā)揮。唯一被定制的元素為刪除按鈕.delete。 點(diǎn)擊這個(gè)按鈕會(huì)向按鈕中指定的url發(fā)送請(qǐng)求,比如
<div class="delete"><button data-type="DELETE" data-url="/file/1">Delete</button></div>
點(diǎn)擊后則會(huì)用DELETE方式發(fā)送HTTP請(qǐng)求
DELETE /file/1
有了上面羅列的UI元素,就可以拼湊出一個(gè)簡(jiǎn)單的jQuery File Upload UI工作流程:
有了上面的基礎(chǔ),要個(gè)性化的定制jQuery File Upload就簡(jiǎn)單了很多:
由于沒有使用Flash空間,上傳的文件選擇框是無法限制文件類型的,所以所謂的限制文件類型,只能讓用戶選擇文件之后,用file.error顯示一個(gè)錯(cuò)誤信息。例如本次需要限定可上傳的文件為圖片,那么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">
不過在客戶端做再多的限定也只是提升用戶體驗(yàn),不能真正保證安全性,所以不要忘記了在服務(wù)器端做同樣的類型檢測(cè)。
只需在Options指定
maxNumberOfFiles : 1
即可。jQuery File Upload UI的處理方式是當(dāng)用戶上傳一個(gè)文件后,文件選擇按鈕被置為Disabled。
這同樣只是客戶端的小把戲,真正想要嚴(yán)格的約束用戶只能上傳一個(gè)文件還是需要在服務(wù)器端通過Session做更加復(fù)雜的控制。
Options中指定
maxFileSize: 5000000
即只允許單文件最大5MB。
在Firefox環(huán)境下測(cè)試是,發(fā)現(xiàn)如果將文件數(shù)量限制為1,選擇一次文件,刷新頁面之后文件選擇按鈕會(huì)莫名其妙的被加上一個(gè)Disabled屬性,導(dǎo)致無法點(diǎn)擊。所以最終我們的初始化代碼為:
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模塊下,點(diǎn)擊查看.
Tags : jQuery 上傳 jQuery File Upload 插件
Follow :
Donate:Buy me a coffee | 文章有幫助,可以請(qǐng)我喝杯咖啡
聯(lián)系客服