(轉載學習)文件上傳的漸進式加強

本文爲轉載學習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
    };
  }
相關文章
相關標籤/搜索