一、 簡單說明
Ajax+Flash多文件上傳是一個開源的上傳組件,名稱是FancyUpload,其官方網址是:http://digitarald.de/project/fancyupload/。這個組件僅僅是客戶端的應用組件,即與任何服務器端的技術沒有關系,服務器端可以采用任何后臺技術(如JSP、Servlet、ASP等)。應用該組件提供給我們的最大的好處有如下幾點(個人認為,呵呵):
n 可以同時選擇多個文件進行上傳;
n 以隊列的形式排列要上傳的文件和其相關信息(如名稱、大小等)(美觀^_^);
n 可以設置要上傳的文件個數、文件類型和文件大小(實用^_^);
n 有上傳進度顯示(感覺這個非常直觀,很方便實用);
n 上傳的過程中可以隨時取消要上傳的文件;
n 平臺獨立性,由于使用flash和成熟的AJAX框架(mootools)可以避免對特定瀏覽器和服務器依賴!
n 使用簡單,文件體積小!(這個才是最實在的,呵呵)
n 表單無須設置enctype="multipart/form-data"了(這個有點意思吧)
二、 應用部署
文件夾fancyupload中的文件就是該組件所需要到的所有文件了,包括四個JS、二個圖片、一個swf文件,另外還包含一個簡單的測試html頁面,其文件結構如下:

將整個文件夾copy到你的web應用目錄即可,使用的時候其步驟和代碼如下:
Ø 引入JS文件
在頁面上依次引入mootools-release-1.11.js、Swiff.Base.js、Swiff.Uploader.js、FancyUpload.js這四個JS,具體目錄請依據自己的情況進行設置!
Ø 在頁面上設置CSS樣式(主要是文件列表和上傳進度的樣式)
在head之間嵌入mytest.html中的css代碼!
Ø 在onload方法中調用如下代碼:
var upload = new FancyUpload(
$(“fileId”),
{
swf: 'Swiff.Uploader.swf'
}
);
我們只要這一行代碼就可以工作了,不過我們可以通過像設置swf一樣來設置多個參數來控制我們的上傳,比如是否使用隊列,控制文件大小等。相關的參數意義如下:
fileId 就是我們頁面上文件域的ID,即type為file的input元素的ID;
{} 這樣包起來的參數就是我們的可選參數了,可參考FancyUpload.js中的說明。
Ø 在頁面上設置類似mytest.html中的body區域的代碼即可!
來看一個文件上傳的實際效果,如下圖:

三、 FancyUpload的參數說明
u url
文件上傳的地址,如果不指定,那么將會自動取文件域所在的表單的action值來進行上傳。如果表單的action也沒有指定值,那么將嘗試獲取路徑欄中的地址來進行文件上傳。一般而言我們都需要指定該參數和文件域所在的表單的action兩者之一!
u swf
就是組件中的flash文件了,主要是用來選擇文件和過濾等,基本上可以不用設置。
u multiple
是否允許選擇多個文件,默認是true。這個多選是指在打開的文件對話框中按住ctr鍵進行多文件的選中。
u queued
是否允許隊列上傳,默認是true。
u types
指定上傳文件的類型,采用的格式是 {提示信息:文件類型},如只允許媒體文件上傳的例子:{“媒體文件(*.rm,*.avi)” : “*.rm; *.avi”}
u limitSize
指定限制的文件大小,單位是字節!默認是不限制,超過此值的文件將不被選中,注意即使選擇后系統也沒有提示,但是隊列中也是沒有該文件的!可以通過修改文件FancyUpload.js,在其128行的if語句中加上一個alert提示即可!
u limitFiles
限制的文件個數,默認是不限制!
u createReplacement
一個自定義函數(參數為文件域對象),用來替換文件域,默認是被替換成為一個按鈕!具體的代碼可以參考FancyUpload.js中的第101到111行的代碼。默認我已經將其按鈕的值改成了中文的“瀏覽文件”。
u instantStart
表示選擇文件后是否立即開始上傳,默認是false!也建議不要設置為true,上傳的操作我們可以交給該文件域所在表單的提交按鈕,這也是自動綁定的,無須我們做任何操作。
u allowDuplicates
是否允許隊列中選擇重復的文件,默認是false!注釋中是true,而代碼中是false,所以以代碼中的為準。
u container
flash文件的容器對象,默認是document.body,可以不用修改!
u optionFxDuration
文件添加到隊列后,其高亮度到消失高亮度的時間,默認是250ms!也就是漸逝的時間長度。
u queueList
來列表顯示文件隊列的容器對象或其ID。
u onComplete
單個文件上傳成功后調用的方法,非AJAX,無回調參數。每個文件上傳成功后都將調用該方法一次!
u onAllComplete
所有文件上傳成功后的調用方法!
四、 表單文件域和參數同時上傳實戰
在你自己試過這個上傳組件后,是不是感覺非常好用的,但同時你也或許發現了一個問題,那就是表單中的參數怎么進行上傳的問題。因為該組件是采用FLASH+AJAX進行上傳的,即頁面是不刷新的,而且上傳的過程中僅僅是上傳了你選擇的文件,而所有的表單非文件域參數則被忽略了。那我們如何來進行文件和參數的同步上傳呢,這里有幾個問題要注意的就是:
1) 由于該組件是綁定了表單的submit方法,所以不能夠直接在js中使用$(‘表單ID’).submit()這樣的方式來進行表單上傳,否則參數是傳上去了而文件則沒有;
2) 如果沒有做設置那么只要選擇了文件而且觸發了表單的submit事件,那么該組件就會開始上傳文件,即使我們加了onsubmit方法中的return false也無效;
3) 在第二條的基礎上我們如何保證用戶既選擇了文件而且又輸入了表單的所有必填參數呢?
這些問題在經過本人一天的實際摸索后,終于得到了解決,呵呵,現說明如下:
1) 首先是上傳前的參數檢查
這包括表單中的必填參數和文件的選擇與否的判斷。既然我們無法通過直接點擊submit按鈕進行提交前檢查,那么我們就用一個普通的按鈕,設置一個onclick事件,通過這個事件來進行參數的檢查。這個即可避免選擇了文件但又沒有輸入參數的誤提交,又檢查了整個數據的完整性,其代碼如下:
<input type=”button” value=”提交” onclikc=”checkSubmit()” />
在checkSubmit方法中我們可以通過調用對象FancyUpload的fileList屬性來判斷用戶是否選擇了文件,其代碼如下(假設你的FancyUpload對象的實例名稱是uploader):
if (uploader. fileList.length < 1) {
alert(‘請選擇要上傳的文件!’);
}
通過判斷這個屬性(類型為數組)的長度來查看用戶是否選擇了文件,具體的個數就需要用戶自己進行判斷了,我這里是一個文件。
2) 表單提交
參數檢查完整后我們就可以開始上傳文件和表單參數了,這里我們的文件和表單參數是無法一起提交的,我們只能分先文件上傳,上傳成功后再提交我們的表單參數。
第一步是文件的上傳,之前也已經提過了不能夠直接在JS中進行表單的submit,否則就無法上傳文件了,這里我們采用一個迂回的辦法,在表單中隱藏一個提交按鈕,代碼如下:
<input type=”submit” id=”mysubmit” style=”display:none” />
然后我們再在checkSubmit函數的最后加上如下代碼:
……
$(“mysubmit”).submit();
……
這樣,我們通過一個隱藏提交按鈕來觸發表單的submit事件,這樣我們就可以順利的進行文件上傳了。
第二步,在文件上傳成功后,我們再進行參數的提交,文件上傳成功的觸發函數我們在FancyUpload對象的onComplete上進行定義,不過對于多文件上傳的就要定義在onAllComplete上了,我建議全部定義在onAllComplete上,如下:
onAllComplete:function() {
$(“你的表單的Id”).submit();
}
在這里我們就可以直接調用表單的submit來提交參數了,當然了你也可以采用AJAX提交,那就要看自己的需求了。
3) 上傳文件的路徑和表單參數的綁定
由于我們的文件上傳和表單參數上傳是分成兩個部分進行上傳的,這就出現了如何將兩次上傳的參數進行綁定的問題。而且查看官方上的評論,作者也沒有給出解決方法,而且該組件只能檢測錯誤時的狀態碼(00 < status < 300),對于上傳成功是無法獲取任何返回信息的。目前我的解決方法就是:
1. 文件上傳成功后將路徑信息存儲以原始文件名為key存儲在session中;
2. 參數進行上傳時根據原始文件的名稱去從session中獲取上傳的路徑信息
通過這二步基本上就可以綁定兩次上傳的參數了!如果有更好的方法大家也可以一起探討。
所以通過以上三個步驟后我們就可以實現文件的無刷新上傳和進度顯示了!^_^另外這個分步進行上傳是相對表單參數比較多的情況,如果參數比較少的話可以直接將參數附加在URL地址后面進行也是可以的,這就要靠個人的發揮了。