文件上傳的漸進式加強

轉自:javascript

http://kb.cnblogs.com/page/153741/
php


文件上傳是最古老的互聯網操做之一。html

  20多年了,它幾乎沒變,仍是原來的樣子:操做麻煩、缺少交互、用戶體驗不佳。在這個新技術突飛猛進的時代,顯得很是落伍。html5

  網頁開發者們想了不少辦法,試圖提高文件上傳的功能和操做體驗,在各類 Javascript 庫的基礎上,開發了五花八門的插件。但是,因爲不一樣瀏覽器之間的差別,缺少統一接口,這些插件要麼用起來很麻煩,要麼不能廣泛適用。java

  HTML5提供了一系列新的瀏覽器 API,使得文件上傳有可能出現革命性變化。英國程序員 Remy Sharp 總結了這些新的接口,本文在他的文章基礎上,討論如何採用 HTML5 的 API,對文件上傳進行漸進式加強,實現如下功能:jquery

  • iframe 上傳
  • ajax 上傳
  • 進度條
  • 文件預覽
  • 拖放上傳

  爲了對這些功能有一個感性認識,你能夠先看看 Remy Sharp 提供的範例程序員

  雖然這些 API,尚未獲得普遍部署,但它們是將來的潮流。有了它們,代碼就能夠寫得很是優雅簡潔,上面五個功能都能在 20 行之內實現。web

  1、傳統形式ajax

  讓咱們從最基本的開始。api

  文件上傳的傳統形式,是使用表單元素 file:

<form action="upload.php" method="post" enctype="multipart/form-data" >
<input type="file" 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 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></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
  };
}

  完成後的效果和整體代碼,請看拖放上傳 demo

相關文章
相關標籤/搜索