長期以來,開發者們一直為此苦惱,大部分為解決這個問題都採用了flash作為解決方案,但flash並非靈丹妙藥,因為flash版本,割據造成的問題有時反倒成為了噩夢。有些網站則採用了form標籤的enctype=multipart/form-data屬性,但這一屬性要求服務器作出特殊的設置才能夠顯示進度,而且本身也比較複雜,複雜就意味著容易出現錯誤,這可不是我們想要的。
現在我們來看看Html5為什麼能夠解決這個問題,以及,它到底能做的多好。
用HTML5上傳文件在HTML5標準中,XMLHttpRequest對像被重新定義,被稱為XMLHttpRequest Level 2,其中包含了以下5個新特性:
1、支持上傳、下載字節流,比如文件、blob以及表單數據
2、增加了上傳、下載中的進度事件
3、跨域請求的支持
4、允許發送匿名請求(即不發送HTTP的Referer部分)
5、允許設置請求的超時
在這篇教程中,我們主要關注第一和第二項特性,尤其是第二項-它能夠提供我們想要的上傳進度。和之前的方案不同,這個方案並不要求服務器作出特殊的設置,因此大家邊看教程就可以邊動手試試了。
上面圖示的就是我們能夠實現的內容:
1、顯示上傳的文件信息,比如文件名、類型、尺寸
2、一個能夠顯示真實進度的進度條
3、上傳的速度
4、剩餘時間的估算
5、已上傳的數據量
6、上傳結束後服務器返回的響應
另外,憑藉XMLHttpRequest,我們的上傳過程整個都是異步的,因此用戶在上傳文件的時候,依然可以操作網頁當中的其它元素,並不需要專門等待上傳的完成。而在上傳結束後,我們能夠獲取服務器發回的響應,因此整個上傳過程都顯得相當順理成章。
HTML5的進度事件HTML5當中新增了一個進度事件(Progress Events),這個事件為我們提供了以下信息:
1、total – 文件大小
2、loaded – 已上傳的大小
3、lengthComputable – 進度是否可計算
信息並不多,但是在計算文件進度上已經足夠了。當然,也還有很多東西它沒有直接給出,這非常遺憾。
HTML與普通的文件上傳代碼並沒有太大差異。不過注意,input標籤關聯了一個JavaScript函數在onchange上。
<!DOCTYPE html><html><head> <title>使用XMLHttpRequest上傳文件</title></head><body><form id=form1 enctype=multipart/form-data method=post action=upload.php> <div class=row> <label for=fileToUpload>Select a File to Upload</label><input type=file name=fileToUpload id=fileToUpload onchange=fileSelected();/> </div><div id=fileName> </div><div id=fileSize></div><div id=fileType></div><div class=row><input type=button onclick=uploadFile() value=Upload /> </div>< div id=progressNumber></div></form></body></html>JavaScript
一旦我們在HTML中使用了input,我們就可以在JS代碼中獲取到一個FileList對象。這個對像是HTML5中新增加的文件API中的一部分,每一個FileList對像都是一組文件對象的集合,而文件對象則擁有下列的屬性:
1、name – 文件名(不包含路徑)
2、type – 文件的MIME類型(小寫)
3、size – 文件的尺寸(單位為字節)
這正是我們所需要的。當然,HTML5中還有一個FileReader對象,但在這裡我們並沒有用它。現在,通過上面的三個內容,我們已經能夠控制用戶上傳的文件大小和文件類型,以便減輕服務器再次檢測時的壓力,並提升安全係數。
function fileSelected() { var file = document.getElementById('fileToUpload').files[0]; if (file) { var fileSize = 0; if (file.size > 1024 * 1024) fileSize = (Math.round(file .size * 100 / (1024 * 1024)) / 100).toString() + 'MB'; else fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + 'KB' ; document.getElementById('fileName').innerHTML = 'Name: ' + file.name; document.getElementById('fileSize').innerHTML = 'Size: ' + fileSize; document.getElementById('fileType').innerHTML = 'Type: ' + file.type; }}
那麼當用戶選擇好文件,點擊上傳之後,又將發生什麼呢?
function uploadFile() { var xhr = new XMLHttpRequest(); var fd = document.getElementById('form1').getFormData(); /* event listners */ xhr.upload.addEventListener(progress, uploadProgress, false); xhr. addEventListener(load, uploadComplete, false); xhr.addEventListener(error, uploadFailed, false); xhr.addEventListener(abort, uploadCanceled, false); /* Be sure to change the url below to the url of your upload server side script * / xhr.open(POST, upload.php); xhr.send(fd);}function uploadProgress(evt) { if (evt.lengthComputable) { var percentComplete = Math.round(evt.loaded * 100 / evt.total) ; document.getElementById('progressNumber').innerHTML = percentComplete.toString() + '%'; } else { document.getElementById('progressNumber').innerHTML = 'unable to compute'; }}function uploadComplete(evt) { /* This event is raised when the server send back a response */ alert(evt.target.responseText);}function uploadFailed(evt) { alert(There was an error attempting to upload the file.);}function uploadCanceled(evt ) { alert(The upload has been canceled by the user or the browser dropped the connection.);}
在代碼的第二行中,我們的JS代碼又使用了另一個HTML5推出的新對象-FormData。 FormData對像是用戶的表單數據的集合,它以鍵值對的形式存儲了表單數據,其值能夠包括數字、字符串以及文件。我們通過輾轉這個對象,來向服務器提交數據。
當然,這個對像我們也可以在代碼中手工構建,比如說像下面這樣:
var fd = new FormData();fd.append(author, Shiv Kumar);fd.append(name, Html 5 File API/FormData);fd.append(fileToUpload, document.getElementById('fileToUpload').files[0 ]);
回到正題。回顧上一段代碼,我們增加了許多有關XMLHttpRequest的事件監聽,其目的是為了獲取文件上傳的真實情況。尤其需要注意的是,我們所掛鉤的,並不是XMLHttpRequest本身,而是其屬性,比如uploadProgress。
完整代碼最後,來看看完整的代碼。
<!DOCTYPE html><html><head> <title>Upload Files using XMLHttpRequest - Minimal</title> <script type=text/javascript> function fileSelected() { var file = document.getElementById('fileToUpload').files [0]; if (file) { var fileSize = 0; if (file.size > 1024 * 1024) fileSize = (Math.round(file.size * 100 / (1024 * 1024)) / 100).toString() + 'MB'; else fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + 'KB'; document.getElementById('fileName').innerHTML = 'Name: ' + file .name; document.getElementById('fileSize').innerHTML = 'Size: ' + fileSize; document.getElementById('fileType').innerHTML = 'Type: ' + file.type; } } function uploadFile() { var fd = new FormData(); fd.append(fileToUpload, document.getElementById('fileToUpload').files[0]); var xhr = new XMLHttpRequest(); xhr.upload.addEventListener(progress, uploadProgress, false); xhr. addEventListener(load, uploadComplete, false); xhr.addEventListener(error, uploadFailed, false); xhr.addEventListener(abort, uploadCanceled, false); xhr.open(POST, UploadMinimal.aspx); xhr.send(fd); } function uploadProgress(evt) { if (evt.lengthComputable) { var percentComplete = Math.round(evt.loaded * 100 / evt.total); document.getElementById('progressNumber').innerHTML = percentComplete.toString() + '% '; } else { document.getElementById('progressNumber').innerHTML = 'unable to compute'; } } function uploadComplete(evt) { /* This event is raised when the server send back a response */ alert(evt.target .responseText); } function uploadFailed(evt) { alert(There was an error attempting to upload the file.); } function uploadCanceled(evt) { alert(The upload has been canceled by the user or the browser dropped the connection.) ; } </script></head><body><form id=form1 enctype=multipart/form-data method=post action=upload.php><div class=row> <label for=fileToUpload>Select a File to Upload</label><input type=file name=fileToUpload id=fileToUpload onchange=fileSelected();/> </div><div id=fileName></div><div id=fileSize></div><div id=fileType></div><div class=row><input type=button onclick=uploadFile() value=Upload /> </div><div id=progressNumber></div></form></body ></html>
我們的任務完成了嗎?可以說完成了,因為這段代碼已經能夠完成上傳文件的任務,而且也能夠顯示上傳的進度;但是理應說我們沒有,因為除了這個骨架HTML之外,我們還有很多沒有做的事情,比如CSS的美化等等。不過這就不是我們這篇文章的主題了。
最後,提醒一下,教程的代碼應當在支持新特性的瀏覽器之上運行,如果你不清楚自己的瀏覽器是否支持,可以在這裡查詢。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。