iT邦幫忙

DAY 17
6

HTML5試試看系列 第 17

[HTML5試試看-17] 互動機制 - drag and drop 與 File API

HTML5的drag and drop機制,不僅可以接收從其他應用軟體拖曳過來的資料,他其實還可以讀取檔案。讀取檔案,靠的是File API
還是先看一下File API的介面:

DataTransfer.files物件,其實是一個FileList,透過他的length屬性可以知道裡面是否有File物件,然後可以用類似陣列的方式來取得個別的File物件。

取出來的每個File物件,繼承自Blob物件:

interface Blob {
  readonly attribute unsigned long long size;
  readonly attribute DOMString type;
  //slice Blob into byte-ranged chunks
  Blob slice(in unsigned long long start,
             in unsigned long long length,
             optional DOMString contentType); 
};

可以透過size取得檔案長度,透過type取得檔案的mime type。透過slice()方法,則可以傳回部份的檔案。

另外,File物件定義了幾個屬性:

interface File : Blob {
    readonly attribute DOMString name;
    readonly attribute DOMString lastModifiedDate;
};

name就是檔案名稱,lastModifiedDate則可取得最後修改的日期資訊。

要讀取檔案,還需要使用FileReader物件:

[Constructor]
interface FileReader {
  // async read methods
  void readAsArrayBuffer(in Blob blob);
  void readAsBinaryString(in Blob blob);
  void readAsText(in Blob blob, [Optional] in DOMString encoding);
  void readAsDataURL(in Blob blob);
  void abort();
  // states
  const unsigned short EMPTY = 0;
  const unsigned short LOADING = 1;
  const unsigned short DONE = 2;
  readonly attribute unsigned short readyState; 
  // File or Blob data
  readonly attribute any result;
  readonly attribute FileError error;
  // event handler attributes
  attribute Function onloadstart;
  attribute Function onprogress;
  attribute Function onload;
  attribute Function onabort;
  attribute Function onerror;
  attribute Function onloadend;
};
FileReader implements EventTarget;

雖然有這麼長一絡,其實只要知道了他「非同步運作」的機制,就可以簡單地使用:

var reader = new FileReader();//產生FileReader物件實例
reader.addEventListener('load', function(){
  console.log(this.result);//指定事件處理函數來處理讀取的資料
}, false);
reader.readAsDataURL(File);//將檔案用不同格式讀取

readAsArrayBuffer(), readAsBinaryString(), readAsText(), readAsDataURL()可以選擇讀取檔案後,存放在result屬性裡的資料格式。load事件會在檔案讀取完畢時觸發,這時就可以在事件處理函數內,透過result屬性來取得讀取的資料。如果是圖檔,有支援DataURL的瀏覽器,就可以直接把DataURL指派為img元素的src,然後在網頁中呈現。JavaScript字串的內部格式都是Unicode,所以readAdText會影響到一些binary資料的正確性。readAsBinaryString應該就沒有這個問題,不過目前找不到比較好的應用方式...其實如果瀏覽器實作了XMLHttpRequest2規格,就用得上了。目前的XMLHttpRequest在傳送資料時會把格式轉成UTF8,XMLHttpRequest2則有能力使用Binary格式來傳送資料。

另外,如果是在網頁之外的環境,例如WebWorker中,也可以使用「同步」版本的FileAPI,不過我還沒嘗試過,也不確定目前支援WebWorker的瀏覽器,在WebWorker的Global物件中是否有提供FileReader。

如果對整合FileAPI的應用有興趣,我試作了一個使用AJAX的方式上傳檔案的網頁,因為目前的XMLHttpRequest不支援Binary格式資料的傳送,所以我是用readAsDataURL()來取得base64編碼的資料,然後利用XMLHttpRequest實作一個multipart/form-data格式的POST命令來傳送檔案資料(一般是使用url encoded格式的POST)。缺點是,伺服器收到的資料也還是base64編碼,所以伺服器端需要對檔案做解碼。有興趣可以看一下我前不久寫的文章:HTML5 Drag&Drop + 純AJAX檔案上傳,程式我就不在這裡貼了。

參賽文章


上一篇
[HTML5試試看-16] 互動機制 - drag and drop(續)
下一篇
[HTML5試試看-18] 溝通 - cross document message
系列文
HTML5試試看30

尚未有邦友留言

立即登入留言