本文爲轉載學習javascript
原文做者:阮一峯php
原文連接:http://www.ruanyifeng.com/blog/2012/08/file_upload.htmlcss
HTML5提供了一系列新的瀏覽器API,使得文件上傳有可能出現革命性變化。英國程序員Remy Sharp總結了這些新的接口,本文在他的文章基礎上,討論如何採用HTML5的API,對文件上傳進行漸進式加強,實現如下功能:html
* iframe上傳java
* ajax上傳程序員
* 進度條ajax
* 文件預覽瀏覽器
* 拖放上傳服務器
爲了對這些功能有一個感性認識,你能夠先看看Remy Sharp提供的範例。app
雖然這些API,尚未獲得普遍部署,但它們是將來的潮流。有了它們,代碼就能夠寫得很是優雅簡潔,上面五個功能都能在20行之內實現。
1、傳統形式
讓咱們從最基本的開始。
文件上傳的傳統形式,是使用表單元素file:
<form id="upload-form" action="upload.php" method="post" enctype="multipart/form-data" > <input type="file" id="upload" name="upload" /> <br /> <input type="submit" value="Upload" /> </form>
全部瀏覽器都支持上面的代碼。它在IE瀏覽器中,顯示以下:
用戶先選擇文件,而後點擊"Upload"按鈕,文件開始上傳。
2、iframe上傳
傳統的表單上傳,屬於"同步上傳"。也就是說,點擊上傳按鈕後,網頁"鎖死",用戶只能等待上傳結束,而後瀏覽器刷新,跳到表單的action屬性指定的網址。
有沒有辦法"異步上傳",在網頁不重載的狀況下,完成整個上傳過程呢?
在HTML5沒有出現以前,只能使用iframe作到這一點。用戶點擊submit時,動態插入一個iframe元素(如下代碼使用了jQuery函數庫)。
var form = $("#upload-form"); form.on('submit',function() { // 此處動態插入iframe元素 });
插入iframe的代碼以下:
var seed = Math.floor(Math.random() * 1000);
var id = "uploader-frame-" + seed;
var callback = "uploader-cb-" + seed;
var iframe = $('<iframe id="'+id+'" name="'+id+'" style="display:none;">');
var url = form.attr('action');
form.attr('target', id).append(iframe).attr('action', url + '?iframe=' + callback);
最後一行,有兩個地方值得注意。首先,它爲表單添加target屬性,指向動態插入的iframe窗口,這使得上傳結束後,服務器將結果返回iframe窗口,因此當前頁面就不會跳轉了。其次,它在action屬性指定的上傳網址的後面,添加了一個參數,使得服務器知道回調函數的名稱。這樣就能將服務器返回的信息,從iframe窗口傳到上層頁面。
服務器(upload.php)返回的信息,應該是以下形式:
<script type="text/javascript"> window.top.window['callback'](data); </script>
而後,在當前網頁定義回調函數:
window[callback] = function(data){ console.log('received callback:', data); iframe.remove(); //removing iframe form.removeAttr('target'); form.attr('action', url); window[callback] = undefined; //removing callback };
3、ajax上傳
HTML5提出了XMLHttpRequest對象的第二版,今後ajax可以上傳文件了。這是真正的"異步上傳",是未來的主流。上一節的iframe上傳,能夠用做老式瀏覽器的替代方案。
ajax上傳代碼,放在表單的submit事件回調函數中:
form.on('submit',function() { // 此處進行ajax上傳 });
咱們主要用的是FormData對象,它可以構建相似表單的鍵值對。
// 檢查是否支持FormData if(window.FormData) { var formData = new FormData(); // 創建一個upload表單項,值爲上傳的文件 formData.append('upload', document.getElementById('upload').files[0]); var xhr = new XMLHttpRequest(); xhr.open('POST', $(this).attr('action')); // 定義上傳完成後的回調函數 xhr.onload = function () { if (xhr.status === 200) { console.log('上傳成功'); } else { console.log('出錯了'); } }; xhr.send(formData); }
4、進度條
XMLHttpRequest第二版還定義了一個progress事件,能夠用來製做進度條。
首先,在頁面中放置一個HTML元素progress。
<progress id="uploadprogress" min="0" max="100" value="0">0</progress>
而後,定義progress事件的回調函數。
xhr.upload.onprogress = function (event) { if (event.lengthComputable) { var complete = (event.loaded / event.total * 100 | 0); var progress = document.getElementById('uploadprogress'); progress.value = progress.innerHTML = complete; } };
注意,progress事件不是定義在xhr,而是定義在xhr.upload,由於這裏須要區分下載和上傳,下載也有一個progress事件。
5、圖片預覽
若是上傳的是圖片文件,利用File API,咱們能夠作一個圖片文件的預覽。這裏主要用到FileReader對象。
// 檢查是否支持FileReader對象 if (typeof FileReader != 'undefined') { var acceptedTypes = { 'image/png': true, 'image/jpeg': true, 'image/gif': true }; if (acceptedTypes[document.getElementById('upload').files[0].type] === true) { var reader = new FileReader(); reader.onload = function (event) { var image = new Image(); image.src = event.target.result; image.width = 100; document.body.appendChild(image); }; reader.readAsDataURL(document.getElementById('upload').files[0]); } }
6、拖放上傳
最後,利用HTML5的拖放功能,實現拖放上傳。
先在頁面中放置一個容器,用來接收拖放的文件。
<div id="holder"></div>
對它設置樣式:
#holder { border: 10px dashed #ccc; width: 300px; min-height: 300px; margin: 20px auto; } #holder.hover { border: 10px dashed #0c0; }
拖放文件的代碼,主要是定義dragover、dragend和drop這三個事件。
// 檢查瀏覽器是否支持拖放上傳。 if('draggable' in document.createElement('span')){ var holder = document.getElementById('holder'); holder.ondragover = function () { this.className = 'hover'; return false; }; holder.ondragend = function () { this.className = ''; return false; }; holder.ondrop = function (event) { event.preventDefault(); this.className = ''; var files = event.dataTransfer.files; // do something with files }; }