Drag and Drop загрузка файлов на сервер

Drag and Drop загрузка файлов на сервер

От автора: данная статья написана нашим гостем Osvaldas Valutis. Osvaldas расскажет нам не только про drag and drop загрузку файлов на сервер, но и затронет тему UI и UX, поддержки браузеров, а также покажет, как реализовать данную загрузку с помощью метода прогрессивного улучшения.

Сейчас я работаю над RSS ридером Readerrr. И передо мной стояла задача разнообразить обычный способ добавления файлов через input, я хотел реализовать drag and drop модель. Иногда такой способ намного удобнее, разве не так?

Демо

Разметка

В разметке нет ничего особенного. Она обычная, просто тег form, хотя присутствуют также блоки с потенциальными состояниями.

Пока блоки состояний нам не нужны, они прячутся:

Разбираем код:

По состояниям: .box__uploading отображается во время загрузки файла через Ajax (все остальные блоки состояний скрыты). Затем в зависимости от результата загрузки отображаются .box__success или .box__error.

input[type=»file»] и label – функциональные элементы формы. В статье настройка input’ов типа file я описывал, как можно их стилизовать. Также в той статье я рассказывал, зачем нужен атрибут [data-multiple-caption]. Input и label служат альтернативой обычному способу выбора файлов (или единственный способ, если drag and drop не поддерживается).

.box__dragndrop отображается, если браузер поддерживает drag and drop.

Обнаружение свойств

Мы не можем 100% полагаться на поддержку в браузере drag and drop. Необходимо обеспечить фолбек, в этом нам поможет метод обнаружения поддерживаемых свойств. В основе метода drag and drop лежат множество различных JavaScript API, необходимо проверить их все.

Сначала само событие drag & drop. Работу по обнаружению поддерживаемых свойств можно с уверенностью доверить библиотеке Modernizr. Ниже тест события:

Далее необходимо проверить FormData интерфейс. Данный интерфейс формирует программный объект выбранного файла (ов), после чего он (и) могут быть отправлены на сервер через Ajax:

Также необходимо проверить объект DataTransfer. Тут немного хитрый метод проверки, так как не существует еще стопроцентного способа проверки на поддержку данного объекта до того, как пользователь не начнет взаимодействовать с drag and drop интерфейсом. Не все браузеры поддерживают объект. Вообще, необходимо избегать таких UX моментов типа:

«Перетащи файл сюда!»

Пользователь перетащил и отпустил файл и

«Опа, я пошутил, такая функция не поддерживается.»

Основная задача успеть проверить поддержку FileReader API в момент загрузки документа. Смысл в том, что если браузер поддерживает FileReader, то и DataTransfer он тоже поддерживает:

Добавим код выше в анонимную самовызывающуюся функцию…

…с ее помощью можно четко определить поддержку свойств:

С полностью рабочим методом обнаружения поддерживаемых свойств, мы можем сказать пользователю, может ли он воспользоваться drag and drop или нет. В случае поддержки к форме можно добавить специальный класс, чтобы потом стилизовать форму:

Не беда если drag & drop не поддерживается. Пользователи могут загружать файлы через старый добрый input[type=»file»]!

Обратите внимание: в Microsoft Edge есть баг, после которого drag & drop не работает. Разработчики вроде бы уже знают о нем, и работают над исправлением.

Drag ‘n’ Drop

А теперь займемся делом. В этой части мы будем добавлять к форме или удалять специальные классы состояний типа, когда пользователь держит элемент над формой. Когда пользователь будет отпускать кнопку мыши, мы будем ловить данные файлы.

e.preventDefault() и e.stopPropagation() предотвращают любые нежелательные действия конкретных событий в браузере.

e.originalEvent.dataTransfer.files возвращает список файлов. Позже я покажу, как использовать эту информацию для отправки файлов на сервер.

С помощью класса .is-dragover мы будем указывать пользователю, когда можно отпустить файлы:

Стандартный способ выбора файлов

Иногда drag & drop не самый удобный способ выбора файлов. Особенно если у пользователя маленький экран. А значит, необходимо дать пользователю выбор между различными методами загрузки. В этом нам поможет input типа file и label. Стилизовав их описанным мной способом, можно сохранить целостность дизайна:

Ajax загрузка

Не существует полностью кроссбраузерного способа реализовать drag & drop без Ajax. Некоторые браузеры (IE и Firefox) не позволяют устанавливать значение в input’ах типа file, которые потом могут отправляться на сервер. Код ниже не работает:

Вместо кода выше после отправки формы необходимо использовать Ajax:

У класса .is-uploading двойное значение: он предотвращает повторную отправку формы (return false), а также показывает пользователям процесс отправки формы:

Ajax для современных браузеров

Если бы в форме не было загрузки файлов, то нам бы и не понадобилось два разных Ajax способа. Но к сожалению, в IE9 и ниже не поддерживается загрузка через XMLHttpRequest.

Чтобы понять, какой метод поддерживается, можно воспользоваться нашим готовым тестом isAdvancedUpload. Так как если браузер поддерживает то, о чем я писал выше, то он будет поддерживать загрузку через XMLHttpRequest. Код ниже работает в IE10+:

FormData($form.get(0)) собирает данные из всех input’ов.

Цикл $.each() пробегается по всем сброшенным файлам. ajaxData.append() добавляет эти файлы в стек для отправки через Ajax.

data.success и data.error – JSON строки с результатом выполнения, возвращенные сервером. Ниже показано, как это будет выглядеть на PHP:

Ajax для старых браузеров

Метод для IE9-. Нам не нужно собирать drag & drop файлы (isAdvancedUpload = false), так как данный метод не поддерживается браузером. Форма работает через input[type=»file»]. Как ни странно, динамическая вставка iframe работает:

Автоматическая отправка файлов

Если в вашей форме только drag & drop поле или input типа file, для удобства пользователя можно сделать, чтобы файлы автоматически загружались на сервер без нажатия на кнопку отправить. Для этого необходимо вручную запустить событие submit:

Если хорошо спроектировать область drag & drop (пользователю будет очевидно, что от него хотят), можно вообще скрыть кнопку отправки (иногда, чем меньше интерфейса, тем лучше). Но будьте осторожны. Если по каким-то причинам JavaScript отключен, кнопка должна быть видимой (прогрессивное улучшение!). Чтобы понять, включен ли JS, можно воспользоваться классом .no-js в теге html:

Отображение выбранных файлов

Если вы не используете метод автоотправки файлов на сервер, то необходимо показать пользователю, что он успешно выбрал файлы для загрузки:

Когда JavaScript отключен

Основной принцип прогрессивного улучшения в том, что пользователь должен любым способов закончить принципиальную задачу, неважно каким. И загрузка файлов не исключение. Если по каким-либо причинам JavaScript не доступен, интерфейс должен выглядеть так:

При нажатии на кнопку отправки формы, страница обновится. Так как JS отключен, то с его помощью нельзя показать результат отправки. Тут необходимо положиться на сервер. Ниже показан пример:

И немного правок в разметке:

Вот и все! Эта и так долгая статья могла быть еще длиннее. Но я думаю, этого вполне хватит, чтобы вы начали использовать адаптивную drag & drop загрузку в своих проектах. Чтобы более подробно ознакомиться с принципом работы, изучите демо (в исходниках можно посмотреть no-jQuery зависимости).

Автор: Osvaldas Valutis

Источник: //css-tricks.com/

Редакция: Команда webformyself.

Метки:

Похожие статьи:

Комментарии Вконтакте:

Комментарии (1)