Всплытие и перехват событий

В библиотеке Shopify Draggable управление событиями является фундаментальной частью работы с перетаскиваемыми элементами. Два ключевых механизма — это всплытие событий и перехват (interception), которые позволяют гибко управлять поведением drag-and-drop интерфейса и предотвращать нежелательные действия по умолчанию.


Основы событийной модели Draggable

Каждый объект Draggable генерирует собственные события в процессе перетаскивания:

  • drag:start — инициируется при начале перетаскивания.
  • drag:move — происходит при движении элемента.
  • drag:stop — возникает при завершении перетаскивания.
  • sortable:swap — срабатывает при обмене позиций элементов в контейнере.
  • droppable:over и droppable:out — срабатывают при наведении или выходе элемента из области droppable.

Все события можно подписывать через метод on:

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

draggable.on('drag:start', (event) => {
  console.log('Начало перетаскивания:', event.source);
});

Каждое событие содержит объект с важными свойствами:

  • source — элемент, который перетаскивается.
  • sensorEvent — оригинальное событие мыши или касания.
  • originalEvent — базовое DOM-событие, которое вызвало срабатывание Draggable-события.

Механизм всплытия событий

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

Пример:

draggable.on('drag:start', (event) => {
  console.log('Событие drag:start на уровне Draggable');
});

document.body.addEventListener('drag:start', (e) => {
  console.log('Всплывшее событие drag:start на body');
});

В этом примере событие drag:start сначала обрабатывается в Draggable, а затем всплывает по DOM, позволяя родительским элементам реагировать на действия пользователя.


Перехват событий (Event Interception)

Для предотвращения стандартного поведения или вмешательства в поток событий используется метод event.cancel().

draggable.on('drag:start', (event) => {
  if (event.source.classList.contains('no-drag')) {
    event.cancel(); // Останавливает дальнейшее перетаскивание
  }
});
  • event.cancel() останавливает текущее событие и предотвращает всплытие.
  • Можно использовать для создания условного drag-and-drop, когда элементы с определёнными классами не могут быть перемещены.

Прерывание и контроль всплытия

Помимо cancel(), есть возможность полностью контролировать всплытие событий:

draggable.on('drag:move', (event) => {
  event.originalEvent.stopPropagation(); // Останавливает дальнейшее DOM-всплытие
});
  • stopPropagation() блокирует подъем события по DOM, но не прерывает обработку Draggable-события внутри самого объекта.
  • Это важно для сложных интерфейсов, где несколько Draggable-контейнеров находятся внутри друг друга.

Использование делегирования и фильтров

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

const draggable = new Draggable(document.querySelectorAll('.lists'), {
  draggable: '.item',
  handle: '.handle' // Только элементы с классом handle можно перетаскивать
});

draggable.on('drag:start', (event) => {
  console.log('Перетаскивается только элемент с handle:', event.source);
});
  • Делегирование уменьшает количество подписок и предотвращает случайное срабатывание на неподходящих элементах.
  • В комбинации с cancel() позволяет реализовать сложные правила перетаскивания в реальном времени.

События droppable и их контроль

Для элементов, которые могут принимать перетаскиваемые объекты, используются события droppable:over, droppable:out и droppable:drop.

draggable.on('droppable:over', (event) => {
  if (event.over.classList.contains('disabled')) {
    event.cancel(); // Запрещает попадание на droppable элемент
  }
});
  • Всплытие этих событий также возможно, что позволяет родителям отслеживать вход элементов в их область.
  • event.cancel() предотвращает не только drop, но и визуальные эффекты hover, используемые Draggable.

Практические советы по управлению событиями

  1. Использовать cancel() для блокировки нежелательного перетаскивания, особенно на элементах, которые не должны перемещаться.
  2. Комбинировать stopPropagation() с делегированием для предотвращения конфликтов при вложенных Draggable.
  3. Подписываться на оригинальные события DOM через originalEvent, если нужно интегрировать с другими библиотеками.
  4. Обрабатывать droppable события для контроля зон, куда можно перемещать объекты, и для реализации визуальных эффектов.

Всплытие и перехват событий в Shopify Draggable дают полный контроль над жизненным циклом перетаскиваемого элемента. Используя методы cancel(), stopPropagation() и делегирование, можно создавать гибкие интерфейсы drag-and-drop, которые реагируют только на необходимые действия, предотвращая случайные или нежелательные события.