糜梅 熊棠
關鍵詞:Javascript;HTML5;FormData;AJAX;異步;文件上傳類
中圖分類號:TP393 文獻標識碼:A 文章編號:1009-3044(2015)02-0072-03
2005年,Google在搜索web界面中推出了Google Suggest。Google Suggest使用AJAX創(chuàng)造出動態(tài)性極強的web界面:當您在谷歌的搜索框輸入關鍵字時,JavaScript會把這些字符發(fā)送到服務器,然后服務器會返回一個搜索建議的列表。[1]其后,隨著Google Reader、Google Map、Gmail等一大批產品的流行,AJAX這種與服務器交換數據并更新部分網頁的藝術迅速的流行起來。但是,AJAX一直沒有實現對文件對象的異步上傳,直到HTML5的出現。
1 FormData對象
在HTML5標準中,XMLHttpRequest Level 2添加了一個新的接口FormData。利用FormData對象,我們可以通過JavaScript用一些鍵值對來模擬一系列表單控件,我們還可以使用XMLHttpRequest的send()方法來異步的提交這個“表單”。比起普通的AJAX,使用FormData的最大優(yōu)點就是我們可以異步上傳一個二進制文件。[2]
1.1 構造
使用new方法構造一個FormData實例:
var form = new FormData([formElement]);
參數formElement為可選,可以包含任何形式的表單控件,如一個文本框,或是一個表單對象。
1.2 append方法
使用append方法可以給當前FormData對象實例添加一個鍵/值對:
form.append(name,value,[filename]);
name表示一個字段名稱,value表示一個字段值。value可以是一個字符串,或者一個二進制大對象或文件;如果給出的數據是其它類型比如整數型,會被自動轉換成字符串型[3]。當value為一個二進制大對象或文件時,可選參數filename將以字符串的形式發(fā)送給服務器。
1.3 delete方法
使用delete方法可以刪除當前FormData對象實例的一個鍵/值對:
form.delete(name);
1.4 get方法
使用get方法可以讀取當前FormData對象實例對應鍵的值:
var value = form.get(name);
此外,還有以數組形式返回所有鍵/值對的getAll方法,檢查否是含有某鍵的has方法,和更新已有鍵/值對的set方法。delete、get、getAll、has、set方法僅支持Chrome、Opera瀏覽器的部分版本[4]。
2 表單
HTML5的文件API有一個FileList接口,可以通過e.dataTransfer.files拖拽事件傳遞的文件信息獲得本地文件列表,因此理論上可以使用任何DOM替代文本域作為拖拽區(qū)域。為了兼容不支持HTML5的瀏覽器,仍然需要使用文本域來訪問本地文件系統(tǒng)。
utf8和authenticity_token字段由框架自動生成,用來防止外部提交。file[file][]字段為文件域,支持多文件,文件列表為數組形式;文本域的樣式設置為同外部DIV同寬同高,且不透明度為0。圖1中FILE圖案的位置對應為文本域的瀏覽按鈕,點擊可打開文件選擇對話框。
work方法以this.FileField文本域為起點查找父節(jié)點,通過迭代方式最終獲得表單對象。將表單對象所屬控件按鍵/值對的形式存入this.data以便于多次提交。this.uploader一般情況下應等于表單的動作,也可以通過對實例屬性賦值進行重設。在上傳開始前設置文本域為不可見以防止在多個大文件上傳的過程中用戶再次操作文本域造成錯誤。如果頁面上沒有進度條,則將主動創(chuàng)建的進度條置于文件域的位置,如圖4所示,這樣不會因為新頁面元素的加入造成頁面變形。up方法以異步方式上傳數據,需用到FormData對象;IE6等不支持HTML5的瀏覽器會運行錯誤,因此使用try{}catch(e){}方法進行錯誤控制,使IE6等瀏覽器運行同步提交表單動作,即form.submit()。
work方法的參數有3個,succFunc、errFunc和doneFunc。succFunc是單個文件上傳成功后調用的方法,errFunc是出現異常時調用的方法,doneFunc是所有文件上傳完成后調用的方法。這3個方法都將作為參數傳遞給up方法。調用方法為:
up(succFunc,errFunc,doneFunc,this.FileField,this.count,up,this.extension,this.data,this.uploader,this.progressBar,this.tip);
3.2.2 up方法
up方法執(zhí)行一個異步上傳任務,包括提交表單,上傳文件,顯示進度及信息,按照上傳結果及計數器決定調用方法等。
當文件域的multiple屬性值為“multiple”時,文件列表以數組形式存在,訪問方法為var fileObj=this.FileField.files[file_index]。fileObj為當前文件對象,file_index為計數器的當前值。fileObj.name為當前文件對象的文件名,使用正則表達式/[^\.]+$/可以得到文件的后綴名ext。將ext與this.extension比較就可以知道當前文件的類型是否合法。當然,前端限制總是可以繞過的,只能作為一種用戶體驗優(yōu)化手段;必須在后端對文件類型的合法性進行嚴格的檢驗。如果文件非法,啟動異常處理程序,否則創(chuàng)建FormData實例form,并使用form.append方法將this.data中的數據添加到form中,添加時需要區(qū)分this.data中的數據是數組類型還是對象:
同樣的方法將當前文件對象也添加進form,form.append(this.filefield.name,fileObj)。創(chuàng)建XMLHttpRequest實例carrier并上傳form對象的方法與一般的AJAX處理過程相同,不再贅述。Carrier的upload事件觸發(fā)添加事件監(jiān)聽,事件類型為"progress",事件處理方法為progressFunction。Carrier上傳結束后計數器加1。異步上傳網絡異常時啟動異常處理程序,否則調用succFunc處理服務器返回結果;如果服務器返回的數據表明上傳不成功,則啟動異常處理程序,否則比較計數器與文件域中文件列表數;如果計數器小于文件數,則迭代調用up方法;如果計數器等于于文件數,則表明文件上傳完畢,調用doneFunc方法。
up方法的參數有succFunc,errFunc,doneFunc,filefield,file_index,next_func,extension,data,uploader,progressBar和tip。next_func為檢測到還有文件未上傳時執(zhí)行的方法,即up方法本身。其余參數文中已有說明。這些參數在迭代時將傳遞給next_func作為參數。
3.2.3 progressFunction方法
4 異常處理
異常處理方法不屬于drawUp類的方法,根據實際需要另外定義,作為參數傳遞給drawUp類的對象方法work。定義方法error為出現異常時的調用方法。error需要完成兩個工作:1、根據實際需要完成對錯誤的處理;2、決定是否進入下一次上傳。此處省略處理錯誤的代碼,修改第2節(jié)的HTML5Uploader()腳本為:
error的參數result是XMLHttpRequest實例carrier的運行狀態(tài)carrier.status或返回結果carrier.responseText。error對這個值進行類型分析或文本分析,然后執(zhí)行具體的錯誤處理流程,此處不再贅述。
5 結束語
本文構建的文件上傳類能夠在支持HTML5的瀏覽器中實現拖拽多個文件、識別文件類型、異步上傳文件、顯示上傳進度、上傳后處理等功能;對于不兼容HTML5的瀏覽器能夠實現傳統(tǒng)的同步方式上傳,實現了設計目標。
參考文獻:
[1] W3School. AJAX 簡介[EB/OL]. [2015-05-22]. http://www.w3school.com.cn/ajax/ajax_intro.asp.
[2] ziyunfei TooBug teoli. FormData[EB/OL].(2015-02)[2015-05-22].https://developer.mozilla.org/zh-CN/docs/Web/API/FormData.
[4] Grissess cpigat cgack kscarfone Jeremie premjoy saneyuki_s Kabe Sicking ernestd mkato Sheppy ziyunfei evilpie teoli Yanmorin mattflaschen ethertank chrisdavidmills Callahad leachlife4 philoyche. FormData [EB/OL].(2015-04)[2015-05-22]. https://developer.mozilla.org/en-US/docs/Web/API/FormData.