在许多Web应用程序中,附件上传是一个常见且重要的功能。本文将介绍如何在HTML页面上实现多文件上传功能,并将文件一次性提交到服务器。这种解决方案完全在客户端进行操作,用户可以选择多个文件,从不同的文件夹中选择文件,应用验证,查看所选文件的缩略图预览,并允许从列表中删除文件。因此,它非常轻量级,因为所有的开销都保留在客户端。
选择多个文件、从不同文件夹选择文件、对文件扩展名、文件大小和上传文件数量进行验证、以缩略图预览列出所选文件、通过允许删除文件选项过滤所选文件、将选定和过滤后的文件列表保存在JavaScript数组中以提交到服务器。
需要对HTML5、CSS和客户端脚本(JavaScript和JQuery)有基本的了解。
技术介绍:HTML5提供了一种标准的方式来处理本地文件,即File API。File API可以用来创建图像的缩略图预览,也可以使用客户端逻辑来验证上传文件的类型、大小和数量。
使用了标准的HTML5控件进行多文件上传。这是上传文件元素的最直接方式。
为了给文件上传控件一个现代的外观,为文件上传父级span添加了一个样式表。
用户选择后,JavaScript返回所选的File对象列表作为FileList。为文件上传控件添加了一个事件处理程序来访问FileList属性。
document.addEventListener("DOMContentLoaded", init, false);
function init() {
document.querySelector('#files').addEventListener('change', handleFileSelect, false);
}
然后,事件处理函数:
function handleFileSelect(e) {
if (!e.target.files) return;
var files = e.target.files;
for (var i = 0, f; f = files[i]; i++) {
var fileReader = new FileReader();
fileReader.onload = (function(readerEvt) {
return function(e) {
ApplyFileValidationRules(readerEvt);
RenderThumbnail(e, readerEvt);
FillAttachmentArray(e, readerEvt);
};
})(f);
fileReader.readAsDataURL(f);
}
document.getElementById('files').addEventListener('change', handleFileSelect, false);
}
用户选择后,调用fileReader.readAsDataURL()读取文件,并通过设置src属性为数据URL来渲染缩略图。
function RenderThumbnail(e, readerEvt) {
var li = document.createElement('li');
ul.appendChild(li);
li.innerHTML = [
' ×',
''
].join('');
var div = document.createElement('div');
div.className = "FileNameCaptionStyle";
li.appendChild(div);
div.innerHTML = [readerEvt.name].join('');
document.getElementById('Filelist').insertBefore(ul, null);
}
通过为每个图像预览添加×(×在HTML代码中表示x)来添加删除文件的功能。因此,当用户点击红色(x)时,将通过调用下面的Jquery函数将其删除:
jQuery(function($) {
$('div').on('click', '.img-wrap .close', function() {
var id = $(this).closest('.img-wrap').find('img').data('id');
var elementPos = AttachmentArray.map(function(x) { return x.FileName; }).indexOf(id);
if (elementPos !== -1) {
AttachmentArray.splice(elementPos, 1);
}
$(this).parent().find('img').not().remove();
$(this).parent().find('div').not().remove();
$(this).parent().parent().find('div').not().remove();
var lis = document.querySelectorAll('#imgList li');
for (var i = 0; li = lis[i]; i++) {
if (li.innerHTML == "") {
li.parentNode.removeChild(li);
}
}
});
});
对上传的文件应用了三个验证规则:
function CheckFileType(fileType) {
if (fileType == "image/jpeg" || fileType == "image/png" || fileType == "image/gif") {
return true;
} else {
return false;
}
}
function CheckFileSize(fileSize) {
if (fileSize < 300000) {
return true;
} else {
return false;
}
}
function CheckFilesCount(AttachmentArray) {
var len = 0;
for (var i = 0; i < AttachmentArray.length; i++) {
if (AttachmentArray[i] !== undefined) {
len++;
}
}
if (len > 9) {
return false;
} else {
return true;
}
}
然后,根据验证规则显示错误消息:
function ApplyFileValidationRules(readerEvt) {
if (CheckFileType(readerEvt.type) == false) {
alert("The file (" + readerEvt.name + ") does not match the upload conditions, You can only upload jpg/png/gif files");
e.preventDefault();
return;
}
if (CheckFileSize(readerEvt.size) == false) {
alert("The file (" + readerEvt.name + ") does not match the upload conditions, The maximum file size for uploads should not exceed 300 KB");
e.preventDefault();
return;
}
if (CheckFilesCount(AttachmentArray) == false) {
if (!filesCounterAlertStatus) {
filesCounterAlertStatus = true;
alert("You have added more than 10 files. According to upload conditions, you can upload 10 files maximum");
}
e.preventDefault();
return;
}
}
客户端的最终输出将是一个JavaScript数组。可以根据解决方案架构将其发送到服务器端。例如,可以用JSON对象发送它,或者将其保存在HTML隐藏字段中,然后从那里读取。
对于上传规则(文件数量、文件大小和文件类型),建议将其保存在配置文件中,并从那里读取。
如果正在处理大尺寸附件,那么可以添加一个进度条,这也是HTML5支持的。它允许监控文件读取的进度;对于大文件,捕获错误和确定读取完成非常有用。
有关更多信息,请阅读此文。
此控件已在最新版本的Firefox、Internet Explorer、Chrome和Safari上进行了测试。
对于旧版浏览器,可以检查浏览器是否完全支持File API:
if (window.File && window.FileReader && window.FileList && window.Blob) {
// Great success! All the File APIs are supported.
} else {
alert('The File APIs are not fully supported in this browser.');
}