Tutorial

Создание перетаскиваемых элементов с помощью JavaScript без расширений и HTML

JavaScript

Введение

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

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

Так, HTML Drag and Drop API использует модель событий DOM для получения информации о перетаскиваемом элементе и обновления этого элемента после перетаскивания. С обработчиками событий JavaScript вы можете превратить любой элемент в перетаскиваемый элемент или в цель перетаскивания.

В этом обучающем модуле мы построим пример перетаскиваемого элемента, используя HTML Drag and Drop API с JavaScript без расширений для использования обработчиков событий.

Предварительные требования

Для данного обучающего руководства вам потребуется следующее:

  • Современный браузер с поддержкой Drag and Drop API (Chrome 4+, Firefox 3.5+, Safari 3.1+, Edge 18+).

Шаг 1 — Создание проекта и начальная разметка

Наш проект будет состоять из контейнера с двумя типами дочерних элементов:

  • Дочерние элементы, которые можно перетаскивать
  • Дочерние элементы, в которые могут быть перетащены элементы

Откройте окно терминала и создайте новый каталог проекта:

  • mkdir drag-and-drop-example

Затем перейдите в этот каталог:

  • cd drag-and-drop-example

Создайте в этом каталоге файл index.html:

  • nano index.html

Добавьте базовый код веб-страницы HTML:

index.html
<!DOCTYPE html>
<html>
  <head>
    <title>My Drag-and-Drop Example</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
  </body>
</html>

Добавьте между тегами <body> перетаскиваемый элемент draggable и элемент dropzone (цель перетаскивания):

index.html
<div class="example-parent">
  <div class="example-origin">
    <div
      id="draggable-1"
      class="example-draggable"
    >
      draggable
    </div>
  </div>

  <div
    class="example-dropzone"
  >
    dropzone
  </div>
</div>

Сохраните и закройте файл. Затем создайте файл style.css:

  • nano style.css

Добавьте стили элементов в файл index.html:

style.css
.example-parent {
  border: 2px solid #DFA612;
  color: black;
  display: flex;
  font-family: sans-serif;
  font-weight: bold;
}

.example-origin {
  flex-basis: 100%;
  flex-grow: 1;
  padding: 10px;
}

.example-draggable {
  background-color: #4AAE9B;
  font-weight: normal;
  margin-bottom: 10px;
  margin-top: 10px;
  padding: 10px;
}

.example-dropzone {
  background-color: #6DB65B;
  flex-basis: 100%;
  flex-grow: 1;
  padding: 10px;
}

При этом в приложение будет добавлено определенное форматирование. Теперь вы можете открыть файл index.html в браузере и увидеть элементы draggable <div> и dropzone <div>.

Снимок экрана с разделами draggable и dropzone

Затем мы явно сделаем первый <div> перетаскиваемым, добавив атрибут draggable:

index.html
<div class="example-parent">
  <div class="example-origin">
    <div
      id="draggable-1"
      class="example-draggable"
      draggable="true"
    >
      draggable
    </div>
  </div>

  <div
    class="example-dropzone"
  >
    dropzone
  </div>
</div>

Сохраните и закройте файл.

В заключение снова откройте файл index.html в браузере. Если мы нажмем на элемент draggable <div> и перетащим его через экран, потребуется визуальная индикация перемещения.

По умолчанию атрибут draggable имеет значение auto. Это означает, что поведение браузера по умолчанию определяет, является ли элемент перетаскиваемым. Обычно это значит, что выделенный текст, изображения и ссылки можно перетаскивать, не задавая draggable="true".

Теперь у нас есть файл HTML с перетаскиваемым элементом. Мы перейдем к добавлению обработчиков onevent.

Шаг 2 — Обработка событий Drag-and-Drop в JavaScript

Сейчас, если мы отпустим мышь при перетаскивании перетаскиваемого элемента, ничего не произойдет. Чтобы при перетаскивании элементов DOM активировалось действие, нам необходимо использовать Drag and Drop API:

  • ondragstart: этот обработчик событий прикрепляется к нашему элементу draggable и срабатывает при возникновении события dragstart.
  • ondragover: этот обработчик событий прикрепляется к нашему элементу dropzone и срабатывает при возникновении события dragover.
  • ondrop: этот обработчик событий прикрепляется к нашему элементу dropzone и срабатывает при возникновении события drop.

Примечание. Всего доступно восемь обработчиков событий: ondrag, ondragend, ondragenter, ondragexit, ondragleave, ondragover, ondragstart и ondrop. В нашем примере они требуются не все.

Вначале разместим ссылку на новый файл script.js в нашем файле index.html:

index.html
<body>
  ...
  <script src="script.js"></script>
</body>

Затем создадим новый файл script.js:

  • nano script.js

Объект DataTransfer будет отслеживать информацию, связанную с текущим перетаскиванием. Чтобы обновить наш элемент после перетаскивания, нам нужен прямой доступ к объекту DataTransfer. Для этого мы можем выбрать свойство dataTransfer события DragEvent элемента DOM.

Примечание. Объект DataTransfer технически может отслеживать информацию нескольких элементов, перетаскиваемых одновременно. В нашем примере мы ограничимся перетаскиванием одного элемента.

Метод setData объекта dataTransfer можно использовать, чтобы задать информацию о состоянии перетаскивания текущего элемента. Для этого нужны два параметра:

  • строка, декларирующая формат второго параметра
  • фактически перемещаемые данные

Наша цель — переместить элемент draggable в новый родительский элемент. Нам нужна возможность выбрать элемент draggable с уникальным идентификатором id. Мы можем задать id перетаскиваемого элемента с помощью метода setData, чтобы его можно было использовать позднее.

Давайте снова откроем файл script.js и создадим новую функцию для использования setData:

script.js
function onDragStart(event) {
  event
    .dataTransfer
    .setData('text/plain', event.target.id);
}

Примечание. Сообщается, что в версиях Internet Explorer с 9 по 11 возникают проблемы при использовании 'text/plain'. Для этих версий браузера следует использовать формат 'text'.

Чтобы обновить стили CSS перетаскиваемого элемента, мы можем снова получить доступ к его стилям, используя событие DOM, и установив желаемые стили для currentTarget.

Дополним нашу функцию и изменим значение backgroundColor на yellow:

script.js
function onDragStart(event) {
  event
    .dataTransfer
    .setData('text/plain', event.target.id);

  event
    .currentTarget
    .style
    .backgroundColor = 'yellow';
}

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

Теперь у нас есть функция JavaScript для начала перетаскивания.

Мы можем добавить ondragstart в элемент draggable в файле index.html:

index.html
<div class="example-parent">
  <div class="example-origin">
    <div
      id="draggable-1"
      class="example-draggable"
      draggable="true"
      ondragstart="onDragStart(event);"
    >
      draggable
    </div>
  </div>

  <div class="example-dropzone">
    dropzone
  </div>
</div>

Откройте файл index.html в браузере. Если вы теперь попытаетесь перетащить элемент, будут применены стили, декларированные в нашей функции:

Анимированный файл gif, показывающий элемент, который перетаскивают, но не отпускают

Однако если отпустить элемент, ничего не произойдет.

Следующим в этой последовательности срабатывает обработчик событий ondragover.

Поведение определенных элементов DOM по умолчанию, в том числе <div> в браузерах, обычно не принимает отпускание. Такое поведение перехватит поведение, которое мы пытаемся реализовать. Чтобы гарантированно получить желаемое поведение при отпускании, мы применим preventDefault.

Давайте снова откроем файл script.js и создадим новую функцию для использования preventDefault: Добавьте в конец файла следующий код:

script.js
function onDragOver(event) {
  event.preventDefault();
}

Теперь мы можем добавить ondragover в элемент dropzone в файле index.html:

index.html
<div class="example-parent">
  <div class="example-origin">
    <div
      id="draggable-1"
      class="example-draggable"
      draggable="true"
      ondragstart="onDragStart(event);"
    >
      draggable
    </div>
  </div>

  <div
    class="example-dropzone"
    ondragover="onDragOver(event);"
  >
    dropzone
  </div>
</div>

На этом этапе мы еще не написали код для обработки завершения перетаскивания. Последним в этой последовательности срабатывает обработчик событий ondrop.

Вернемся в файл script.js и создадим новую функцию.

Мы можем сослаться на ранее сохраненные данные, используя метод setData объекта dataTransfer. Мы будем использовать метод getData объекта dataTransfer. Мы задали данные id, и поэтому результат выполнения будет выглядеть так:

script.js
function onDrop(event) {
  const id = event
    .dataTransfer
    .getData('text');
}

Выберем элемент draggable с полученным id:

script.js
function onDrop(event) {
  // ...

  const draggableElement = document.getElementById(id);
}

Выберем элемент dropzone:

script.js
function onDrop(event) {
  // ...

  const dropzone = event.target;
}

Добавим элемент draggable в dropzone:

script.js
function onDrop(event) {
  // ...

  dropzone.appendChild(draggableElement);
}

Сбросим объект dataTransfer:

script.js
function onDrop(event) {
  // ...

  event
    .dataTransfer
    .clearData();
}

Теперь мы можем добавить ondrop в элемент dropzone в файле index.html:

index.html
<div class="example-parent">
  <div class="example-origin">
    <div
      id="draggable-1"
      class="example-draggable"
      draggable="true"
      ondragstart="onDragStart(event);"
    >
      draggable
    </div>
  </div>

  <div
    class="example-dropzone"
    ondragover="onDragOver(event);"
    ondrop="onDrop(event);"
  >
    dropzone
  </div>
</div>

Сделав это, мы завершили реализацию функции перетаскивания. Откройте файл index.html в браузере и перетащите элемент draggable в dropzone.

Анимированный файл gif, показывающий перетаскивание объекта в целевую зону

В нашем примере мы рассмотрели сценарий с одним перетаскиваемым элементом и одной целевой зоной. Мы можем использовать несколько перетаскиваемых элементов, несколько целей, и настроить все это с помощью других обработчиков событий Drag and Drop API.

Шаг 3 — Построение расширенного примера с несколькими перетаскиваемыми элементами

Приведем пример возможного использования этого API: список задач с перетаскиваемыми задачами, которые вы можете перетаскивать из столбца «Сделать» в столбец «Сделано».

Анимированный файл gif, показывающий перетаскивание нескольких задач в столбец «Сделано»

Чтобы создать собственный список задач, добавьте дополнительные перетаскиваемые элементы с уникальными id в файл index.html:

index.html
<div class="example-parent">
  <h1>To-do list</h1>
  <div class="example-origin">
    To-do
    <div
      id="draggable-1"
      class="example-draggable"
      draggable="true"
      ondragstart="onDragStart(event);"
    >
      thing 1
    </div>
    <div
      id="draggable-2"
      class="example-draggable"
      draggable="true"
      ondragstart="onDragStart(event);"
    >
      thing 2
    </div>
    <div
      id="draggable-3"
      class="example-draggable"
      draggable="true"
      ondragstart="onDragStart(event);"
    >
      thing 3
    </div>
    <div
      id="draggable-4"
      class="example-draggable"
      draggable="true"
      ondragstart="onDragStart(event);"
    >
      thing 4
    </div>
  </div>

  <div
    class="example-dropzone"
    ondragover="onDragOver(event);"
    ondrop="onDrop(event);"
  >
    Done
  </div>
</div>

Откройте index.html в браузере и перетащите элементы из столбца «Сделать» в столбец «Сделано». Вы создали приложение списка задач и протестировали его работу.

Заключение

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

Drag and Drop API предоставляет много разных возможностей настроить действия в дополнение к перетаскиванию. Например, вы можете обновлять стили CSS перетаскиваемых элементов. Также вместо перемещения вы можете копировать перетаскиваемый элемент так, чтобы при отпускании он реплицировался.

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

Чтобы узнать больше обо всех элементах, которые вы можете перетаскивать с помощью Drag and Drop API, ознакомьтесь с соответствующей документацией MDN.

Creative Commons License