Фазы событий

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

1. Фаза mirror:create

Эта фаза срабатывает в момент создания зеркального элемента (mirror element), который визуально повторяет перетаскиваемый объект. Mirror используется для анимаций и позволяет пользователю видеть движение объекта без изменения оригинального DOM-элемента.

Ключевые особенности:

  • Событие вызывается до начала движения объекта.
  • Доступ к оригинальному элементу осуществляется через свойство event.source.
  • Mirror элемент можно стилизовать, добавлять классы или изменять его размеры перед началом перемещения.

Пример использования:

draggable.on('mirror:create', (event) => {
  event.mirror.style.border = '2px dashed #000';
  event.mirror.textContent = 'Перетаскиваю';
});

2. Фаза mirror:destroy

Фаза mirror:destroy наступает при завершении перетаскивания и удалении зеркального элемента из DOM. Она позволяет выполнить очистку ресурсов, удалить классы или отменить анимации, связанные с mirror.

Пример:

draggable.on('mirror:destroy', (event) => {
  console.log('Mirror элемент удалён', event.source);
});

3. Фаза drag:start

drag:start — это начало перетаскивания, момент, когда пользователь удерживает объект и начинает его движение. На этой фазе можно:

  • Блокировать определённые элементы для перетаскивания.
  • Добавлять классы для визуальной индикации активности.
  • Инициализировать анимацию или логику взаимодействия с другими элементами.

Пример:

draggable.on('drag:start', (event) => {
  event.source.classList.add('is-dragging');
});

4. Фаза drag:move

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

Особенности:

  • Высокая частота срабатывания требует оптимизации кода.
  • Полезно для динамической проверки столкновений и ограничения движения.

Пример:

draggable.on('drag:move', (event) => {
  console.log('Текущая позиция:', event.sensorEvent.clientX, event.sensorEvent.clientY);
});

5. Фаза drag:stop

Фаза drag:stop срабатывает в момент отпускания объекта пользователем. Она сигнализирует о завершении действия перетаскивания, но ещё до выполнения сортировки или других изменений DOM.

Применение:

  • Снятие классов активности.
  • Валидация позиции объекта.
  • Подготовка к фазе drop.

Пример:

draggable.on('drag:stop', (event) => {
  event.source.classList.remove('is-dragging');
});

6. Фаза drop:prepare

drop:prepare — это момент, когда библиотека определяет возможные зоны сброса для элемента. На этой фазе можно:

  • Изменять поведение определённых контейнеров.
  • Ограничивать зоны для допустимых drop.
  • Подсвечивать активные контейнеры.

Пример:

draggable.on('drop:prepare', (event) => {
  event.containers.forEach(container => container.classList.add('highlight'));
});

7. Фаза drop:move

Фаза drop:move отслеживает движение элемента над контейнерами, где потенциально может произойти drop. Используется для динамического изменения состояния контейнеров: подсветки, анимаций, ограничения позиции.

Пример:

draggable.on('drop:move', (event) => {
  if (event.over) {
    event.over.classList.add('over');
  }
});

8. Фаза drop:stop

drop:stop срабатывает в момент фактического сброса элемента в контейнер. На этом этапе можно обновлять данные, изменять DOM или запускать сторонние события.

Пример:

draggable.on('drop:stop', (event) => {
  console.log('Элемент сброшен в контейнер', event.over);
});

9. Фаза droppable:over и droppable:out

Эти события фиксируют пересечение перетаскиваемого элемента с контейнером:

  • droppable:over — элемент вошёл в область контейнера.
  • droppable:out — элемент покинул область контейнера.

Применение:

  • Подсветка активной зоны.
  • Анимация появления/исчезновения placeholder.

Пример:

draggable.on('droppable:over', (event) => {
  event.over.classList.add('active-zone');
});

draggable.on('droppable:out', (event) => {
  event.over.classList.remove('active-zone');
});

10. Управление фазами и приоритеты

  • Фазы событий происходят в строгой последовательности, что позволяет логически разделить обработку создания mirror, перетаскивания и drop.
  • Для сложных интерфейсов рекомендуется разделять логику на отдельные обработчики каждой фазы, чтобы избежать конфликтов и снизить нагрузку на рендеринг.
  • Использование event.cancelable позволяет отменять действия на определённой фазе, например предотвращать drop в недопустимых контейнерах.

11. Практическая схема жизненного цикла

  1. mirror:create
  2. drag:start
  3. drag:move (многократные срабатывания)
  4. drop:prepare
  5. drop:move (при пересечении контейнеров)
  6. droppable:over / droppable:out
  7. drag:stop
  8. drop:stop
  9. mirror:destroy

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

Каждая фаза предоставляет набор данных через объект event, включая source, mirror, over, containers и sensorEvent, что делает библиотеку Shopify Draggable мощным инструментом для создания интерактивных интерфейсов с перетаскиванием.