Как сделать форму Drag-and-Drop у себя на сайте
easy

Как сделать форму Drag-and-Drop у себя на сайте

Добавляем загрузку файлов на страницу

В прошлый раз мы рассказали, что такое Drag-and-drop и как работает такая форма загрузки файлов на сайт. Сегодня мы сделаем такую форму на своём сайте.

Как сделать форму Drag-and-Drop у себя на сайте

Что делаем

Форма Drag-and-Drop позволяет загружать файлы на сайт путём перетаскивания их в специальную область на экране. С такой формой интерфейс удобнее, чем с кнопкой «Обзор», по нажатию которой открывается проводник всех файлов на компьютере. Но на всякий случай мы добавим и такую кнопку. Пока что займёмся визуальной составляющей:

  1. Подготовим страницу к тому, чтобы она умела принимать файлы перетаскиванием.
  2. Придадим этому процессу симпатичный внешний вид.
  3. Научим страницу обрабатывать файлы и отправлять на нужный сервер.

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

Чтобы сделать форму Drag-and-drop, нам понадобятся:

  • HTML-страница с нужными элементами.
  • CSS-стили, чтобы форма выглядела симпатично.
  • Код JavaScript для взаимодействия элементов между собой и связки формы с сервером.

Всё это мы сохраним в отдельных файлах в одной папке. Так страница будет знать, откуда что брать.

Делаем страницу с формой

Создадим стандартный HTML-файл:

<!DOCTYPE html>
<html lang="ru">

<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title>Форма Drag-and-Drop</title>
	<link rel="stylesheet" href="style.css">
</head>

<body>
</body>
</html>

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

Чтобы добавить форму загрузки, используем тег <div> — он создаст блок внутри страницы, с которым мы будем работать дальше. Ещё нам понадобится указать id, чтобы к этому блоку мог обращаться код JavaScript, и класс для применения стилей CSS:

  <!-- общий класс для всего блока формы -->
  <div id="uploadFile_Loader" class="upload-zone">  
  </div>

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

    <!-- класс для формы отправки -->
    <form class="form-upload" id="uploadForm" method="post" enctype="multipart/form-data">

Наконец, наполним нашу форму нужными элементами:

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

Вот как это выглядит в коде:

     <!-- область для перетаскивания файлов -->
     <div class="upload-zone_dragover">
       <!-- текст внутри области для перетаскивания -->
       <p>Перетащите файл сюда</p>
     </div>
     <!-- кнопка отправки на сервер -->
     <button type="submit" class="form-upload__submit">Отправить</button>
     <!--  указываем, к какому элементу будет относиться подсказка для кнопки -->
     <label class="form-upload__label" for="uploadForm_file">
       <!-- текст подсказки для кнопки -->
       <span class="form-upload__title">Или выберите:</span>
       <!-- кнопка выбора файла -->
       <input class="form-upload__input" id="uploadForm_File" type="file" name="file_name">
     </label>
     <!-- кнопка отправки на сервер -->
     <button type="submit" class="form-upload__submit">Отправить</button>

Обратите внимание, как мы сделали кнопку для выбора файла:

  • Задали тег input, который обозначает элементы ввода.
  • Указали, что кнопка отвечает за загрузку файла (type="file").
  • Задали имя, которое получит сервер при отправке формы (name="file_name").

С кнопкой отправки всё проще, потому что мы пропишем её поведение в коде JavaScript.

В итоге получилась такая форма. Выглядит не очень — у нас пока нет дизайна:

Как сделать форму Drag-and-Drop у себя на сайте

Настраиваем стили

Чтобы форма выглядела лучше, настроим стили. Для этого создадим файл style.css, который потом подключим к нашей html-странице.

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

/* внешний вид всей области */
.form-upload {
  /* делаем область гибкой, подстраиваемой под ширину под ширину внутренних элементов */
  display: inline-flex;
  /* все элементы внутри выстраиваем в столбец */
  flex-direction: column;
  /* центрируем внутренние элементы по горизонтали */
  align-items: center;
  /* центрируем элементы по вертикали */
   justify-content: center;
  /* область занимает 100% ширины окна браузера */
  width: 100%;
  /* область занимает 100% высоты окна браузера */
  min-height: 100vh;
  /* внутренние отступы */
  padding: 16px;
}

Для удобства мы применяем модуль CSS, который называется Flexbox. Он позволяет блоку растягиваться под размеры внутренних элементов, экраны разных устройств и браузеров. Например, display: inline-flex — это Flexbox.

Наша страница немного преобразилась:

Как сделать форму Drag-and-Drop у себя на сайте

Теперь настроим область, в которую нужно перетаскивать файлы:

/* область для перетаскивания файлов */
.upload-zone_dragover {
  /* цвет фона */
  background-color: #1e96ff;
  /* форма подстраивается под размеры элементов */
  display: inline-flex;
  /* центрируем внутренние элементы по горизонтали */
  align-items: center;
  /* центрируем элементы по вертикали */
  justify-content: center;
  /* центрируем элементы по вертикали */
  justify-content: center;
  /* ширина */
  width: 450px;
  /* высота */
  height: 250px;
  /* внутренние отступы */
  padding: 16px;
  /* скругление рамки */
  border-radius: 10px;
  /* цвет текста */
  color: #ffffff;
  /* размер текста */
  font-size: 24px;
  /* тень с размытием */
  box-shadow: 3px 3px 4px rgba(0, 0, 0, 0.2);
}

Область для перетаскивания файлов стала симпатичнее:

Как сделать форму Drag-and-Drop у себя на сайте

Настроим область для подсказки к кнопке загрузки и саму кнопку:

/* зону с кнопкой и подписью к ней */
.form-upload__label {
  /* область занимает всю область элемента, внутри которого находится */
  display: flex;
  /* подпись над кнопкой */
  flex-direction: column;
  /* центрируем внутренние элементы по горизонтали */
  align-items: center;
}
/* подпись к кнопке */
.form-upload__title {
  /* размер шрифта */
  font-size: 16px;
  /* насыщенность шрифта */
  font-weight: 500;
  /* шрифт */
  font-family: Arial, sans-serif;
  /* отступ над текстом */
  margin-top: 8px;
  /* отступ под текстом */
  margin-bottom: 8px;
}

Настроим оформление для самой кнопки:

/* кнопка выбора файла */
.form-upload__label input[type="file"]::file-selector-button {
  /* убираем рамку */
  border: none;
  /* скругляем углы */
  border-radius: 8px;
  /* размер шрифта */
  font-size: 16px;
  /* шрифт и его цвет */
  font-family: Arial, sans-serif;
  color: #000000;
  /* внутренние отступы */
  padding: 8px 16px;
}

Получилось так:

Как сделать форму Drag-and-Drop у себя на сайте

Добавим класс, чтобы кнопка реагировала при наведении:

/* цвет кнопки при наведении на неё курсора */
.form-upload__label input[type="file"]::file-selector-button:hover {
  background-color: #FD7F4A;
}

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

Как сделать форму Drag-and-Drop у себя на сайте

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

/* шрифт названия файла */
.form-upload__input {
  /* выставляем шрифт и его размер */
  font-family: Arial, sans-serif;
  font-size: 16px;
}

Теперь так же оформим кнопку для отправки файлов на сервер.

/* стили для кнопки отправки формы */
button[type="submit"] {
  /* отступ над текстом */
  margin-top: 8px;
  /* цвет фона */
 background-color: #c4c4c4;
  /* цвет текста */
 color: white;
  /* внутренние отступы кнопки */
  padding: 12px 20px;
  /* убираем границу */
  border: none;
  /* добавляем скругление */
  border-radius: 8px;
  /* размер шрифта */
  font-size: 18px;
  /* шрифт */
  font-family: Arial, sans-serif;
  /*цвет шрифта */
  color: #000000;
}

/* стили для кнопки отправки формы при наведении */
button[type="submit"]:hover {
  /* цвет фона */
 background-color: #45a049;
}

Теперь кнопка отправки тоже меняет цвет, если навести на неё курсор мыши:

Как сделать форму Drag-and-Drop у себя на сайте

Добавим другой цвет для области загрузки во время перетаскивания файла в неё:

/* стили для состояния, когда над формой держат файл */
.upload-zone_dragover._active {
  /* цвет текста */
  color: #000000;
  /* цвет фона */
  background-color: #00ff51be;
}

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

Как сделать форму Drag-and-Drop у себя на сайте

Учим форму отправлять файлы на сервер

Создадим файл script.js. Сначала скрипту нужно объяснить, с какими элементами из HTML-файла мы будем работать. Для этого мы создадим переменные, в которые положим id из HTML-кода страницы.

// запоминаем область перетаскивания файла
const dropFileZone = document.querySelector(".upload-zone_dragover");
// запоминаем кнопку добавления файла
const uploadInput = document.querySelector(".form-upload__input");
// запоминаем кнопку отправки
const submitButton = document.querySelector('.form-upload__submit');

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

// записываем в переменную адрес, куда отправятся файлы после загрузки
const uploadUrl = "/unicorns";

Добавим обработчики событий. Это функции, которые будут говорить коду, что делать в конкретной ситуации. Сейчас добавим две: когда файл перетаскивают над формой и когда файл положили в форму.

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

// добавляем обработчики событий "dragover" и "drop" для документа
["dragover", "drop"].forEach(function (event) {
    // блокируем стандартное поведение браузера для события и возвращаем false
    document.addEventListener(event, function (evt) {
      evt.preventDefault();
      return false;
    });
   });

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

// добавляем обработчик события для входа в зону перетаскивания файла"
dropFileZone.addEventListener("dragenter", function () {
    // добавляем класс стиля, красим форму
    dropFileZone.classList.add("_active");
   });

    // добавляем обработчик события для выхода из зоны перетаскивания файла"
    dropFileZone.addEventListener("dragleave", function () {
      // возвращаем цвет неактивной формы"
      dropFileZone.classList.remove("_active");
   });

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

// добавляем обработчик события "drop" для зоны перетаскивания"
dropFileZone.addEventListener("drop", function () {
    // удаляем класс активности при сбросе файла
    dropFileZone.classList.remove("_active");
    // получаем первый файл в списке
    const file = event.dataTransfer?.files[0];
    // проверяем, что файл есть
    if (file) {
      // готовим файл к отправке
      uploadInput.files = event.dataTransfer.files;
    }
   });

// добавляем обработчик события для файлов, добавленных кнопкой"
uploadInput.addEventListener("change", (event) => {
    // получаем первый файл в списке
    const file = uploadInput.files?.[0];
    // проверяем, что файл есть
    if (file) {
      // готовим файл к отправке
      uploadInput.files = event.dataTransfer.files;
    }
   });

У нас есть кнопка отправки, но пока что наш код не знает, что делать при её нажатии. Исправляем это через последний обработчик события:

// добавляем обработчик события "click" для кнопки отправки
submitButton.addEventListener("click", function (event) {
     // блокируем стандартное поведение кнопки (отправку формы)
    event.preventDefault();
    // вызываем функцию для отправки файла
    processingUploadFile();
   });

Пишем функцию для отправки данных на сервер

Чтобы файл из формы отправился на сервер, а страница при этом не перезагрузилась, используют технологию XMLHttpRequest. Это специальный API для обмена данными между сервером и клиентом. Благодаря XMLHttpRequest обновляется только часть веб-страницы. Эта технология часто используется в одностраничных приложениях.

Логика такая:

  1. Файл из формы сохраняется для отправки.
  2. Выполняется запрос к серверу.
  3. Файл отправляется на сервер.
  4. Добавляются уведомление для пользователя о статусе загрузки.

Получается такая функция:

// функция для обработки загрузки файла
function processingUploadFile(file) {
  // проверяем, что файл был отправлен
  if (file) {
    // создаём объект для отправки данных формы
    const dropZoneData = new FormData();
    // создаём объект для отправки запроса на сервер
    const xhr = new XMLHttpRequest();

    // добавляем файл из формы в объект FormData
    dropZoneData.append("file", file);

    // открываем соединение с сервером
    xhr.open("POST", uploadUrl, true);

    // отправляем данные на сервер
    xhr.send(dropZoneData);

    // устанавливаем обработчик события onload для выполнения действий после завершения загрузки
      xhr.onload = function () {
      // проверяем статус ответа сервера
      if (xhr.status == 200) {
       // сообщаем об успехе в консоли"
       console.log("Всё загружено");
      } else {
       // соообщаем об ошибке в консоли"
       console.log("Ошибка загрузки");
      }
      // скрываем элемент
      HTMLElement.style.display = "none";
   };
 }
}

Что дальше

У нас получилась простая форма для загрузки файлов с помощью перетаскивания Drag-and-Drop. А вот что можно в ней улучшить:

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

А ещё, чтобы форма действительно отправляла файлы, нужна серверная часть. У нас её пока нет.

<!DOCTYPE html>
<html lang="ru">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Форма Drag-and-Drop</title>
<link rel="stylesheet" href="style.css">
</head>

<body>
  <div id="uploadFile_Loader" class="upload-zone">
    <form class="form-upload" id="uploadForm" method="post" enctype="multipart/form-data">
      <!-- область для перетаскивания файлов -->
      <div class="upload-zone_dragover">
        <!-- текст внутри области для перетаскивания -->
        <p>Перетащите файл сюда</p>
      </div>
      <!-- указываем, к какому элементу будет относиться подсказка для кнопки -->
      <label class="form-upload__label" for="uploadForm_file">
        <!-- подсказка для нажатия кнопки -->
        <span class="form-upload__title">Или выберите
        <!-- кнопка выбора файла -->
        <input class="form-upload__input" id="uploadForm_File" type="file" name="file_name">
        </span>
      </label>
      <!-- кнопка отправки на сервер -->
      <button type="submit" class="form-upload__submit">Отправить</button>
    </form>
  </div>
  <script src="script.js"></script>
</body>

</html>

/* внешний вид всей области */
.form-upload {
  /* область подстраиваится под ширину внутренних элементов */
  display: inline-flex;
  /* выстраиваем все элементы внутри в столбец */
  flex-direction: column;
  /* центрируем внутренние элементы по горизонтали */
  align-items: center;
  /* центрируем элементы по вертикали */
  justify-content: center;
  /* область занимает 100% ширины окна браузера */
  width: 100%;
  /* область занимает 100% высоты окна браузера */
  min-height: 100vh;
  /* выставляем внутренние отступы */
  padding: 16px;
}

/* область для перетаскивания файлов */
.upload-zone_dragover {
  /* цвет фона */
  background-color: #4061EA;
  /* форма подстраивается под размеры элементов */
  display: inline-flex;
  /* центрируем внутренние элементы по горизонтали */
  align-items: center;
  /* центрируем элементы по вертикали */
  justify-content: center;
  /* центрируем элементы по вертикали */
  justify-content: center;
  /* ширина */
  width: 450px;
  /* высота */
  height: 250px;
  /* внутренние отступы */
  padding: 16px;
  /* скругление рамки */
  border-radius: 10px;
  /* цвет текста */
  color: #ffffff;
  /* размер текста */
  font-size: 24px;
  /* тень с размытием */
  box-shadow: 3px 3px 4px rgba(0, 0, 0, 0.2);
}

/* область с кнопкой и подпись к ней */
.form-upload__label {
  /* область занимает всю область элемента, внутри которого находится */
  display: flex;
  /* подпись к кнопке */
  flex-direction: column;
  /* центрируем внутренние элементы по горизонтали */
  align-items: center;
}
/* подпись к кнопке */
.form-upload__title {
  /* размер шрифта */
  font-size: 16px;
  /* насыщенность шрифта */
  font-weight: 500;
  /* шрифт */
  font-family: Arial, sans-serif;
  /* отступ над текстом */
  margin-top: 8px;
  /* отступ под текстом */
  margin-bottom: 8px;
}

/* кнопка выбора файла */
.form-upload__label input[type="file"]::file-selector-button {
  /* убираем рамку */
  border: none;
  /* скругляем углы */
  border-radius: 8px;
  /* размер шрифта */
  font-size: 16px;
  /* шрифт и его цвет */
  font-family: Arial, sans-serif;
  color: #000000;
  /* внутренние отступы */
  padding: 8px 16px;
}

/* цвет кнопки выбора файла при наведении на неё курсора */
.form-upload__label input[type="file"]::file-selector-button:hover {
  background-color: #FD7F4A;
  }
  /* шрифт названия файла */
  .form-upload__input {
  /* шрифт */
  font-family: Arial, sans-serif;
  /* размер шрифта */
  font-size: 16px;
}

/* стили для кнопки отправки формы */
button[type="submit"] {
  /* отступ над текстом */
  margin-top: 8px;
  /* цвет фона */
  background-color: #c4c4c4;
  /* цвет текста */
  color: white;
  /* внутренние отступы */
  padding: 12px 20px;
  /* убираем границу */
  border: none;
  border-radius: 8px;
  /* размер шрифта */
  font-size: 18px;
  /* шрифт */
  font-family: Arial, sans-serif;
  /* цвет шрифта */
  color: #000000;
  /* курсор в виде указателя при наведении */
  cursor: pointer;
}

/* стили для кнопки отправки формы при наведении */
button[type="submit"]:hover {
  /* цвет фона кнопки при наведении */
  background-color: #D4FB51;
}

/* стили для состояния, когда над формой держат файл */
.upload-zone_dragover._active {
  /* цвет текста */
  color: #000000;
  /* цвет фона */
  background-color: #D4FB51;
}

// запоминаем область перетаскивания файла
const dropFileZone = document.querySelector(".upload-zone_dragover");
// запоминаем кнопку добавления файла
const uploadInput = document.querySelector(".form-upload__input");
// запоминаем кнопку отправки
const submitButton = document.querySelector('.form-upload__submit');
// записываем в переменную адрес, куда отправятся файлы после загрузки
const uploadUrl = "/unicorns";

// добавляем обработчики событий "dragover" и "drop" для документа
["dragover", "drop"].forEach(function (event) {
    // блокируем стандартное поведение браузера для события и возвращаем false
    document.addEventListener(event, function (evt) {
      evt.preventDefault();
      return false;
    });
   });

// добавляем обработчик события для входа в зону перетаскивания файла"
dropFileZone.addEventListener("dragenter", function () {
    // добавляем класс стиля, красим форму
    dropFileZone.classList.add("_active");
   });

    // добавляем обработчик события для выхода из зоны перетаскивания файла"
    dropFileZone.addEventListener("dragleave", function () {
      // возвращаем цвет неактивной формы"
      dropFileZone.classList.remove("_active");
   });

// добавляем обработчик события "drop" для зоны перетаскивания"
dropFileZone.addEventListener("drop", function () {
    // удаляем класс активности при сбросе файла
    dropFileZone.classList.remove("_active");
    // получаем первый файл в списке
    const file = event.dataTransfer?.files[0];
    // проверяем, что файл есть
    if (file) {
      // готовим файл к отправке
      uploadInput.files = event.dataTransfer.files;
    }
   });

// добавляем обработчик события для файлов, добавленных кнопкой"
uploadInput.addEventListener("change", (event) => {
    // получаем первый файл в списке
    const file = uploadInput.files?.[0];
    // проверяем, что файл есть
    if (file) {
      // готовим файл к отправке
      uploadInput.files = event.dataTransfer.files;
    }
   });

// добавляем обработчик события "click" для кнопки отправки
submitButton.addEventListener("click", function (event) {
     // блокируем стандартное поведение кнопки (отправку формы)
    event.preventDefault();
    // вызываем функцию для отправки файла
    processingUploadFile();
   });

// функция для обработки загрузки файла
function processingUploadFile(file) {
  // проверяем, что файл был отправлен
  if (file) {
    // создаём объект для отправки данных формы
    const dropZoneData = new FormData();
    // создаём объект для отправки запроса на сервер
    const xhr = new XMLHttpRequest();

    // добавляем файл из формы в объект FormData
    dropZoneData.append("file", file);

    // открываем соединение с сервером
    xhr.open("POST", uploadUrl, true);

    // отправляем данные на сервер
    xhr.send(dropZoneData);

    // устанавливаем обработчик события onload для выполнения действий после завершения загрузки
      xhr.onload = function () {
      // проверяем статус ответа сервера
      if (xhr.status == 200) {
       // сообщаем об успехе в консоли"
       console.log("Всё загружено");
      } else {
       // соообщаем об ошибке в консоли"
       console.log("Ошибка загрузки");
      }
      // скрываем элемент
      HTMLElement.style.display = "none";
   };
 }
}

Текст:

Игорь Росляков

Редактор:

Инна Долога

Обложка:

Алексей Сухов

Корректор:

Ирина Михеева

Вёрстка:

Маша Климентьева

Соцсети:

Юлия Зубарева

Вы фронтендер? Гляньте сюда ↓
У нас есть курсы по прокачке навыков до уровня middle и далее. Начать можно бесплатно. Посмотрите, интересно ли вам это.
Начать бесплатно
Вы фронтендер? Гляньте сюда ↓ Вы фронтендер? Гляньте сюда ↓ Вы фронтендер? Гляньте сюда ↓ Вы фронтендер? Гляньте сюда ↓
Получите ИТ-профессию
В «Яндекс Практикуме» можно стать разработчиком, тестировщиком, аналитиком и менеджером цифровых продуктов. Первая часть обучения всегда бесплатная, чтобы попробовать и найти то, что вам по душе. Дальше — программы трудоустройства.
Начать карьеру в ИТ
Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию
Еще по теме
easy