Drag and Drop API: dragstart, dragover, drop, dragend

Как работает Drag and Drop API? 🎯

Drag and Drop (DnD) — это не просто красивые анимации, а мощный инструмент для создания интерактивных интерфейсов. Представьте: вы можете перетаскивать файлы, карточки задач или даже целые блоки на странице. Давайте разберёмся, как это работает под капотом!


Основные события DnD 🧩

Вот ключевые события, которые вам нужно знать:

  1. dragstart — срабатывает, когда пользователь начинает перетаскивание элемента.
  2. dragover — вызывается, когда перетаскиваемый элемент находится над другим элементом.
  3. drop — происходит, когда элемент «бросают» в зону, которая принимает перетаскивание.
  4. dragend — завершает процесс перетаскивания (даже если элемент не был успешно «сброшен»).

💡 Совет: Для работы DnD нужно задать элементу атрибут draggable="true". Без этого браузер просто не поймёт, что элемент можно перетаскивать!


Практический пример: Перетаскиваемый список 📋

Давайте создадим простой список задач, который можно сортировать перетаскиванием.

HTML-разметка

<ul id="tasks">
  <li draggable="true">Купить молоко</li>
  <li draggable="true">Позвонить маме</li>
  <li draggable="true">Закончить проект</li>
</ul>

JavaScript: Настройка событий

const tasks = document.getElementById('tasks');

// Запоминаем перетаскиваемый элемент
let draggedItem = null;

// Начало перетаскивания
tasks.addEventListener('dragstart', (e) => {
  draggedItem = e.target;
  e.target.style.opacity = '0.5'; // Визуальный эффект
});

// Элемент над другим элементом
tasks.addEventListener('dragover', (e) => {
  e.preventDefault(); // Обязательно для работы drop!
});

// Сброс элемента
tasks.addEventListener('drop', (e) => {
  e.preventDefault();
  if (e.target.tagName === 'LI' && e.target !== draggedItem) {
    tasks.insertBefore(draggedItem, e.target.nextSibling || e.target);
  }
  draggedItem.style.opacity = '1';
});

// Завершение перетаскивания
tasks.addEventListener('dragend', () => {
  draggedItem.style.opacity = '1';
});

Как передавать данные при перетаскивании? 📦

Часто нужно передавать дополнительную информацию (например, ID элемента). Для этого используем DataTransfer:

// В dragstart
e.dataTransfer.setData('text/plain', e.target.id);

// В drop
const id = e.dataTransfer.getData('text/plain');
const element = document.getElementById(id);

⚠️ Важно: Браузеры могут обрабатывать только строковые данные. Для сложных объектов используйте JSON.stringify().


Стилизация при перетаскивании 🎨

Пользователь должен видеть, куда можно «бросить» элемент. Пример стилей для зоны drop:

.drop-zone {
  border: 2px dashed #ccc;
  padding: 20px;
}

.drop-zone.active {
  border-color: #4CAF50;
  background-color: rgba(76, 175, 80, 0.1);
}

Добавляем класс в dragover и убираем в dragleave:

dropZone.addEventListener('dragover', () => {
  dropZone.classList.add('active');
});

dropZone.addEventListener('dragleave', () => {
  dropZone.classList.remove('active');
});

Где это применяется в реальной жизни? 🌍

  1. Файловые менеджеры — загрузка файлов перетаскиванием.
  2. Канбан-доски (Trello, Jira) — перемещение задач между колонками.
  3. Конструкторы сайтов — перетаскивание блоков.
  4. Игры — инвентарь, перемещение объектов.

Частые ошибки и как их избежать 🚧

Ошибка Решение
drop не срабатывает Всегда вызывайте preventDefault() в dragover!
Данные не передаются Проверьте формат в setData()/getData()
Элемент «прилипает» к курсору Сбросьте dragImage через e.dataTransfer.setDragImage()
Не работает на мобильных DnD API не всегда поддерживается — используйте Touch Events как fallback

Дополнительные фишки ✨

  • Кастомизация курсора:
e.dataTransfer.setDragImage(customImage, xOffset, yOffset);
  • Ограничение типов данных:
dropZone.addEventListener('dragover', (e) => {
  if (e.dataTransfer.types.includes('text/plain')) {
    e.preventDefault();
  }
});

Что дальше? 🚀

Попробуйте реализовать:

  1. Сортировку таблиц.
  2. Перетаскивание между разными списками.
  3. Drag-and-drop загрузку файлов.

📹 Если хотите глубже разобрать нюансы — посмотрите разборы Данилы Бежина на YouTube. Он отлично объясняет сложные тесты!

Теперь вы знаете, как оживить интерфейсы с помощью Drag and Drop API. Вперёд, творите! 🔥

Скрыть рекламу навсегда

🧠 Учёба без воды и зубрёжки

Закрытый Boosty с наработками опытного преподавателя.

Объясняю сложное так, чтобы щелкнуло.

🚀 Забрать доступ к Boosty