转自: https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications#Example.3A_Using_object_URLs_to_display_images
Using the File API, which was added to the DOM in HTML5, it's now possible for web content to ask the user to select local files and then read the contents of those files. This selection can be done by either using an HTML <input>
element or by drag and drop.
If you want to use the DOM File API from extensions or other browser chrome code, you can; however, note there are some additional features to be aware of. See Using the DOM File API in chrome code for details.
Consider this HTML:
<input type="file" id="input">
The File API makes it possible to access a FileList
containing File
objects representing the files selected by the user.
If the user selects just one file, it is then only necessary to consider the first file of the list.
Accessing one selected file using a classical DOM selector:
var selectedFile = document.getElementById('input').files[0];
Accessing selected file(s) on a change event
It is also possible (but not mandatory) to access the FileList
through the change
event:
<input type="file" id="input" onchange="handleFiles(this.files)">
When the user selects a file, the handleFiles()
function gets called with a FileList
object containing File
objects representing the files selected by the user.
If you want to let the user select multiple files, simply use the multiple
attribute on the input
element:
<input type="file" id="input" multiple onchange="handleFiles(this.files)">
In this case, the file list passed to the handleFiles()
function contains one File
object for each file the user selected.
You need to use EventTarget.addEventListener()
to add the change
event listener, like this:
var inputElement = document.getElementById("input");
inputElement.addEventListener("change", handleFiles, false);
function handleFiles() {
var fileList = this.files; /* now you can work with the file list */
}
Note that in this case, the handleFiles()
function itself is the event handler, unlike previous examples where it was called by an event handler which passed it a parameter.
The FileList
object provided by the DOM lists all of the files selected by the user, each specified as a File
object. You can determine how many files the user selected by checking the value of the file list's length
attribute:
var numFiles = files.length;
Individual File
objects can be retrieved by simply accessing the list as an array:
for (var i = 0, numFiles = files.length; i < numFiles; i++) {
var file = files[i];
..
}
This loop iterates over all the files in the file list.
There are three attributes provided by the File
object that contain useful information about the file.
name
size
type
""
if the type couldn't be determined.
The following example shows a possible use of the size
property:
<!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";
// optional code for multiples approximation
for (var aMultiples = ["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"], nMultiple = 0, nApprox = nBytes / 1024; 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>
Starting in Gecko 2.0 (Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1), you can hide the admittedly ugly file <input>
element and present your own interface for opening the file picker and displaying which file or files the user has selected. You can do this by styling the input element with display:none
and calling the click()
method on the <input>
element.
Consider this HTML:
<input type="file" id="fileElem" multiple accept="image/*" style="display:none" onchange="handleFiles(this.files)">
<a href="#" id="fileSelect">Select some files</a>
The code that handles the click
event can look like this:
var fileSelect = document.getElementById("fileSelect"),
fileElem = document.getElementById("fileElem");
fileSelect.addEventListener("click", function (e) {
if (fileElem) {
fileElem.click();
}
e.preventDefault(); // prevent navigation to "#"
}, false);
You can style the new button for opening the file picker as you wish.
To allow opening the file picker without using JavaScript (the click() method), a <label>
element can be used.
Consider this HTML:
<input type="file" id="fileElem" multiple accept="image/*" style="display:none" onchange="handleFiles(this.files)">
<label for="fileElem">Select some files</label>
There is no need to add JavaScript code to call fileElem.click()
. Also in this case you can style the label element as you wish.
You can also let the user drag and drop files into your web application.
The first step is to establish a drop zone. Exactly what part of your content will accept drops may vary depending on the design of your application, but making an element receive drop events is easy:
var dropbox;
dropbox = document.getElementById("dropbox");
dropbox.addEventListener("dragenter", dragenter, false);
dropbox.addEventListener("dragover", dragover, false);
dropbox.addEventListener("drop", drop, false);
In this example, we're turning the element with the ID dropbox
into our drop zone. This is done by adding listeners for the dragenter
, dragover
, and drop
events.
We don't actually need to do anything with the dragenter
and dragover
events in our case, so these functions are both simple. They just stop propagation of the event and prevent the default action from occurring:
function dragenter(e) {
e.stopPropagation();
e.preventDefault();
}
function dragover(e) {
e.stopPropagation();
e.preventDefault();
}
The real magic happens in the drop()
function:
function drop(e) {
e.stopPropagation();
e.preventDefault();
var dt = e.dataTransfer;
var files = dt.files;
handleFiles(files);
}
Here, we retrieve the dataTransfer
field from the event, pull the file list out of it, and then pass that to handleFiles()
. From this point on, handling the files is the same whether the user used the input
element or drag and drop.
Let's say you're developing the next great photo-sharing website and want to use HTML5 to display thumbnail previews of images before the user actually uploads them. You can establish your input element or drop zone as discussed previously and have them call a function such as the handleFiles()
function below.
function handleFiles(files) {
for (var i = 0; i < files.length; i++) {
var file = files[i];
var imageType = /^image\//;
if (!imageType.test(file.type)) {
continue;
}
var img = document.createElement("img");
img.classList.add("obj");
img.file = file;
preview.appendChild(img); // Assuming that "preview" is the div output where the content will be displayed.
var reader = new FileReader();
reader.onload = (function(aImg) { return function(e) { aImg.src = e.target.result; }; })(img);
reader.readAsDataURL(file);
}
}
Here our loop handling the user-selected files looks at each file's type
attribute to see if it's an image file (by doing a regular expression match on the MIME type string pattern "image/*
"). For each file that is an image, we create a new img
element. CSS can be used to establish any pretty borders or shadows and to specify the size of the image, so that doesn't need to be done here.
Each image has the CSS class obj
added to it, making it easy to find in the DOM tree. We also add a file
attribute to each image specifying the File
for the image; this will let us fetch the images for actual upload later. We use Node.appendChild()
to add the new thumbnail to the preview area of our document.
Next, we establish the FileReader
to handle asynchronously loading the image and attaching it to the img
element. After creating the new FileReader
object, we set up its onload
function and then call readAsDataURL()
to start the read operation in the background. When the entire contents of the image file are loaded, they are converted into a data:
URL which is passed to the onload
callback. Our implementation of this routine sets the img
element's src
attribute to the loaded image which results in the image appearing in the thumbnail on the user's screen.
Gecko 2.0 (Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1) introduces support for the DOM window.URL.createObjectURL()
and window.URL.revokeObjectURL()
methods. These let you create simple URL strings that can be used to reference any data that can be referred to using a DOM File
object, including local files on the user's computer.
When you have a File
object you'd like to reference by URL from HTML, you can create an object URL for it like this:
var objectURL = window.URL.createObjectURL(fileObj);
The object URL is a string identifying the File
object. Each time you call window.URL.createObjectURL()
, a unique object URL is created even if you've created an object URL for that file already. Each of these must be released. While they are released automatically when the document is unloaded, if your page uses them dynamically you should release them explicitly by calling window.URL.revokeObjectURL()
:
window.URL.revokeObjectURL(objectURL);
This example uses object URLs to display image thumbnails. In addition, it displays other file information including their names and sizes.
The HTML that presents the interface looks like this:
<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>
This establishes our file <input>
element as well as a link that invokes the file picker (since we keep the file input hidden to prevent that less-than-attractive user interface from being displayed). This is explained in the section Using hidden file input elements using the click() method, as is the method that invokes the file picker.
The handleFiles()
method follows:
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 {
fileList.innerHTML = "";
var list = document.createElement("ul");
fileList.appendChild(list);
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() {
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);
}
}
}
This starts by fetching the URL of the <div>
with the ID fileList
. This is the block into which we'll insert our file list, including thumbnails.
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:
<ul>
) element is created.<div>
block by calling its Node.appendChild()
method.File
in the FileList
represented by files
:
<li>
) element and insert it into the list.<img>
) element.window.URL.createObjectURL()
to create the blob URL.window.URL.revokeObjectURL()
method and passing in the object URL string as specified by img.src
.Here is a live demo of the code above: