Файлы через ajax спокойно отправляются, и даже прогресс-бар можно прикрутить.
Пример (jQuery, WinterCMS, Bootstrap):
postFiles: function($form, request, callback)
{
var formData = new FormData($form[0]);
var input = $form.find('input[type=file]')[0];
for(var n in input.files) {
if(input.files[n].size > 104857600) {
alert('Максимальный размер загружаемых файлов - 100 Мб!');
return;
}
}
$.ajax({
url: window.location.href,
headers: {
'X-WINTER-REQUEST-HANDLER': request? request : $form.attr('data-request') // это для WinterCMS
},
method: 'POST',
dataType: 'json',
type: 'POST',
processData: false,
contentType: false,
data: formData,
success: function(data) {
$('#file-upload-progress').remove();
if(callback) {
callback(data);
} else {
eval($form.attr('data-request-success'));
}
},
error: function(data) {
$('#file-upload-progress').remove();
if(data.responseText) {
alert(data.responseText);
}
},
xhr: function() { // custom xhr
var myXhr = $.ajaxSettings.xhr();
if(myXhr.upload) {
myXhr.upload.addEventListener(
'progress',
function(evt) {
if (evt.lengthComputable) {
var $progress = $('#file-upload-progress');
if($progress.length === 0) {
$progress = $(
'<div id="file-upload-progress" style="position: fixed; top: 0; left: 45%; text-align: center; background-color: white; border-radius: 1em; padding: 0 1em 1em 1em; border: 2px solid #CEF; z-index: 2000">' +
'<h6>Загрузка файлов</h6>' +
'<div class="progress" style="margin-bottom: 1em">' +
'<div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>' +
'</div>' +
'</div>'
);
$progress.append(
$('<button class="btn btn-sm btn-default"><i class="icon-remove"></i> Отменить загрузку</button>')
.click(function() {
myXhr.abort();
$progress.remove();
})
)
$('body').append($progress.hide());
}
var percentComplete = Math.round(evt.loaded / evt.total * 100);
if(percentComplete === 1) {
$progress.hide();
} else {
$progress.find('div.progress-bar').css('width', percentComplete + '%').attr('aria-valuenow', percentComplete).html(percentComplete + ' %');
$progress.show();
}
}
},
false
);
}
return myXhr;
}
});
return false;
},