Progressive enhancement of file upload
File upload is one of the oldest Internet operations.
After more than 20 years, it has hardly changed and is still the same: troublesome operation, lack of interaction, and poor user experience. In this era of ever-changing new technologies, it seems very outdated.
Web developers have thought of many ways to improve the function and operating experience of file upload. Based on various Javascript libraries, they have developed a variety of plug-ins . However, due to the differences between different browsers and the lack of a unified interface, these plug-ins are either cumbersome to use or not universally applicable.
HTML5 provides a series of new browser APIs, making file uploads possible revolutionary changes. British programmer Remy Sharp summarized these new interfaces . Based on his article, this article discusses how to use HTML5 API to progressively enhance file upload to achieve the following functions:
* iframe upload
* ajax upload
* progress bar
* File preview
* Drag and drop upload
In order to have a perceptual understanding of these functions, you can first take a look at the examples provided by Remy Sharp .
Although these APIs have not been widely deployed, they are the trend of the future. With them, the code can be written very elegantly and concisely, and the above five functions can be implemented in less than 20 lines.
1. Traditional form
Let’s start from the most basic.
The traditional form of file upload is to use the form element 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>
All browsers support the above code. It is displayed as follows in IE browser:
The user first selects the file, and then clicks the “Upload” button, the file starts uploading.
Two, iframe upload
The traditional form upload belongs to “synchronous upload”. In other words, after clicking the upload button, the web page “locks up”, and the user can only wait for the upload to end, then the browser refreshes and jumps to the URL specified by the action attribute of the form.
Is there a way to “asynchronous upload” to complete the entire upload process without reloading the web page?
Before HTML5 appeared, this could only be done using iframes. When the user clicks submit, an iframe element is dynamically inserted (the following code uses the jQuery library).
var form = $(“#upload-form”);
form.on(‘submit’,function() {
// dynamically insert iframe elements here
});
The code to insert the iframe is as follows:
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);
There are two things worth noting in the last line. First, it adds a target attribute to the form to point to the dynamically inserted iframe window. This makes the server return the result to the iframe window after the upload is complete, so the current page will not jump. Second, it adds a parameter after the upload URL specified by the action attribute, so that the server knows the name of the callback function. In this way, the information returned by the server can be transferred from the iframe window to the upper page.
The information returned by the server (upload.php) should be in the following form:
<script type=”text/javascript”>
window.top.window[‘callback’](data);
</script>
Then, define the callback function on the current web page:
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
};
Three, ajax upload
HTML5 proposed the second version of the XMLHttpRequest object , and since then Ajax can upload files. This is true “asynchronous upload”, and it will be the mainstream in the future. The iframe upload in the previous section can be used as an alternative to older browsers.
The ajax upload code is placed in the submit event callback function of the form:
form.on(‘submit’,function() {
// Ajax upload here
});
We mainly use the FormData object , which can build key-value pairs similar to forms.
// Check if FormData is supported
if(window.FormData) {var formData = new FormData();
// Create an upload form item with the value of the uploaded file
formData.append(‘upload’, document.getElementById(‘upload’).files[0]);var xhr = new XMLHttpRequest();
xhr.open(‘POST’, $(this).attr(‘action’));
// Define the callback function after the upload is complete
xhr.onload = function () {if (xhr.status === 200) {
console.log(‘Uploaded successfully’);
} else {
console.log(‘Something went wrong’);
}
};
xhr.send(formData);
}
Fourth, the progress bar
The second edition of XMLHttpRequest also defines a progress event , which can be used to make a progress bar.
First, place an HTML element progress on the page.
<progress id=”uploadprogress” min=”0″ max=”100″ value=”0″>0</progress>
Then, define the callback function for the progress event.
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;
}
};
Note that the progress event is not defined in xhr, but in xhr.upload, because download and upload need to be distinguished here, and download also has a progress event.
Five, picture preview
If the upload is a picture file, using the File API , we can do a preview of the picture file. The FileReader object is mainly used here .
// Check if the FileReader object is supported
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]);
}
}
Six, drag and drop upload
Finally, use HTML5’s drag-and-drop function to realize drag-and-drop upload.
First place a container on the page to receive the drag and drop files.
<div id=”holder”></div>
Style it:
#holder {
border: 10px dashed #ccc;
width: 300px;
min-height: 300px;
margin: 20px auto;
}#holder.hover {
border: 10px dashed #0c0;
}
The code of drag and drop files mainly defines the three events of dragover, dragend and drop.
// Check if the browser supports drag and drop upload.
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
};
}
For the finished effect and overall code, please see the drag and drop upload demo .
(over)