Серия статей "Ajax на практике"
- Основы передачи данных
- Получение данных из формы
- Загрузка файлов
- Progress Bar - индикатор процесса загрузки.
- Запрос на чистом JavaScript
В предыдущей статье, мы коснулись темы загрузки файлов методом $.ajax() и, если обычные данные грузятся и обрабатываются на сервере достаточно быстро, то с файлами этот процесс, может занять значительно больше времени, а тем более, если выполняется мультизагрузка. В первом случае, вполне достаточно вывести для пользователя какой-нибудь анимированный прелоадер, чтоб дать ему понять, что сервер не ушёл на обед, а занимается делом. Во втором же случае, гораздо разумней показать пользователю ход выполнения операции, т.к. веся́щий секунд 5 и больше прелоадер, может утомить юзера или, того хуже, если он подумает, что сервер завис, развернется и уйдет с вашего ресурса. Вот тут-то и пригодится нам "индикатор процесса", он же "прогресс-бар", он же "progress bar" и т.п. ;)
С частью html - всё достаточно просто, хотя и не так безоблачно. Для прогрессбара используют или тег <progress> (реже <meter>), или создают кастомный из любого понравившегося html-элемента. Первые два не очень кроссбраузерны, но предусмотренный в них альтернативный текст, который можно использовать для показа процентов выполнения загрузки, немного исправляет положение. Со вторым вариантом - приходится повозится в CSS, но это не проблема для людей знающих. Мы остановимся на первом, т.к. у нас сейчас основная цель - разобраться с механизмом на JavaScript.
Итак, создадим простую форму для загрузки файла и после поля файла, разместим прогресс-бар, в котором нас интересуют два атрибута: value - текущее значение и max - максимальное значение. Так как мы будем использовать проценты, значения будут колебатся от нуля до ста. Соответственно стартовое значение (value) должно быть "0", а максимальное (max) - "100" :
HTML (файл index.html)
<form action="handler.php" method="post" id="my_form" enctype="multipart/form-data">
<p>
<label for="my_file">Файл:</label>
<input type="file" name="my_file" id="my_file">
<progress id="progressbar" value="0" max="100"></progress>
</p>
<input type="submit" id="submit" value="Отправить">
</form>
В JS пишем практически всё, что разбирали в статье по "загрузке файлов", но добавляем параметр xhr, в callback-функции которого, мы можем работать с объектом XMLHttpRequest, изменяя или дополняя его поведение, получать доступ его свойствам и методам, устанавливать свои обработчики событий и т.д.:
jQuery (файл script.js)
$(function(){
var progressBar = $('#progressbar');
$('#my_form').on('submit', function(e){
e.preventDefault();
var $that = $(this),
formData = new FormData($that.get(0));
$.ajax({
url: $that.attr('action'),
type: $that.attr('method'),
contentType: false,
processData: false,
data: formData,
dataType: 'json',
xhr: function(){
var xhr = $.ajaxSettings.xhr(); // получаем объект XMLHttpRequest
xhr.upload.addEventListener('progress', function(evt){ // добавляем обработчик события progress (onprogress)
if(evt.lengthComputable) { // если известно количество байт
// высчитываем процент загруженного
var percentComplete = Math.ceil(evt.loaded / evt.total * 100);
// устанавливаем значение в атрибут value тега <progress>
// и это же значение альтернативным текстом для браузеров, не поддерживающих <progress>
progressBar.val(percentComplete).text('Загружено ' + percentComplete + '%');
}
}, false);
return xhr;
},
success: function(json){
if(json){
$that.after(json);
}
}
});
});
});
Что касается серверной части, то там работаем с файлом/файлами, как если бы вы их загружали обычным способом.
Готово! Теперь, чтобы протестировать на локальной машине, нужно выбрать файл побольше, иначе загрузка будет происходить практически моментально и работу прогрессбара, вы попросту не заметите. Что будет в обработчике в этом случае - не важно, главное, чтоб он был. И не забудьте перед тестированием, установить значение директивы upload_max_filesize чуть больше, чем загружаемый файл. Для времменого изменения - это проще всего сделать в файле .htaccess, прописав строку:
php_value upload_max_filesize 1000M # вместо 1000 - своё значение
P.S. На всякий случай, если кому-то понадобится сделать прогресс бар не на UPLOAD, а на DOWNLOAD то нужно внести маленькое изменение, а именно - установить соответствующий обработчик. Ну, естественно, что убрать лишнее. Такое может вам пригодиться, если, например, вы подгружаете на страницу большое изображение.
$(function(){
var progressBar = $('#progressbar'),
bigImg = '/image.png'; // путь к очень большой картинке
// В примере - по клику на какой-то кнопке
$('#get_big_file').on('click', function(e){
e.preventDefault();
$.ajax({
url: bigImg,
type: 'GET', // можно и POST
contentType: false,
processData: false,
xhr: function(){
var xhr = $.ajaxSettings.xhr();
// Устанавливаем обработчик подгрузки
xhr.addEventListener('progress', function(evt){
if (evt.lengthComputable) {
var percentComplete = Math.ceil(evt.loaded / evt.total * 100);
progressBar.val(percentComplete);
}
}, false);
return xhr;
},
success: function(json){
// После того, как изображение полностью получено
// подставляем его URL и выводим на экран
if(json){
$('#output').html('<img src="' + bigImg + '">');
}
}
});
});
});
Пробежавшись по всем четырем статьям, я надеюсь, что у вас уже не возникнет особых сложностей с тем, как работать с методом $.ajax() и вы без труда сможете внедрить его в свои проекты. И наконец, в завершение темы "Ajax", в следующей статейке, разберем реализацию ajax-запросов на чистом (нативном) JavaScript.