Валидация перемещений

Dragula — это легковесная библиотека для реализации drag-and-drop функционала в веб-приложениях на JavaScript. Основной её принцип заключается в управлении перемещениями элементов между контейнерами с минимальными усилиями, предоставляя набор событий и опций для тонкой настройки поведения.

Перемещение в Dragula осуществляется за счёт создания drake — объекта, который управляет всеми аспектами перетаскивания. Создание drake выглядит следующим образом:

const drake = dragula([container1, container2]);

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

Валидация перемещений

Валидация перемещений — ключевой инструмент для контроля над тем, какие элементы могут быть перемещены и куда. В Dragula это реализуется через опцию moves и ряд вспомогательных функций:

Опция moves

moves — это функция, вызываемая каждый раз, когда начинается попытка перетаскивания. Она получает три аргумента:

  • el — элемент, который пытаются перетащить;
  • source — контейнер, из которого происходит перемещение;
  • handle — элемент, по которому был выполнен захват мышью.

Пример функции moves, запрещающей перемещение элементов с классом locked:

const drake = dragula([container1, container2], {
  moves: (el, source, handle) => {
    return !el.classList.contains('locked');
  }
});

Здесь ключевой момент: возвращение true разрешает перемещение, false — запрещает.

Опция accepts

accepts отвечает за валидацию целевых контейнеров. Она принимает четыре аргумента:

  • el — элемент, который перетаскивается;
  • target — контейнер, в который предполагается поместить элемент;
  • source — контейнер, из которого элемент берётся;
  • sibling — элемент, перед которым будет вставлен перетаскиваемый элемент, либо null, если элемент добавляется в конец.

Пример ограничения перемещения в определённый контейнер:

const drake = dragula([container1, container2], {
  accepts: (el, target, source, sibling) => {
    return target.id !== 'restricted-container';
  }
});

Таким образом, элемент может быть перетащен только в контейнеры, не помеченные как restricted-container.

Использование событий для дополнительной проверки

Dragula предоставляет ряд событий, которые помогают контролировать процесс перемещения:

  • drag — срабатывает при начале перетаскивания;
  • drop — срабатывает при успешном размещении элемента;
  • over и out — при наведении и уходе элемента над контейнером;
  • cancel — при отмене перемещения.

Пример валидации через событие drop:

drake.on('drop', (el, target, source, sibling) => {
  if (target.classList.contains('no-drop')) {
    source.appendChild(el);
  }
});

Здесь при попытке сброса элемента в контейнер с классом no-drop элемент возвращается в исходный контейнер.

Динамическая модификация правил перемещения

Dragula позволяет изменять правила перемещения во время работы приложения. Для этого можно переназначать функции moves и accepts или использовать событие drag для динамической блокировки элементов.

Пример блокировки всех элементов при включении режима редактирования:

let editMode = false;

const drake = dragula([container1, container2], {
  moves: (el) => {
    return editMode;
  }
});

// Включение режима редактирования
editMode = true;

Учет специфических условий

Для сложных интерфейсов важно учитывать дополнительные условия:

  • Тип элемента: ограничение перемещения определённых тегов или классов;
  • Родительский контейнер: запрет перемещения элементов из одного раздела в другой;
  • Позиция внутри контейнера: контроль вставки перед конкретными элементами.

Пример с контролем позиции:

const drake = dragula([container1, container2], {
  accepts: (el, target, source, sibling) => {
    if (sibling && sibling.classList.contains('protected')) {
      return false;
    }
    return true;
  }
});

Это предотвращает вставку элемента перед защищёнными элементами.

Совмещение нескольких правил

Для полного контроля перемещений часто требуется комбинация опций moves и accepts с дополнительными проверками через события. Такой подход обеспечивает:

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

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