Тарифы Услуги Сим-карты

Красивая AJAX форма для загрузки файлов. HTML5: загрузка файлов с помощью Drag & Drop Работа с загруженными файлами

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

Решение

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

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("");

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.

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

Dropzone.JS это замечательная опенсурс библиотека написанная на ванильном JS предоставляющая вам интерфес для загрузки файлов drag and drop с предварительным просмотром файлов.

Для начала скачайте свежую версию библиотеки и её стили:

Затем создайте папку uploads и файлы index.php и upload.php

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

Как вы наверное заметили мы создали форму с экшеном upload.php, но не создавали никаких инпутов для прикрепления файлов, и не объявляли enctype формы. В этом нет никакой ошибки, все обрабатывается самой библиотекой DropzoneJS. Все, что нам нужно сделать, это присвоить форме класс dropzone. По умолчанию DropzoneJS находит все формы с данным классом и автоматически потрисовывет свой интерфейс.

Вы пожете открыть на исполнение в браузете страницу index.php и убедиться что библиотека срабатывает как задумано. Вот что у меня получилось:

Теперь давайте создадим обработчик загрузки для которого мы уже создали файл upload.php. Привожу пример моего простейшего кода загрузки:

Работа с загруженными файлами

Для полноценного взаимодействия с вашими фалами, нам осталась добавить возможность манипулировать ими. Для начала нам нужно добавить фрагмент кода для извлечения информации о хранящихся файлах (имя и размер) и вернуть его в формате JSON.

Для этого обновляем файл upload.php до такого вида (вставлено условие else):

  • Функция PHP scandir просматривает папку uploads и возращает массив файлов или значение FALSE елси папка пуста.
  • Перебираем возвращаемое значение из функции scandir и сохраняем в массив $ result. Помните, мы игнорируем "." И "..", поскольку scandir всегда будет возвращать "." И ".." в качестве допустимого содержимого, относящегося к текущему и предыдущему каталогу.
  • Выводим правильные заголовки для разметки JSON, а также конвертируем PHP-массив в JSON-строку, используя функцию json_encode.
  • Теперь пришло время обновить index.php:

    Dropzone.options.myDropzone = { init: function() { thisDropzone = this; $.get("upload.php", function(data) { $.each(data, function(key,value){ var mockFile = { name: value.name, size: value.size }; thisDropzone.options.addedfile.call(thisDropzone, mockFile); thisDropzone.options.thumbnail.call(thisDropzone, mockFile, "uploads/"+value.name); }); }); } };

    Что мы тут накодили? Давайте разбиратся:

  • Увы и ах, мы добавили библиотеку Jquery на нашу страницу. Это на самом деле не необходимость для DropzoneJs. Мы используем только ajax-функцию JQuery $ .get. Вы же на своё усмотрение можете реализовать подобные запросы на vue.js или что вам больше по душе.
  • Мы добавили в форму элемент ID (my-dropzone). Это необходимо, для того что бы передать значения конфигурации в Dropzone. И для этого мы должны иметь уникальный индификатор указывающий на него. Таким образом мы можем настроить библиотеку, присвоив значения Dropzone.options.myDropzone.
  • Инициализируем основную часть редактирования. То, что мы здесь сделали, - передали функцию прослушивания события init Dropzone. Это событие вызывается, когда Dropzone инициализируется.
  • Получаем массив файлов из «upload.php» посредством ajax.
  • Создаём mockFile, используя значения с сервера. MockFile - это просто объекты JavaScript со свойствами имени и размера. Затем мы явно вызываем функции Dropbox и добавляем иконки, чтобы поместить существующие файлы в область загрузки Dropzone и создать их миниатюры.
  • Если вы сделали всё корректно. Загрузите несколько изображений и перезагрузите страницу с формой. Ранее загруженные файлы должны автоматически отображаться в области Dropzone.

    Продолжаем создавать нашу 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 и отменяем поведение по-умолчанию. Если мы этого не сделаем, то наш файл просто откроется в браузере, чего нам не нужно.

    Для начала, конечно, понадобиться создать элемент, который будет «ловить» файл. Кроме того, поместим в этот элемент span-тег для вывода сообщений о состоянии загрузки и input с типом file , чтобы не ограничивать выбор файла лишь перетаскиванием, а так же дать возможность пользователям выбрать файл нажатием на эту обозначенную область. Конечный вид такой структуры представлен ниже.

    Нажмите сюда или перетащите файл для загрузки.

    CSS к данному HTML коду ничем не примечателен, за исключением оформления поля input :

    #file{ width:100%; height:100%; display:block; position:absolute; top:0; left:0; opacity:0.01; }

    Так же описываем два класса, которые при добавлении к области «захвата» файла будут сигнализировать об успешной загрузке файла или же об ошибке, при возникновении таковой:

    #drop-zone.success{ background-color:#2ecc71; } #drop-zone.error{ background-color:#e74c3c; }

    Теперь можем перейти к написанию «экшена» нашей страницы. Для начала запишем в переменные ссылки на объекты, к которым будем достаточно часто обращаться:

    Var dropZone = document.getElementById("drop-zone"); var msgConteiner = document.querySelector("#drop-zone .text");

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

    Var eventClear = function (e) { e.stopPropagation(); e.preventDefault(); } dropZone.addEventListener("dragenter", eventClear, false); dropZone.addEventListener("dragover", eventClear, false);

    DropZone.addEventListener("drop", function (e) { if(!e.dataTransfer.files) return; e.stopPropagation(); e.preventDefault(); sendFile(e.dataTransfer.files); }, false); document.getElementById("file").addEventListener("change", function (e) { sendFile(e.target.files); }, false);

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

    Эта функция отвечает за передачу файла серверу. Ее описание можете увидеть ниже.

    Var sendFile = function(file) { // удаляем классы состояния, которые могли быть добавлены // если пользователь уже пытался что либо загрузить dropZone.classList.remove("success"); dropZone.classList.remove("error"); // делаем проверку при помощи регулярного выражения на тип файла // (в примере только изображения допускаем к загрузке) var re = /(.jpg|.jpeg|.bmp|.gif|.png)$/i; if (!re.exec(file.name)) { msgConteiner.innerHTML = "Недопустимый формат файла!"; dropZone.classList.remove("success"); dropZone.classList.add("error"); } else { var fd = new FormData(); // создание объекта формы fd.append("upfile", file); // добавление файла в форму отправки var xhr = new XMLHttpRequest(); xhr.open("POST", "./upload.php", true); xhr.upload.onprogress = showProgress; xhr.onreadystatechange = statChange; xhr.send(fd); // отправка на сервер } }

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

    Var showProgress = function(e) { if (e.lengthComputable) { // расчет процента загрузки var percent = Math.floor((e.loaded / e.total) * 100); // вывод текущего процента msgConteiner.innerHTML = "Загрузка... ("+ percent +"%)"; } }; var statChange = function (e) { if (e.target.readyState == 4) { // по завершению обработки запроса к серверу if (e.target.status == 200) { // если запрос выполнен успешно msgConteiner.innerHTML = "Загрузка успешно завершена!"; dropZone.classList.remove("error"); dropZone.classList.add("success"); document.getElementById("showUpFile").innerHTML = this.responseText; } else { // иначе msgConteiner.innerHTML = "Произошла ошибка!"; dropZone.classList.remove("success"); dropZone.classList.add("error"); } } }

    Завершающим этапом будет обработка получаемых сервером данных.