在web應用中使用文件

使用HTML5 DOM新增的File API,如今可讓網頁要求用戶選擇本地文件,而且讀取這些文件的信息了。選擇的方式既能夠是HTML<input> 元素,也能夠是拖拽 。javascript

你能夠在chrome擴展等代碼中使用DOM File API ;事實上有些須要注意的額外特性。參考 Using the DOM File API in chrome code 。php

訪問選中的文件Edit

考慮下面的HTML:css

<input type="file" id="input">

經過File API,咱們能夠在用戶選取一個或者多個文件以後,訪問到表明了所選文件的一個或多個File對象,這些對象被包含在一個FileList對象中.html

若是用戶只選擇了一個文件,那麼咱們只須要訪問這個FileList對象中的第一個元素.java

可使用傳統的DOM選擇方法來獲取到用戶所選擇的文件:jquery

var selected_file = document.getElementById('input').files[0];

還可使用jQuery選擇器來選擇:web

var selectedfile = $('#input').get(0).files[0];


var selectedFile = $('#input')[0].files[0];

若是你有一個"files is undefined" 錯誤,那麼就是你沒有選擇正確的HTML元素,忘記了一個jQuery選擇器返回的是匹配的DOM元素的列表。用獲取的DOM元素調用「files」的方法就能夠了。正則表達式

在change事件發生時讀取所選擇的文件Edit

另外,還能夠在input元素上的change事件觸發時再訪問它的FileList屬性(但不是強制性的):chrome

<input type="file" id="input" onchange="handleFiles(this.files)">

當用戶成功選取若干個文件後,handleFiles()函數會被調用,且一個表明用戶所選擇的文件的包含了File 對象的FileList對象會做爲參數傳入該函數。canvas

若是你的程序可讓用戶選擇多個文件,記得要在input元素上加上multiple屬性:

<input type="file" id="input" multiple onchange="handleFiles(this.files)">

在用戶選擇了多個文件的狀況下,傳入handleFiles()函數的文件列表將會包含多個File對象,每一個File對象對應一個真實的文件。

動態添加change事件監聽器

你還能夠經過element.addEventListener()方法來添加多個change事件處理函數,像這樣:

var inputElement = document.getElementById("inputField"); inputElement.addEventListener("change", handleFiles, false); function handleFiles() { var fileList = this.files; }

獲取所選文件的信息Edit

用戶所選擇的文件都存儲在了一個FileList對象上,其中每一個文件都對應了一個File對象。你能夠經過這個FileList對象的length屬性知道用戶一共選擇了多少個文件:

var numFiles = files.length;

能夠經過普通的循環語句來操做每一個單獨的File對象:

for (var i = 0, numFiles = files.length; i < numFiles; i++) { var file = files[i]; .. }

File對象上有三個屬性提供了所包含文件的相關信息.

name
文件名,只讀字符串,不包含任何路徑信息.
size
文件大小,單位爲字節,只讀的64位整數.
type
MIME類型,只讀字符串,若是類型未知,則返回空字符串.

例子:顯示文件大小

下面的例子演示了size屬性的用法:

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>File(s) size</title> <script> function updateSize() { var nBytes = 0, oFiles = document.getElementById("uploadInput").files, nFiles = oFiles.length; for (var nFileId = 0; nFileId < nFiles; nFileId++) { nBytes += oFiles[nFileId].size; } var sOutput = nBytes + " bytes"; var aMultiples = ["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"], nMultiple = 0, nApprox = nBytes / 1024; // optional code for multiples approximation for ( ; nApprox > 1; nApprox /= 1024, nMultiple++) { sOutput = nApprox.toFixed(3) + " " + aMultiples[nMultiple] + " (" + nBytes + " bytes)"; } // end of optional code document.getElementById("fileNum").innerHTML = nFiles; document.getElementById("fileSize").innerHTML = sOutput; } </script> </head> <body onload="updateSize();"> <form name="uploadForm"> <p> <input id="uploadInput" type="file" name="myFiles" onchange="updateSize();" multiple> selected files: <span id="fileNum">0</span>; total size: <span id="fileSize">0</span> </p> <p> <input type="submit" value="Send file"> </p> </form> </body> </html>

在隱藏的文件輸入框上調用click()方法Edit

從Gecko 2.0 (Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1)開始,你能夠隱藏掉默認的文件輸入框<input>元素,使用自定義的界面來充當打開文件選擇對話框的按鈕.實現起來很簡單,你只須要使用樣式display:none把本來的文件輸入框隱藏掉,而後在須要的時候調用它的click()方法就好了.

考慮一下下面的HTML:

<input type="file" id="fileElem" multiple accept="image/*" style="display:none" onchange="handleFiles(this.files)">
<a href="#" id="fileSelect">Select some files</a>

爲自定義的按鈕綁定click事件:

var fileSelect = document.getElementById("fileSelect"), fileElem = document.getElementById("fileElem"); fileSelect.addEventListener("click", function (e) { if (fileElem) { fileElem.click(); } e.preventDefault(); // prevent navigation to "#" }, false);

這樣,你就能任意改變這個新按鈕的樣式了.

經過拖放操做選擇文件Edit

你可讓用戶將本地文件拖放到你的應用程序上.

首先要建立一個拖放操做的目的區域:

第一步是創建一個放置區域。可根據您的應用程序的設計來決定哪部分的內容接受 drop,但建立一個接收drop事件的元素是簡單的:

var dropbox; dropbox = document.getElementById("dropbox"); dropbox.addEventListener("dragenter", dragenter, false); dropbox.addEventListener("dragover", dragover, false); dropbox.addEventListener("drop", drop, false);

在這個例子中,ID爲dropbox的元素所在的區域是咱們的拖放目的區域。咱們須要在該元素上綁定dragenterdragover,drop事件。

咱們必須阻止dragenterdragover事件的默認行爲,這樣才能觸發drop事件:

function dragenter(e) { e.stopPropagation(); e.preventDefault(); } function dragover(e) { e.stopPropagation(); e.preventDefault(); }

下面是drop()函數:

function drop(e) { e.stopPropagation(); e.preventDefault(); var dt = e.dataTransfer; var files = dt.files; handleFiles(files); }

在該函數中,咱們從事件對象中獲取到dataTransfer對象,把該對象包含的Filelist對象傳入函數handleFiles(),這個函數會無區別的對待從input元素或拖放操做中來的文件列表。

例子:顯示用戶所選圖片的縮略圖Edit

假設你正在開發下一個偉大的照片分享網站,並但願使用HTML5在用戶上傳他們圖片以前進行縮略圖預覽。您能夠如前面所討論的創建一個輸入元素或者拖放區域,並調用一個函數,以下面的handleFiles()函數。

function handleFiles(files) {
  for (var i = 0; i < files.length; i++) {
    var file = files[i];
    var imageType = /^image\//;
    
    if ( ) {
      continue;
    }
    
    var img = document.createElement("img");
    img.classList.add("obj");
    img.file = file;
    
    preview.appendChild(img);
    
    var reader = new FileReader();
    reader.onload = (function(aImg) { 
      return function(e) { 
        aImg.src = e.target.result; 
      }; 
    })(img);
    reader.readAsDataURL(file);
  }
}!imageType.test(file.type)// Assuming that "preview" is the div output where the content will be displayed

這裏咱們循環處理用戶選擇的文件,查看每一個文件的類型屬性,看看這是不是一個圖像文件(經過一個正則表達式匹配字符串「image.*」)。對於每 個圖片文件,咱們建立一個新的img元素。CSS能夠用於創建任何漂亮的邊界,陰影,和指定圖像的大小,因此,甚至不須要在這裏完成。

每張圖片咱們添加一個obj類,讓他們更容易的在DOM樹中被找到。咱們也在圖片上添加了一個file屬性來確認每張圖片的 File,這樣能夠幫助咱們在以後真正的上傳工做時獲取到圖片。最後咱們使用 Node.appendChild() 把縮略圖添加到咱們先前的文檔區域中。

而後,咱們創建了{ { domxref(FileReader)} }來處理圖片的異步加載,並把它添加到img元素上。在建立新的FileReader對象以後,咱們創建了onload函數,而後調用 readAsDataURL()開始在後臺進行讀取操做。當圖像文件的全部內容加載後,他們轉換成一個 data: URL,傳遞到onload回調函數中。以後只須要把img元素的src屬性設置爲這個加載過的圖像,就可讓圖像的縮略圖出如今用戶的屏幕 上。

使用對象URLEdit

Gecko 2.0 (Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1)開始支持window.URL.createObjectURL()window.URL.revokeObjectURL()兩個DOM方法。這兩個方法建立簡單的URL字符串對象,用於指向任何 DOM File 對象數據,包括用戶電腦中的本地文件。

當你想要在HTML中經過URL來引用File對象,你能夠參考以下方式建立:

var objectURL = window.URL.createObjectURL(fileObj);

URL對象是 File 對象的一個字符串標識。 每次調用window.URL.createObjectURL()的時候,會建立一個惟一的URL對象,即便你已經爲該文件建立了URL對象。這些對象都必須被釋放。 當文檔被卸載時,它們會自動釋放,若是你的頁面動態地使用它們,你應該明確地經過調用window.URL.revokeObjectURL()釋放它們:

window.URL.revokeObjectURL(objectURL);

例子: 使用對象URL來顯示圖片Edit

這個例子使用了對象URL來顯示圖片縮略圖,同時還顯示了圖片的其餘信息,包括圖片名和圖片大小,你能夠查看該例子的在線演示.

負責界面呈現的HTML以下:

<input type="file" id="fileElem" multiple accept="image/*" style="display:none" onchange="handleFiles(this.files)"> <a href="#" id="fileSelect">Select some files</a> <div id="fileList"> <p>No files selected!</p> </div>

這創建文件的<input>元素就像一個調用文件選擇器的連接(由於咱們要隱藏文件輸入,以防止表現出不友好的UI)。這部分將在 Using hidden file input elements using the click() method裏解釋,由於是調用文件選擇器的方法。

下面是 handleFiles()方法

window.URL = window.URL || window.webkitURL; var fileSelect = document.getElementById("fileSelect"), fileElem = document.getElementById("fileElem"), fileList = document.getElementById("fileList"); fileSelect.addEventListener("click", function (e) { if (fileElem) { fileElem.click(); } e.preventDefault(); // prevent navigation to "#" }, false); function handleFiles(files) { if (!files.length) { fileList.innerHTML = "<p>No files selected!</p>"; } else { var list = document.createElement("ul"); for (var i = 0; i < files.length; i++) { var li = document.createElement("li"); list.appendChild(li); var img = document.createElement("img"); img.src = window.URL.createObjectURL(files[i]); img.height = 60; img.onload = function(e) { window.URL.revokeObjectURL(this.src); } li.appendChild(img); var info = document.createElement("span"); info.innerHTML = files[i].name + ": " + files[i].size + " bytes"; li.appendChild(info); } fileList.appendChild(list); } }

This starts by fetching the URL of the <div> with the ID fileList. This is the block into which we'll insert out file list, including thumbmails.

If the FileList object passed to handleFiles() is null, we simply set the inner HTML of the block to display "No files selected!". Otherwise, we start building our file list, as follows:

  1. A new unordered list (<ul>) element is created.
  2. The new list element is inserted into the <div> block by calling its element.appendChild() method.
  3. For each File in the FileList represented by files
    1. Create a new list item (<li>) element and insert it into the list.
    2. Create a new image (<img>) element.
    3. Set the image's source to a new object URL representing the file, using window.URL.createObjectURL() to create the blob URL.
    4. Set the image's height to 60 pixels.
    5. Set up the image's load event handler to release the object URL, since it's no longer needed once the image has been loaded. This is done by calling the window.URL.revokeObjectURL() method, passing in the object URL string as specified by img.src.
    6. Append the new list item to the list.

例子:上傳用戶選擇的文件Edit

你能夠異步的將用戶所選擇的文件上傳到服務器上(好比一張圖片).

建立上傳任務

Continuing with the code that builds the thumbnails in the previous example, recall that every thumbnail image is in the CSS class obj, with the corresponding File attached in a file attribute. This lets us very easily select all the images the user has chosen for uploading using Document.querySelectorAll(), like this:

function sendFiles() { var imgs = document.querySelectorAll(".obj"); for (var i = 0; i < imgs.length; i++) { new FileUpload(imgs[i], imgs[i].file); } }

Line 2 creates an array, called imgs, of all the elements in the document with the CSS class obj. In our case, these will be all the image thumbnails. Once we have that list, it's trivial to go through the list, creating a new FileUpload instance for each. Each of these handles uploading the corresponding file.

實現文件上傳

FileUpload函數接受兩個參數:一個IMG元素,一個File對象或Blob對象.

function FileUpload(img, file) { var reader = new FileReader(); this.ctrl = createThrobber(img); var xhr = new XMLHttpRequest(); this.xhr = xhr; var self = this; this.xhr.upload.addEventListener("progress", function(e) { if (e.lengthComputable) { var percentage = Math.round((e.loaded * 100) / e.total); self.ctrl.update(percentage); } }, false); xhr.upload.addEventListener("load", function(e){ self.ctrl.update(100); var canvas = self.ctrl.ctx.canvas; canvas.parentNode.removeChild(canvas); }, false); xhr.open("POST", "http://demos.hacks.mozilla.org/paul/demos/resources/webservices/devnull.php"); xhr.overrideMimeType('text/plain; charset=x-user-defined-binary'); reader.onload = function(evt) { xhr.sendAsBinary(evt.target.result); }; reader.readAsBinaryString(file); }

The FileUpload() function shown above creates a throbber, which is used to display progress information, then creates an XMLHttpRequest to handle uploading the data.

Before actually transferring the data, several preparatory steps are taken:

  1. The XMLHttpRequest's upload progress listener is set to update the throbber with new percentage information, so that as the upload progresses, the throbber will be updated based on the latest information.
  2. The XMLHttpRequest's upload load event handler is set to update the throbber with 100% as the progress information (to ensure the progress indicator actually reaches 100%, in case of granularity quirks during the process). It then removes the throbber, since it's no longer needed. This causes the throbber to disappear once the upload is complete.
  3. The request to upload the image file is opened by calling XMLHttpRequest's open() method to start generating a POST request.
  4. The MIME type for the upload is set by calling the XMLHttpRequest function overrideMimeType(). In this case, we're using a generic MIME type; you may or may not need to set the MIME type at all, depending on your use case.
  5. The FileReader object is used to convert the file to a binary string.
  6. Finally, when the content is loaded the XMLHttpRequest function sendAsBinary() is called to upload the file's content.

異步實現文件上傳

<?php if (isset($_FILES['myFile'])) { // Example: move_uploaded_file($_FILES['myFile']['tmp_name'], "uploads/" . $_FILES['myFile']['name']); exit; } ?><!DOCTYPE html> <html> <head> <title>dnd binary upload</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script type="text/javascript"> function sendFile(file) { var uri = "/index.php"; var xhr = new XMLHttpRequest(); var fd = new FormData(); xhr.open("POST", uri, true); xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { // Handle response. alert(xhr.responseText); // handle response. } }; fd.append('myFile', file); // Initiate a multipart/form-data upload xhr.send(fd); } window.onload = function() { var dropzone = document.getElementById("dropzone"); dropzone.ondragover = dropzone.ondragenter = function(event) { event.stopPropagation(); event.preventDefault(); } dropzone.ondrop = function(event) { event.stopPropagation(); event.preventDefault(); var filesArray = event.dataTransfer.files; for (var i=0; i<filesArray.length; i++) { sendFile(filesArray[i]); } } </script> </head> <body> <div> <div id="dropzone" style="margin:30px; width:500px; height:300px; border:1px dotted grey;"> Drag & drop your file here... </div> </div> </body> </html>

示例: 使用URLs對象顯示 PDFEdit

URLs對象不只僅是可用於圖像!它們可用於顯示嵌入的PDF文件,或能夠由瀏覽器顯示的任何其它資源。

在火狐中,使PDF出如今內嵌的iframe中(並不建議做爲一個下載的文件),把偏好pdfjs.disabled設置爲false 

<iframe id="viewer">

src 屬性在這裏有些變化:

var obj_url = window.URL.createObjectURL(blob);
var iframe = document.getElementById('viewer');
iframe.setAttribute('src', obj_url);
window.URL.revokeObjectURL(obj_url);

示例:其餘文件類型使用URLs對象Edit

你能夠用一樣的方式操縱其它格式的文件。下面是如何預覽上傳的視頻:

var video = document.getElementById('video');
var obj_url = window.URL.createObjectURL(blob);
video.src = obj_url;
video.play()
window.URL.revokeObjectURL(obj_url);
相關文章
相關標籤/搜索