Создание drop-зон

В библиотеке Shopify Draggable drag-and-drop взаимодействия строятся вокруг трёх основных компонентов: Draggable, Droppable и Sortable. Drop-зона — это элемент, на который можно «бросить» перетаскиваемый объект. Она управляет событиями входа, выхода и завершения перетаскивания, а также обеспечивает визуальную обратную связь.

Drop-зона создаётся путём подключения плагина Droppable к контейнеру, который должен принимать элементы. Структура инициализации выглядит так:

import { Draggable, Droppable } from '@shopify/draggable';

const draggable = new Draggable(document.querySelectorAll('.draggable-item'), {
  draggable: '.item'
});

const droppable = new Droppable(document.querySelectorAll('.drop-zone'), {
  draggable: '.item'
});

Здесь '.draggable-item' — элементы, которые можно перемещать, а '.drop-zone' — контейнеры, способные принимать эти элементы.

События drop-зоны

Drop-зона поддерживает множество событий, которые позволяют контролировать процесс перетаскивания:

  • droppable:over — срабатывает, когда draggable входит в зону.
  • droppable:out — вызывается при выходе draggable из зоны.
  • droppable:dropped — фиксирует успешное «бросание» элемента.
  • droppable:returned — срабатывает, если элемент возвращается в исходное место.

Пример подписки на события:

droppable.on('droppable:over', (event) => {
  event.over.classList.add('highlight');
});

droppable.on('droppable:out', (event) => {
  event.over.classList.remove('highlight');
});

droppable.on('droppable:dropped', (event) => {
  console.log('Элемент успешно перемещён:', event.dragEvent.source);
});

Ключевой объект события — event, содержащий dragEvent.source (перетаскиваемый элемент), over (текущая drop-зона) и другие свойства.

Настройка поведения drop-зоны

Drop-зоны можно конфигурировать через опции:

  • dropzone — CSS-селектор для контейнеров.
  • mirror — опции зеркала (визуальное отображение перетаскиваемого объекта).
  • ignoreInputTextSelection — предотвращение срабатывания drag на текстовых полях.
  • delay — задержка перед началом перетаскивания.

Пример расширенной инициализации:

const droppable = new Droppable(document.querySelectorAll('.drop-zone'), {
  draggable: '.item',
  delay: 150,
  mirror: {
    constrainDimensions: true,
    xAxis: false,
    yAxis: false
  }
});

Создание нескольких drop-зон

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

const droppable = new Droppable(document.querySelectorAll('.drop-zone, .secondary-drop-zone'), {
  draggable: '.item'
});

События автоматически различают, в какую зону был брошен объект, через свойство event.over.

Визуальная обратная связь

Добавление CSS-классов для состояний drop-зоны улучшает UX. Основные подходы:

  • highlight — при наведении draggable.
  • active — когда элемент находится в зоне.
  • invalid — если drop запрещён.

Пример:

droppable.on('droppable:over', ({ over }) => over.classList.add('highlight'));
droppable.on('droppable:out', ({ over }) => over.classList.remove('highlight'));
droppable.on('droppable:dropped', ({ over }) => {
  over.classList.remove('highlight');
  over.classList.add('active');
});

Интеграция с Sortable и другими плагинами

Drop-зоны можно комбинировать с Sortable, чтобы одновременно поддерживать перетаскивание между контейнерами с перестановкой элементов:

import { Sortable } from '@shopify/draggable';

const sortable = new Sortable(document.querySelectorAll('.sortable-list'), {
  draggable: '.item',
  mirror: { constrainDimensions: true }
});

Drop-зона и сортируемый список могут работать параллельно, где события droppable:dropped и sortable:stop позволяют синхронизировать данные и выполнять действия, например, обновление состояния на сервере.

Обработка ошибок и ограничений

  • Проверка, разрешён ли drop в конкретную зону (accept условие) через кастомные события.
  • Игнорирование элементов с запрещёнными селекторами.
  • Контроль зеркала (mirror) для ограничения перемещения за пределы видимой области.

Пример фильтрации допустимых элементов:

droppable.on('droppable:dropped', (event) => {
  if (!event.dragEvent.source.matches('.allowed')) {
    event.dragEvent.cancel();
  }
});

Рекомендации по производительности

  • Использовать делегирование событий вместо подписки на каждый элемент.
  • Ограничивать количество одновременно активных drop-зон.
  • Включать mirror.constrainDimensions, чтобы уменьшить нагрузку на рендеринг.

Итоговая структура drop-зоны

  1. Создание контейнера с нужным селектором.
  2. Инициализация Droppable с настройками.
  3. Подписка на события (over, out, dropped, returned).
  4. Управление визуальными состояниями через CSS-классы.
  5. Обработка логики допустимых drop-элементов.
  6. При необходимости интеграция с Sortable и другими плагинами.

Эта последовательность позволяет строить гибкие и динамичные интерфейсы с drag-and-drop, полностью используя возможности Shopify Draggable.