Приложение из реальной жизни

Приложение из реальной жизни.

Вряд ли веб-разработчики считают удобной загрузку файлов на сервер по одному, и редко кому нравится использовать поле <input> для выбора предназначенных для отправки файлов. Программисты стараются делать свои приложения максимально интуитивно понятными, и лучший способ создать такое приложение — объединить техники и методы, с которыми пользователи давно и близко знакомы. Благодаря возможностям API перетаскивания мы создадим практическое приложение, позволяющее загружать на сервер несколько файлов одновременно. Пользователю для выбора файлов нужно будет перетащить их на специальную область на экране. Для начала создадим HTML-документ с зоной приема.

Листинг 13.10. Зона приема для загрузки файлов на сервер

<!DOCTYPE html>

<html lang="ru">

<head>

<title>Ajax Level 2</title>

<link rel="stylesheet" href="ajax. css">

<script src="ajax. js"></script>

</head>

<body>

<section id="databox">

^^еретащите файлы сюда</p>

</section>

</body>

</html>

Код JavaScript для этого примера будет самым сложным из рассмотренных нами до сих пор в этой книге. В нем не только объединяются возможности двух API, но и постоянно используются анонимные функции, позволяющие аккуратно организовать код и ограничить его единым контекстом (все находится внутри одной и той же функции). Нам необходимо собрать файлы, которые пользователь перетащит на элемент databox, и перечислить их на экране, затем подготовить формы с файлами, предназначенными для отправки, и создать для каждого из них запрос на загрузку. Кроме того, мы создадим индикаторы прогресса для всех файлов и будем обновлять их в процессе загрузки.

Листинг 13.11. Последовательная загрузка файлов на сервер

Function initiate(){

Databox=document. getElementById(‘databox’);

Databox. addEventListener(‘dragenter’, function(e){ e. preventDefault(); }, false);

Databox. addEventListener(‘dragover’, function(e){ e. preventDefault(); }, false);

Databox. addEventListener(‘drop’, dropped, false);

}

Function dropped(e){ e. preventDefault(); var files=e. dataTransfer. files; if(files. length){ var list=»;

For(var f=0;f<files. length;f++){ var file=files[f];

List+=’<blockquote>Файл: ‘+file. name; list+=’<br><span><progress value="0" max="100">0% </progress></span>’; list+=’</blockquote>’;

Var count=0;

Var upload=function(){ var file=files[count]; var data=new FormData(); data. append(‘file’,file); var url="process. php"; var request=new XMLhttpRequest(); var xmlupload=request. upload;

Xmlupload. addEventListener(‘progress’,function(e){ if(e. lengthComputable){ var child=count+1;

Var per=parseInt(e. loaded/e. total*100); var progressbar=databox. querySelector(

"blockquote:nth-child("+child+") > span > progress"); progressbar. value=per; progressbar. innerHTML=per+’%';

}

},false);

Xmlupload. addEventListener(‘load’,function(){ var child=count+1; var elem=databox. querySelector(

"blockquote:nth-child("+child+") > span"); elem. innerHTML=’Готово!’;

Count++;

If(count<files. length){

Upload();

}

},false);

Request. open("POST", url, true); request. send(data);

}

Upload();

}

}

Понимаю, в этом коде нелегко разобраться с первого взгляда, поэтому предлагаю изучить происходящее шаг за шагом. Как всегда, все начинается с вызова функции initiate() — это происходит сразу же, как только завершается загрузка документа. Эта функция создает ссылку на элемент databox, который в нашем примере будет служить зоной приема файлов, и добавляет прослушиватели трех событий, позволяющих контролировать операцию перетаскивания. Для того чтобы вспомнить подробности работы с API перетаскивания, обратитесь к главе 8. Если коротко: событие dragenter срабатывает, когда при перетаскивании файлов указатель мыши оказывается над зоной приема, событие dragover срабатывает периодически, пока указатель мыши с файлами находится над зоной приема, а событие drop срабатывает, когда пользователь отпускает файлы на зоне приема. В этом примере мы никак не обрабатываем события dragenter и dragover, просто отменяем их, для того чтобы запретить действия браузера по умолчанию. Единственное событие, на которое мы реагируем, — это drop. Прослушиватель этого события вызывает функцию dropped() каждый раз, когда пользователь отпускает какой-либо объект над элементом databox.

В первой строке кода функции dropped() также используется метод preventDefault(). Это необходимо для того, чтобы мы могли самостоятельно обработать файлы, которые пользователь перетащил на зону приема, запретив браузеру выполнять над ними действия по умолчанию. Теперь, когда мы обеспечили полный контроль над ситуацией, настало время обработать файлы, попавшие в зону приема. Сначала мы извлекаем их из объекта dataTransfer. Возвращаемое данным объектом значение представляет собой массив файлов, и мы сохраняем его в переменной files. Для того чтобы убедиться, что в зону приема попали именно файлы (а не элементы другого типа), проверяем значение свойства length в условном операторе if(files. length). Если данное значение не равно 0 или null, значит, пользователь перетащил на зону приема один или несколько файлов и мы можем продолжать работу.

Теперь переходим к непосредственной обработке полученных файлов. В цикле for мы проходим по массиву файлов и создаем список элементов <blockquote>, содержащих заключенные в теги <span> имена файлов и соответствующие индикаторы прогресса. После того как создание списка завершено, результат выводится на экран внутри элемента databox.

Создается впечатление, что вся работа происходит в функции dropped(), но на самом деле внутри этой функции мы создали еще одну и назвали ее upload(). Она занимается процессом загрузки каждого из файлов на сервер. Таким образом, после вывода списка файлов на экран мы создаем эту функцию и вызываем ее для каждого файла в списке.

Функция upload() создается через анонимную функцию. Внутри нее мы выбираем файл из массива, используя в качестве индекса переменную count. При инициализации переменной ей присваивается значение 0, поэтому во время первого вызова функции upload() выбирается и загружается на сервер первый файл из списка.

Для загрузки каждого файла из списка мы прибегаем к тому же способу, что и во всех предыдущих примерах. Ссылка на файл сохраняется в переменной file, с помощью конструктора FormData() создается объект FormData, и файл добавляется к этому объекту посредством метода append().

На этот раз для управления процессом мы прослушиваем только два события: progress и load. При каждом срабатывании события progress вызывается анонимная функция, обновляющая индикатор прогресса для соответствующего загружаемого файла. Для идентификации элемента <progress>, связанного с этим файлом, применяется метод querySelector() с псевдоклассом :nth-child(). При этом индекс псевдокласса вычисляется на основе значения переменной count. Эта переменная содержит значение индекса для массива файлов, но диапазон индексов начинается с 0, а номера дочерних элементов, на которые ссылается :nth-child(), — с 1. Для того чтобы получить правильный номер и найти нужный элемент <progress>, мы добавляем к значению переменной count единицу, сохраняем результат в переменной child и используем это значение.

Каждый раз, когда описанный процесс завершается, нам необходимо информировать пользователя о ситуации и переходить к следующему файлу в массиве files. Для этой цели в анонимной функции, которая выполняется при срабатывании события load, мы увеличиваем на 1 значение переменной count, заменяем элемент <progress> строкой «Готово!» и снова вызываем функцию upload() на случай, если еще остались необработанные файлы.

Последовательно прочитав листинг 13.11, вы увидите, что после своего объявления функция upload() впервые вызывается в конце функции dropped(). Поскольку мы ранее инициализировали переменную count со значением 0, первым обрабатывается первый файл в массиве files. Затем, когда загрузка этого файла завершается, срабатывает событие load и происходит вызов анонимной функции для обработки данного события. Она, в свою очередь, увеличивает значение count на 1 и снова вызывает функцию upload() для обработки следующего файла в массиве

Array. Таким образом, все файлы, которые пользователь перетащил на зону приема, один за другим загружаются на сервер.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *