Как загружать файлы методом drag n drop. HTML5: загрузка файлов с помощью Drag-and-drop

This markup doesn"t have anything specifically to do with drag and drop. It"s just a normal, functional , albeit with some extra HTML elements for potential states.

Choose a file or drag it here. Upload Done! Error! .

We"ll hide those states until we need them:

Box__dragndrop, .box__uploading, .box__success, .box__error { display: none; }

A little explanation:

  • Regarding states: .box__uploading element will be visible during the Ajax process of file upload (and the others will still be hidden). Then .box__success or .box__error will be shown depending on what happens.
  • input and label are the functional parts of the form. I wrote about styling these together in my post about customizing file inputs . In that post I also described the purpose of attribute. The input and label also serve as an alternative for selecting files in the standard way (or the only way if drag and drop isn"t supported).
  • .box__dragndrop will be shown if a browser supports drag and drop file upload functionality.
Feature detection

We can"t 100% rely on browsers supporting drag and drop. We should provide a fallback solution. And so: feature detection . Drag & drop file upload relies on a number of different JavaScript API"s, so we"ll need to check on all of them.

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

Решение

Как видно из примера выше, файлы отправляются на сервер сразу же после выбора. Отправим их по событию:

Window.onload = function(){ var uploader = new qq.FileUploader({ autoUpload: false, element: document.getElementById("file-uploader"), action: "php/upload.php" }); $("#startUpload").on("click", function(){ uploader.uploadStoredFiles(); }); };

Результат

В целом у плагина много опций и настроек, имеются колбеки. Все это описано . Fineuploader находится в постоянной разработке, поэтому рекомендую при привязке посещать репозиторий и брать свежую версию.

Стилизация

Плагин создает свою структуру на базе класса.qq-uploader, все элементы описаны в css файле fileuploader.css

На заметку

Если ослы упорно отказываются работать, открываем скрипт, ищем там строку:

Var form = qq.toElement("");

и меняем на:

Var form = qq.toElement("");

Продолжаем создавать нашу drag and drop загрузку, а сегодня мы напишем наш сервер и начнём писать JavaScript код.

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

  • .htaccess
  • index.html
  • style.css
  • upload.php
  • uploads

С файлами index.html и style.css всё понятно. В файле .htaccess у нас просто прописана кодировка, чтобы не было проблем.

AddDefaultCharset UTF-8

Файл upload.php будет загружать файлы на сервер в папку uploads .

Итак, давайте начнём с php . Для этого откройте файл upload.php и пропишите следующее:

В начале файла мы прописываем заголовок Content-Type , чтобы сообщить браузеру, что он получит json . После создаём пустой массив $uploaded и проверяем, есть ли вообще какие-то файлы. Если да, то перебираем их и загружаем в нашу директорию uploads , а, также, заполняем наш главный массив $uploaded подмассивами, которые будут содержать информацию о файлах. В нашем случае это имя файла и его месторасположения . Наконец, мы преобразовываем наш массив в json и выводим его. Как видите, сервер вовсе несложный.

Теперь перейдём к файлу index.html


Перетащите файлы сюда

(function() {
var dropzone = document.getElementById("dropzone");
dropzone.ondragover = function() {
this.className = "dropzone dragover";
this.innerHTML = "Отпустите мышку";
return false;
};

Dropzone.ondragleave = function() {


return false;
};

Dropzone.ondrop = function(e) {
this.className = "dropzone";
this.innerHTML = "Перетащите файлы сюда";
e.preventDefault();
};
})();

Помните класс .dragover , который мы написали в прошлой статье, и я говорил, что он будет применяться, когда над нашим блоком будет какой-то файл? Вот, собственно, это мы сейчас и сделали. Когда над блоком появляется какой-то файл, срабатывает событие ondragover , где мы просто добавляем наш класс .dragover и меняем текст на "Отпустите мышку" . Когда же мы отводим мышку с файлом от нашего блока, то срабатываем событие ondragleave , где мы возвращаем всё в исходное положение. Когда человек "бросает" файл в наш блок, то срабатывает событие ondrop . Там мы снова всё меняем, как было в начале, иначе у нас "зависнет" класс .dragover и отменяем поведение по-умолчанию. Если мы этого не сделаем, то наш файл просто откроется в браузере, чего нам не нужно.

Приветствую всех! В этой статье хочу рассказать о нескольких своих экспериментах с HTML5. Начну издалека. Всем нам периодически приходится работать с различными web интерфейсами и часто возникает ощущение, что эта работа могла бы быть организована более эффективно.

Возможно, в каких-то случаях виноваты разработчики сервиса, но часто проблема заключается в ограничениях, которые накладывают браузеры. Рассмотрим загрузку файлов на сервер. В большинстве случаев вам предложат стандартное поле с кнопкой выбора файла с вашего компьютера и/или поле, в котором можно указать URL файла, размещенного где-нибудь в Сети.

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

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

Пример реализации такого интерфейса я покажу в этой статье. Если хотите, можете посмотреть, как он работает на демонстрационной страничке или .

Обратите внимание! Данный пример работает только в браузере Google Chrome. По-идее, поддержка всех необходимых технологий есть в Firefox и Safari, но с ними я пока не разбирался. В качестве объектов для «перетягивания» я брал в основном картинки с википедии. Было замечено несколько проблем связанных с не латинскими символами в URL картинок, но чтобы не перегружать пример проверками и преобразованиями я их оставил как есть.

Принцип работы

Стандарт HTML5 предусматривает поддержку «перетягивания» объектов страницы (Drag and Drop). Кстати, пример простейшей реализации D&D я уже показывал – Drag & Drop с использованием HTML5 . И, кроме того, есть довольно много JavaScript библиотек, реализующих поддержку D&D.

Но тут важно понимать, что если необходимо «перетягивать» картинки со сторонних ресурсов, то использовать библиотеки не получится. Т.к. вы не сможете добавить свой JS код на чужую страницу. А для того, чтобы загрузить картинку, нам нужно получить её URL, т.е. браузер должен вместе с перетягиваемым объектом передавать и его параметры (например, атрибут src картинки или весь тег img).

В этом случае мы можем создать на своей странице «приёмник» картинок. Это будет обычный div которому назначен обработчик события drop. Если пользователь «сбросит» картинку над этим div"ом, то будет вызван обработчик и в первом параметре он получит объект, содержащий информацию о перетягиваемой картинке.

Реализация

Начнём со страницы нашего приложения.

Images Upload


На ней размещены два блока: images – здесь будем показывать загруженные изображения и img_target – на этот блок нужно перетягивать картинки. Внизу страницы подключаем библиотеку jQuery и скрипт main.js, который будет отправлять информацию о перетянутых изображениях на сервер.

Рассмотрим main.js
$(function() {
$("#img_target")
.bind("dragenter", function(event) {
$(this).addClass("drop_here");
return false;
})
.bind("dragleave", function(event) {

return false;
})
.bind("dragover", function(event) {
return false;
})
.bind("drop", function(event) {
$(this).removeClass("drop_here");
var srcRegex = /src=\"([^\s]+)\"/ig;
var data = event.originalEvent.dataTransfer.getData("text/html");
var img_data = srcRegex.exec(data);
$.post("upload.php", {"file_url":img_data}, function(res) {
var response = eval("(" + res + ")");
$("#images").append($(""));
});
return true;
});
});
Здесь мы назначаем обработчики событиям dragenter, dragleave и dragover. Все они должны просто возвращать false и, чтобы как-то проинформировать пользователя о том, что можно «сбрасывать» картинку, в обработчике dragenter устанавливаем CSS класс drop_here для блока-приёмника. Основная часть работы выполняется в обработчике события drop. При возникновении этого события мы читаем информацию о «сброшенном» объекте и «вырезаем» значение атрибута src, т.е. URL картинки. Информация передается в объекте event.originalEvent.dataTransfer.

Затем формируем обычный AJAX запрос и в качестве параметра передаём ему найденный URL. Серверный скрипт (upload.php) получит URL изображения на удалённом сервере и загрузит его. А в ответе на AJAX запрос он отправит новый URL загруженной картинки. В свою очередь, обработчик AJAX-запроса создаст тег img и вставит его в блок images. Таким образом, загруженные картинки будут появляться над полем загрузки.

Рассмотрим upload.php

Принцип работы следующий. Читаем URL картинки и пытаемся её загрузить. Если картинка загружена, сохраняем её в папку upload. Получение картинки с удалённого сервера осуществляется с помощью функций fread. Файл читаем блоками по 1кБ. Такой подход позволяет прервать загрузку файла, если его размер превышает заданный предел (в данном случае 300кБ).

После загрузки файла формируем для него URL и отправляем браузеру в формате JSON. Как видите, реализовать такой загрузчик несложно. И пользоваться им достаточно удобно. Естественно, основным недостатком является поддержка HTML5 браузерами, точнее её отсутствие Тем не менее, если вы создаёте интерфейс для сотрудников какой-нибудь компании, и можете оговорить тип браузера, то HTML5 вполне можно использовать.

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

Мы будем использовать плагины jQuery File Upload и jQuery Knob для отображения .

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

HTML

Как обычно, начнем с HTML5 разметки:

Mini Ajax File Upload Form Drop Here Browse

В теге нашего документа, подключаем шрифты Google Webfonts, а перед закрытием тега — JavaScript библиотеки: jQuery, jQuery Knob и jQuery File Upload.

Главный элемент страницы — форма #upload . Внутри нее элемент #drop (принимает файлы с использованием drag&drop) и список, в котором будут отображаться загружаемые файлы. Разметка, которая будет генерироваться для загруженных файлов:

  • Sunset.jpg 145 KB

  • Элемент input будет спрятан с помощью CSS. Он нужен для инициализации плагина jQuery Knob, который будет рисовать файла. Input имеет атрибуты data-* , которые используются для обновления шкалы. Позже, когда мы будет отслеживать прогресс загрузки, мы будем обновлять эти значения для перерисовки шкалы. span будет содержать зеленую галку или красный крест.

    jQuery

    У посетителя будет 2 способа загрузки файла:

    • Перетащить файл в окно браузера (в IE не работает).
    • Нажатием на кнопку browse. Будет имитировано нажатие на спрятанный input и показано системное окно выбора файлов. Обратите внимание, что input имеет параметр multiple параметр, что позволит выбирать много файлов за один раз.

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

    $(function(){ var ul = $("#upload ul"); $("#drop a").click(function(){ // имитация нажатия на поле выбора файла $(this).parent().find("input").click(); }); // инициализация плагина jQuery File Upload $("#upload").fileupload({ // этот элемент будет принимать перетаскиваемые на него файлы dropZone: $("#drop"), // Функция будет вызвана при помещении файла в очередь add: function (e, data) { var tpl = $("

  • "); // вывод имени и размера файла tpl.find("p").text(data.files.name) .append("" + formatFileSize(data.files.size) + ""); data.context = tpl.appendTo(ul); // инициализация плагина jQuery Knob tpl.find("input").knob(); // отслеживание нажатия на иконку отмены tpl.find("span").click(function(){ if(tpl.hasClass("working")){ jqXHR.abort(); } tpl.fadeOut(function(){ tpl.remove(); }); }); // Автоматически загружаем файл при добавлении в очередь var jqXHR = data.submit(); }, progress: function(e, data){ // Вычисление процента загрузки var progress = parseInt(data.loaded / data.total * 100, 10); // обновляем шкалу data.context.find("input").val(progress).change(); if(progress == 100){ data.context.removeClass("working"); } }, fail:function(e, data){ // что-то пошло не так data.context.addClass("error"); } }); $(document).on("drop dragover", function (e) { e.preventDefault(); }); // вспомогательная функция, которая форматирует размер файла function formatFileSize(bytes) { if (typeof bytes !== "number") { return ""; } if (bytes >= 1000000000) { return (bytes / 1000000000).toFixed(2) + " GB"; } if (bytes >= 1000000) { return (bytes / 1000000).toFixed(2) + " MB"; } return (bytes / 1000).toFixed(2) + " KB"; } });

    В jQuery File Upload есть собственный интерфейс, но мы используем базовую версию плагина для создания собственного дизайна интерфейса. И чтобы наш интерфейс работал, мы передаем плагину несколько параметров / колбэков:

    • dropZone – этот параметр содержит jQuery селектор, который будет принимать перетаскиваемые файлы. Файлы, брошенные на него, будут добавлены в очередь загрузки.
    • add – функция вызывается при добавлении файла в очередь загрузки. Она будет генерировать разметку для файлов и вызвать метод data.submit() .
    • progress – Эта функция будет вызываться каждые 100ms (можно изменить). Второй аргумент содержит размер файла и количество загруженных байт. Это позволяет отслеживать прогресс и обновлять шкалу.
    • fail – функция вызывается при возникновении ошибки.
    PHP

    В комплект jQuery File Upload входит также и PHP скрипт для обработки файлов на сервере, но мы напишем свой. Процесс загрузки фалов будет происходить также как и при обычной загрузке, поэтому всю информацию о них мы можем получить из глобального массива $_FILES: