Логирование событий

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

Система событий позволяет:

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

Каждый объект перетаскивания выступает источником событий и реализует механизм подписки через метод on.


Подписка на события

Каждый экземпляр Draggable предоставляет API для подписки на события.

Базовый синтаксис:

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

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

Метод on() принимает:

  • имя события
  • обработчик события

Обработчик получает объект события, содержащий подробную информацию о текущем состоянии операции.


Основные категории событий

События библиотеки делятся на несколько логических групп:

1. Drag события

Относятся к процессу перетаскивания.

Основные события:

Событие Описание
drag:start начало перетаскивания
drag:move перемещение элемента
drag:stop завершение операции

2. Mirror события

При перетаскивании создаётся «зеркальный» элемент — визуальная копия объекта, которая следует за курсором.

События:

Событие Описание
mirror:create создание зеркала
mirror:move перемещение зеркала
mirror:destroy удаление зеркала

3. Container события

Отслеживают взаимодействие с контейнерами.

Событие Описание
drag:over элемент перемещён над контейнером
drag:out элемент покинул контейнер
drag:over:container наведение на контейнер

4. Sortable события

Если используется модуль сортировки, появляются дополнительные события:

Событие Описание
sortable:start начало сортировки
sortable:sort изменение позиции
sortable:sorted элемент перемещён

Структура объекта события

Каждый обработчик получает объект события со структурой:

draggable.on('drag:start', (event) => {
  console.log(event.source);
  console.log(event.originalSource);
  console.log(event.container);
});

Основные поля:

Поле Назначение
source текущий перетаскиваемый элемент
originalSource исходный DOM-элемент
container контейнер
originalEvent нативное DOM событие
mirror зеркальный элемент

Базовое логирование событий

Логирование удобно использовать для отладки.

Пример отслеживания жизненного цикла:

draggable.on('drag:start', (event) => {
  console.log('Drag started', event.source);
});

draggable.on('drag:move', (event) => {
  console.log('Dragging', event.source);
});

draggable.on('drag:stop', (event) => {
  console.log('Drag finished', event.source);
});

В консоли можно наблюдать последовательность действий пользователя.


Централизованное логирование

При работе с большим количеством событий удобнее создать универсальный логгер.

const logEvent = (name) => (event) => {
  console.log(`[${name}]`, event);
};

draggable.on('drag:start', logEvent('drag:start'));
draggable.on('drag:move', logEvent('drag:move'));
draggable.on('drag:stop', logEvent('drag:stop'));

Преимущества подхода:

  • уменьшение дублирования кода
  • единый формат логов
  • упрощение анализа событий

Групповая регистрация событий

Можно зарегистрировать сразу несколько обработчиков:

const events = [
  'drag:start',
  'drag:move',
  'drag:stop',
  'mirror:create',
  'mirror:destroy'
];

events.forEach((eventName) => {
  draggable.on(eventName, (event) => {
    console.log(eventName, event);
  });
});

Такой подход полезен при:

  • тестировании
  • изучении поведения библиотеки
  • разработке сложных интерфейсов

Детализированное логирование

Для полноценной диагностики полезно выводить ключевые параметры события.

draggable.on('drag:start', (event) => {
  console.log({
    element: event.source,
    container: event.container,
    x: event.originalEvent.clientX,
    y: event.originalEvent.clientY
  });
});

Получаемые данные:

  • DOM-элемент
  • текущий контейнер
  • координаты курсора
  • нативное событие

Логирование перемещений

Отслеживание координат позволяет анализировать поведение пользователя.

draggable.on('drag:move', (event) => {
  const { clientX, clientY } = event.originalEvent;

  console.log(`Move: ${clientX}, ${clientY}`);
});

Такая информация применяется в:

  • аналитике интерфейсов
  • UX-исследованиях
  • системах трекинга действий

Логирование контейнеров

Отслеживание переходов между контейнерами важно при сложных интерфейсах.

draggable.on('drag:over:container', (event) => {
  console.log('Entered container', event.overContainer);
});

И при выходе:

draggable.on('drag:out', (event) => {
  console.log('Left container', event.container);
});

Логирование зеркального элемента

Зеркало (mirror) создаётся автоматически при начале перетаскивания.

draggable.on('mirror:create', (event) => {
  console.log('Mirror created', event.mirror);
});

Удаление:

draggable.on('mirror:destroy', (event) => {
  console.log('Mirror removed');
});

Это позволяет:

  • анализировать жизненный цикл DOM-элементов
  • отслеживать производительность
  • отлаживать стили

Удаление обработчиков

Для предотвращения утечек памяти обработчики необходимо удалять.

function handleStart(event) {
  console.log('Start', event);
}

draggable.on('drag:start', handleStart);

draggable.off('drag:start', handleStart);

Метод off():

  • снимает подписку
  • освобождает ресурсы
  • предотвращает повторные вызовы

Логирование всех событий библиотеки

Для глубокого анализа можно подписаться на максимальное количество событий.

const allEvents = [
  'drag:start',
  'drag:move',
  'drag:stop',
  'drag:over',
  'drag:out',
  'mirror:create',
  'mirror:move',
  'mirror:destroy'
];

allEvents.forEach((name) => {
  draggable.on(name, (event) => {
    console.log(`[Draggable] ${name}`, event);
  });
});

Такой режим используется при:

  • разработке сложных drag-and-drop систем
  • изучении внутренней механики библиотеки
  • поиске нестандартных багов

Интеграция с системами логирования

Логи можно отправлять во внешние системы.

Пример:

function sendLog(data) {
  fetch('/logger', {
    method: 'POST',
    body: JSON.stringify(data)
  });
}

draggable.on('drag:start', (event) => {
  sendLog({
    type: 'drag_start',
    element: event.source.id
  });
});

Это позволяет:

  • хранить статистику
  • анализировать поведение пользователей
  • строить аналитические отчёты

Производительность логирования

Избыточное логирование может влиять на производительность, особенно при событиях drag:move, которые вызываются десятки раз в секунду.

Методы оптимизации:

1. Дебаунс

let lastLog = 0;

draggable.on('drag:move', (event) => {
  const now = Date.now();

  if (now - lastLog > 200) {
    console.log('Drag move');
    lastLog = now;
  }
});

2. Фильтрация событий

draggable.on('drag:move', (event) => {
  if (!event.source.classList.contains('loggable')) {
    return;
  }

  console.log('Tracked element move');
});

3. Условное логирование

const DEBUG = true;

draggable.on('drag:start', (event) => {
  if (DEBUG) {
    console.log(event);
  }
});

Практическая схема логирования

Часто используется следующая структура:

drag:start
drag:move
drag:over
drag:out
drag:stop
mirror:destroy

Это позволяет проследить полный цикл:

  1. пользователь начинает перетаскивание
  2. элемент перемещается
  3. происходит вход в контейнер
  4. элемент покидает контейнер
  5. операция завершается
  6. зеркало удаляется

Логи формируют детальную временную линию взаимодействия пользователя с интерфейсом.