Хуки и middleware

Библиотека Shopify Draggable предоставляет мощный инструмент для реализации перетаскивания элементов на странице с высокой степенью контроля и гибкости. Одним из ключевых компонентов её архитектуры являются хуки (hooks) и middleware, которые позволяют вмешиваться в процесс drag & drop на различных этапах жизненного цикла действия.


Понятие хуков в Draggable

Хуки — это функции, которые вызываются до, во время или после определённых событий drag & drop. Они дают возможность расширять поведение библиотеке без необходимости модифицировать её исходный код.

В Draggable хуки делятся на несколько типов:

  1. beforeStart – вызывается перед началом перетаскивания. Позволяет отменить операцию или подготовить данные для drag.
  2. start – вызывается в момент начала drag. На этом этапе можно изменять визуальное представление элемента.
  3. move – вызывается при каждом перемещении элемента. Позволяет динамически изменять позиции или накладывать ограничения.
  4. over – срабатывает, когда перетаскиваемый элемент оказывается над контейнером или другим элементом.
  5. out – срабатывает при выходе элемента из зоны контейнера.
  6. drop – вызывается в момент отпускания элемента. Здесь можно выполнить финальные изменения DOM или данные синхронизации.
  7. afterDrop – финальный хук после завершения всех операций drop.

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

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

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

draggable.on('beforeStart', (event) => {
  console.log('Подготовка к перетаскиванию', event.source);
});

draggable.on('move', (event) => {
  console.log('Элемент перемещается', event.source, 'Координаты:', event.sensorEvent.clientX, event.sensorEvent.clientY);
});

draggable.on('afterDrop', (event) => {
  console.log('Перетаскивание завершено', event.source);
});

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


Middleware: промежуточная обработка событий

Middleware в Draggable — это функции, которые обрабатывают события между шагами drag & drop, позволяя внедрять кастомную логику без изменения базовой реализации.

Middleware можно рассматривать как фильтры или трансформаторы событий. Они принимают событие, могут изменить его свойства и передать дальше.

Основные возможности middleware:

  • Ограничение движения – можно ограничивать перемещение элемента по оси X или Y.
  • Изменение визуального представления – например, добавление тени или эффекта прозрачности при перетаскивании.
  • Валидация элементов – запрещение перетаскивания определённых элементов.
  • Интеграция с внешними данными – синхронизация изменений позиции с сервером или другим состоянием приложения.

Пример middleware для ограничения движения по оси Y:

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

class LimitYMiddleware extends Plugins.AbstractPlugin {
  attach() {
    this.draggable.on('drag:start', this.onDragStart.bind(this));
    this.draggable.on('drag:move', this.onDragMove.bind(this));
  }

  onDragStart(event) {
    this.startY = event.sensorEvent.clientY;
  }

  onDragMove(event) {
    const deltaY = event.sensorEvent.clientY - this.startY;
    event.source.style.transform = `translateY(${deltaY}px)`;
    event.cancel(); // предотвращает стандартное перемещение Draggable
  }
}

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

Особенность: Middleware получают полный контроль над поведением drag & drop, позволяя изменять стандартные методы и параметры без вмешательства в ядро библиотеки.


Комбинирование хуков и middleware

Использование хуков и middleware вместе позволяет создавать комплексные сценарии взаимодействия. Например:

  • Хук beforeStart проверяет условия перетаскивания.
  • Middleware корректирует траекторию движения.
  • Хук afterDrop синхронизирует результат с сервером.

Пример комбинированного подхода:

draggable.on('beforeStart', (event) => {
  if (event.source.dataset.locked === 'true') {
    event.cancel(); // запрещаем перетаскивание заблокированного элемента
  }
});

class SnapMiddleware extends Plugins.AbstractPlugin {
  onDragMove(event) {
    const snapValue = 50; // шаг привязки
    let y = Math.round(event.sensorEvent.clientY / snapValue) * snapValue;
    event.source.style.transform = `translateY(${y}px)`;
    event.cancel();
  }
}

draggable.addPlugin(SnapMiddleware);

Эффект: блокируем нежелательные элементы и одновременно создаём «привязку» к сетке при перетаскивании.


Практические рекомендации

  • Для простого перетаскивания достаточно хуков, middleware нужен для нестандартного поведения.
  • Middleware лучше использовать, когда необходимо перехватывать и модифицировать движение элементов.
  • Хуки не должны содержать долгие синхронные операции, чтобы не замедлять интерфейс.
  • Middleware можно комбинировать и создавать цепочки, каждая из которых изменяет событие по своему алгоритму.

Использование хуков и middleware в Shopify Draggable превращает простое drag & drop в мощный инструмент для создания интерактивных интерфейсов с тонкой настройкой поведения элементов. Правильная комбинация этих механизмов обеспечивает полное управление жизненным циклом перетаскивания, улучшая UX и позволяя реализовать сложные сценарии взаимодействия.