Drag and drop загрузка файлов jquery

Is there a nice tidy jQuery plugin that allows including a single JS script then using a simple snippet to enable a form? Something like this:

With the upload target being the action of the form.

Any solution must not prevent a regular file field from being usable (using traditional browse method).

I only need one file at a time, though of course having the option for multiple isn’t a bad thing.

But the code there isn’t setup as a plugin. It’s probably not too difficult to change it, but also no point doing so if someone else has already done that work and is simply evading my Google searches.

I’m ideally looking for a pure HTML5/jQuery solution.
A Google Gears one is acceptable, but a Flash solution is not.

Известный факт, что поле для загрузки файлов трудно стилизовать так, как хочется разработчику. Многие просто скрывают его и добавляют кнопку, которая открывает диалог выбора файлов. Однако, теперь у нас появился даже ещё более модный способ обработки выбора файлов: drag and drop.

Технически это уже было возможно сделать, потому что большинство (если не все) реализации поля выбора файлов позволяли перетаскивать файлы для их выбора, но это требовало от вас показывать элемент с типом file . Итак, давайте по-настоящему использовать API, которое даёт нам браузер, для реализации выбора файлов через drag-and-drop и их загрузки на сервер.

В этой статье мы будем использовать чистый ES2015+ JavaScript (без фреймворков или библиотек) для выполнения этого проекта, и это предполагает, что у вас есть опыт работы с JavaScript в браузере. Этот пример — помимо ES2015+ синтаксиса, который можно легко изменить на синтаксис ES5 или транспилировать с помощью Babel — должен быть совместим со всеми вечнозелёными браузерами + IE 10 и 11.

Ниже можете видеть пример того, что должно получиться:

Первое, что мы должны обсудить, это события связанные с перетаскиванием, потому что они движущая сила этого функционала. В общем, есть восемь событий, срабатывающих в браузере и связанных с перетаскиванием: drag , dragend , dragenter , dragexit , dragleave , dragover , dragstart и drop . Мы не будем проходиться по ним всем, потому что события drag , dragend , dragexit и dragstart срабатывают на элементе, который перетаскивают, а это не наш случай, мы будем перетаскивать файлы из нашей файловой системы вместо DOM-элементов, так что эти события никогда не сработают.

Если вам стало интересно почитать об этих событиях, то вы можете изучить документацию связанную с ними на MDN.

Как и следовало ожидать, вы можете навесить обработчики для нужных событий таким же образом, каким происходит регистрация обработчиков большинства браузерных событий: с помощью addEventListener .

Ниже приведено небольшое описание того, что эти события делают. Используем dropArea из примера кода выше для того, чтобы сделать описание понятнее:

Событие dragenter — перетаскиваемый объект перетаскивается над dropArea , делая dropArea целью события drop , если пользователь перетащит его туда. Событие dragleave — перетаскиваемый объект перетащили за пределы dropArea на другой элемент, делая его целью события drop вместо dropArea . Событие dragover срабатывает каждые несколько сотен миллисекунд, пока объект перетаскивают над dropArea . Событие drop — пользователь отпустил кнопку мыши, перетаскиваемый объект перетащили на dropArea .

Стоит отметить, что при перетаскивании объекта над элементом, являющимся дочерним для dropArea , событие dragleave сработает над dropArea , а событие dragenter на дочернем элементе, потому что он становится target . Событие drop всплывёт до элемента dropArea (конечно, если до этого всплытие не остановит другой обработчик событий), таким образом событие сработает на dropArea , несмотря на то, что target у него будет другим.

Также обратите внимание, что для реализации пользовательского интерфейса с drag-and-drop, вам необходимо вызывать event.preventDefault() на каждом из слушателей этих событий. Если вы этого не сделаете, то браузер в конечном итоге откроет файл, который вы перетаскиваете, вместо того, чтобы отправить его в обработчик события drop .

До того как мы начнём добавлять функциональность drag-and-drop, нам надо добавить базовую форму со стандартным полем типа file . Технически это не обязательно, но рекомендуется предоставить такую альтернативу пользователям, чей браузер не поддерживает drag-and-drop API.

Довольно простая структура. Вы можете заметить обработчик события onchange на input . Посмотрим на него позже. Было бы также хорошей идеей добавить action к тегу form и кнопку submit , чтобы помочь людям, у которых выключен JavaScript. Затем можно использовать JavaScript для того, чтобы избавиться от них, почистить форму. В любом случае, вам понадобится серверный скрипт для загрузки файлов, неважно написан ли он собственными силами или вы используете сервис, такой как Cloudinary. Кроме этого, здесь нет ничего особенного, так что давайте набросаем стили:

Многие из этих стилей пока не используются, но это нормально. Основным моментом является то, что поле file скрыто, а его подпись label стилизована так, чтобы выглядеть как кнопка, таким образом люди поймут, что кликнув по нему вызовется диалог выбора файлов. Кроме того, мы следуем соглашению, согласно которому область, куда следует перетащить файл, обозначается пунктирной линией.

Теперь можем перейти к сладкому: drag and drop. Давайте напишем скрипт внизу страницы или в отдельном файле, смотря как вам больше нравится. Первое, что нам понадобится — это ссылка на область, куда предстоит тащить файл. Так мы сможем обрабатывать нужные нам события на ней:

Теперь давайте добавим сами события. Начнём с добавления обработчиков для всех событий, чтобы предотвратить поведение по умолчанию и остановить всплытие выше необходимого:

Теперь давайте добавим индикатор, который позволит пользователям понять, что они действительно перетаскивали элементы над нужной областью, используем CSS для изменения цвета границы области для перетаскивания. Стили уже описаны выше для селектора #drop-area.highlight , так что давайте используем JavaScript для добавления и удаления класса highlight , когда это необходимо.

Мы использовали оба события dragenter и dragover для подсвечивания области для перетаскивания по причинам, о которых я говорил ранее. Если вы начинаете перетаскивать непосредственно над dropArea и затем перешли на дочерний элемент, то сработает событие dragleave и подсвечивание области пропадёт. Событие dragover сработает после событий dragenter и dragleave , так что подсветка вернётся обратно на dropArea до того, как мы увидим, что она пропала.

Мы также убираем подсветку, когда перетаскиваемый элемент покидает обозначенную область и когда его перетаскивают в неё.

Теперь всё что нам нужно, это выяснить что делать, когда файлы будут перетащены:

Код выше не приближает нас к цели, но делает две важные вещи:

  1. Демонстрирует, как получить данные о файлах, которые перетащили.
  2. Приводит нас в то же место, что и поле input с типом file и обработчиком на событие onchange : handleFiles .

Помните о том, что files это не массив, а FileList . Таким образом, при реализации handleFiles , нам нужно преобразовать FileList в массив, чтобы более легко было его итерировать:

Это было скучно ( That was aniticlimactic). Перейдём к uploadFile , где будут действительно крутые штуки ( real meaty stuff).

Здесь мы используем FormData — встроенный браузерный API для создания форм с данными для отправки на сервер. Для этого мы используем fetch API, чтобы действительно отправить изображения на сервер. Убедитесь, что вы изменили URL для работы с вашим сервером или сервисом, с помощью formData.append можете добавить к форме любые дополнительные данные, которые могут потребоваться для работы с вашим сервером. Как альтернатива, если вы хотите поддерживать Internet Explorer, вы можете захотеть использовать XMLHttpRequest , это значит, что ваш uploadFile будет выглядеть так:

В зависимости от настроек вашего сервера, вы можете проверять различные значения status , отличные от 200 , но для наших нужд это сработает.

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

Есть несколько способов сделать это: вы можете ждать пока изображения загрузятся и запросить у сервера URL для картинок, но это означает что вам придётся ждать пока выполняется загрузка, а временами изображения могут быть довольно большими. Альтернатива, которую мы будет исследовать сегодня — это использовать FileReader API с данными файлов, которые мы получили из события drop . Это работает асинхронно, но вы можете использовать синхронную альтернативу FileReaderSync, но пользователи могут попробовать прочитать несколько больших файлов подряд, таким образом, это может заблокировать поток выполнения на длительное время и по-настоящему испортить впечатления пользователя от сервиса. Что же, давайте создадим функцию previewFile и посмотрим как это работает:

Здесь мы создали new FileReader и вызвали метод readAsDataURL для объекта File . Как уже упоминалось, это работает асинхронно, поэтому нужно добавить обработчик события onloadend для обработки результата чтения файла. После этого используем base64 URL для атрибута src нового элемента и добавляем его в элемент gallery . Есть только две вещи, которые надо сделать, чтобы всё было готово и работало: добавить элемент gallery и вызов функции previewFile .

Во-первых, добавим HTML, который приведен ниже, сразу после закрывающего тега form :

Ничего особенного, это просто div . Стили уже заданы для него и изображений в нём, так что больше здесь ничего делать не надо. Теперь изменим функцию handleFiles на следующую:

Есть несколько способов сделать это, например композиция или простой колбэк forEach , в котором запускается uploadFile и previewFile , и это тоже сработает. Таким образом, когда вы перетащите или выбираете несколько изображений, они будут показаны почти мгновенно ниже формы. Интересная мысль по этому поводу: в некоторых приложениях вы можете не захотеть действительно загружать изображения на сервер, а вместо этого хранить ссылки на них в localStorage или в каком-нибудь другом кеше на стороне пользователя, чтобы приложение имело к ним доступ позже. Я лично не могу придумать хорошие сценарии использования этого, но я готов поспорить, что такие есть.

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

Если что-нибудь занимает некоторое время, индикатор прогресса помогает пользователю понять, что процесс идёт, и показывает, как долго это что-нибудь будет выполняться. Добавить индикатора прогресса довольно легко благодаря HTML5 тегу progress . Давайте начнём с добавления его в HTML-код.

Вы можете вставить его сразу после элемента label или между элементами form и div для предпросмотра изображений, как больше нравится. Вообще, вы можете добавить его куда захотите в пределах тега body . Стили для этого примера не добавлены, так что будет отрисован браузерный элемент по умолчанию, который вполне пригоден. Теперь давайте добавим JavaScript. Сначала рассмотрим реализацию с использованием fetch , а затем покажем версию для XMLHttpRequest . Для начала нам понадобится пара новых переменных в верхней части скрипта:

При использовании fetch мы только можем определить, когда загрузка завершена, так что единственная информация, которую мы отслеживаем: сколько файлов выбрано для загрузки (переменная filesToDo ) и количество уже загруженных файлов (переменная filesDone ). Также мы храним ссылку на элемент #progress-bar , чтобы мы могли быстро обновлять его. Теперь давайте создадим пару функций для управления прогрессом:

Когда мы только начинаем загрузку, вызовем функцию initializeProgress для сброса состояния индикатора. Затем, с каждой выполненой загрузкой, мы вызываем функцию progressDone для увеличения числа загруженых файлов на единицу и обновления индикатора для демонстрации прогресса. Итак, добавим вызовы этих функций, обновив пару старых:

И на этом всё. Теперь пришло время посмотреть как будет выглядеть реализация с XMLHttpRequest . Мы могли бы просто сделать быстрое обновление в uploadFile , но XMLHttpRequest фактически даёт нам больше возможностей чем fetch , а именно: мы можем добавить обработчик события для отслеживания прогресса загрузки на каждом запросе, который будет периодически давать информацию о прогрессе. Исходя из этого, нам нужно отслеживать процентную готовность каждого запроса вместо количества выполненных запросов. Итак, давайте начнём с замены объявлений переменных filesDone и filesToDo на следующий код:

Тогда нам нужно обновить и наши функции. Переименуем progressDone в updateProgress и изменим её код как показано ниже:

Теперь initializeProgress инициализирует массив с длиной, равной numFiles , который заполнен нулями, означающими, что каждый файл загружен на 0%. В updateProgress мы видим какое из изображений обновляет свой прогресс и изменяем значение элемента с нужным индексом на предоставленный percent . Затем мы вычисляем общий процент выполнения как среднее среди всех процентов и обновляем индикатор прогресса, чтобы отобразить вычисленное значение. Мы по-прежнему вызываем initializeProgress в handleFiles также, как делали это в примере с fetch . Таким образом, всё что нам нужно, это обновить uploadFile , добавив вызов updateProgress .

Первое, что нужно отметить, это то, что мы добавили параметр i . Это индекс файла в списке файлов. Нам не нужно обновлять handleFiles для передачи этого параметра, потому что он использует forEach , который уже передаёт индекс элемента вторым параметром в колбэк. Также мы добавили слушатель события progress в xhr.upload , чтобы можно было вызвать updateProgress со значением прогресса. Объект события ( e в нашем коде) имеет два информативных поля: loaded — количество уже загруженных байтов, и total — общее количество байтов.

Выражение || 100 нужно потому, что иногда, при возникновении ошибки, e.loaded и e.total будут равны нулю, что значит, что вычисления с ними дадут NaN , таким образом 100 используется вместо отчёта о выполнении загрузки. Вы можете также использовать 0 . В любом случае ошибки будут отображаться в обработчике события readystatechange , и вы можете сообщить о них пользователю. Это сделано просто для предотвращения исключений, связанных с попытками вычислений с NaN .

Примечание редактора: Такой подход к подавлению ошибок не очень правильный, и, к тому же, приводит к скачкам индикатора загрузки. Гораздо надёжнее заранее проверить значения на корректность и в случае ошибки не менять значение индикатора загрузки.

Это последняя часть. Теперь у нас есть страница, на которой можно загружать изображения с помощью drag and drop, есть мгновенный предпросмотр изображений и отображение прогресса загрузки с помощью индикатора. Вы можете посмотреть окончательную версию (с использованием XMLHttpRequest ) в действии на CodePen, но помните, что сервис, через который я загружаю файлы, имеет ограничения, и если много людей будут его использовать одновременно, то он может быть недоступен некоторое время.

Drag and drop is a simple way to allow users to upload their files by dropping to the container. Nowadays most websites allow uploading using both drag and drop and the file browse e.g. PushBullet, Facebook, SlideShare, etc.

I am using AJAX to save the file to the server which triggers when the file dropped on the target container.

In this tutorial, I show how you can implement a similar type of feature in your project and which show thumbnail when the file successfully uploaded.

Contents

1. HTML

I am using this

Completed Code

2. CSS

3. PHP

Create a new upload directory and upload.php file.

Use upload directory to store files and also added default.png image which uses as an thumbnail for non-image type file.

Upload file to upload directory and check file is image or not. If image then assign $location to $src .

Initialize $return_arr Array with file name, size, and location.

Return JSON response.

Completed Code

4. jQuery

The below code stop the page from redirect when the file drop on the page.

This removes page default functionality.

Drag & Drop

When the file is dropped on

Using append() method to store the file in FormData variable.

Passing FormData Object variable in uploadData() function.

From where send AJAX request and using FormData variable as data. When the AJAX successfully callback, passing the response to addThumbnail() function which creates a new thumbnail and shows its information (name and size).

If the uploaded file is an image then show its image otherwise show the default image.

Click

When the user clicks on the upload area then fire the click event on the file element ( >

Completed Code

5. Conclusion

I showed how you implement drag and drop file upload functionality in your project and I didn’t add any type of restriction while uploading the file in PHP which you can add as per your requirement.

If you found this tutorial helpful then don’t forget to share.


[an error occurred while processing the directive]
Карта сайта