Передача данных между событиями

В Interact.js события (drag, resize, gesture и другие) позволяют не только реагировать на действия пользователя, но и передавать между ними контекстную информацию. Для эффективного управления сложными взаимодействиями важно понимать механизмы хранения и передачи данных.

Использование объекта interaction

Каждое взаимодействие в Interact.js представлено объектом interaction, который создается автоматически при начале действия. Этот объект сохраняет состояние текущего взаимодействия и доступен во всех связанных событиях. Ключевые свойства:

  • interaction.target — элемент, с которым ведется взаимодействие.
  • interaction.prepared — объект с данными о предстоящем действии (например, тип действия: drag, resize).
  • interaction.coords — координаты текущего состояния взаимодействия.
  • interaction._customData — поле для хранения пользовательских данных между событиями (неофициальное, но широко используется для передачи информации).

Пример сохранения данных:

interact('.draggable')
  .draggable({
    listeners: {
      start(event) {
        event.interaction._customData = { startX: event.pageX, startY: event.pageY };
      },
      move(event) {
        const data = event.interaction._customData;
        const dx = event.pageX - data.startX;
        const dy = event.pageY - data.startY;
        event.target.style.transform = `translate(${dx}px, ${dy}px)`;
      },
      end(event) {
        console.log('Движение завершено', event.interaction._customData);
      }
    }
  });

В этом примере startX и startY сохраняются на этапе start и доступны на этапе move и end.

Использование event для передачи информации

События Interact.js содержат объект event, который передается каждому слушателю. Он включает:

  • event.target — элемент взаимодействия.
  • event.pageX и event.pageY — координаты курсора.
  • event.dx и event.dy — смещение с предыдущего события.
  • event.interaction — ссылка на текущий объект взаимодействия.

Для передачи данных можно расширять event или хранить данные в объекте interaction, как показано выше.

interact('.resizable')
  .resizable({
    edges: { left: true, right: true, bottom: true, top: true },
    listeners: {
      start(event) {
        event.interaction.startSize = {
          width: event.rect.width,
          height: event.rect.height
        };
      },
      move(event) {
        const startSize = event.interaction.startSize;
        const width = startSize.width + event.deltaRect.width;
        const height = startSize.height + event.deltaRect.height;
        Object.assign(event.target.style, {
          width: `${width}px`,
          height: `${height}px`
        });
      }
    }
  });

Общие подходы к обмену данными между событиями

  1. Хранение состояния в объекте DOM Использование dataset или свойств элемента (element._data) позволяет сохранять контекст без зависимости от interaction. Пример:

    interact('.draggable').draggable({
      listeners: {
        start(event) {
          event.target._dragStart = { x: event.pageX, y: event.pageY };
        },
        move(event) {
          const start = event.target._dragStart;
          event.target.style.transform = `translate(${event.pageX - start.x}px, ${event.pageY - start.y}px)`;
        }
      }
    });
  2. Хранение состояния в глобальном объекте Подходит для сложных интерфейсов, где несколько элементов взаимодействуют между собой:

    const dragData = {};
    interact('.draggable').draggable({
      listeners: {
        start(event) {
          dragData[event.target.id] = { x: event.pageX, y: event.pageY };
        },
        move(event) {
          const start = dragData[event.target.id];
          event.target.style.transform = `translate(${event.pageX - start.x}px, ${event.pageY - start.y}px)`;
        },
        end(event) {
          delete dragData[event.target.id];
        }
      }
    });
  3. Использование кастомных событий Можно инициировать собственные события с данными:

    interact('.draggable').draggable({
      listeners: {
        move(event) {
          const detail = { x: event.pageX, y: event.pageY };
          event.target.dispatchEvent(new CustomEvent('drag-move', { detail }));
        }
      }
    });
    
    document.querySelector('.draggable').addEventListener('drag-move', e => {
      console.log('Кастомные координаты:', e.detail);
    });

Передача данных между разными типами действий

Иногда нужно, чтобы данные, накопленные во время drag, использовались в resize или gesture. Для этого объект interaction сохраняется глобально в пределах сессии:

interact('.box')
  .draggable({
    listeners: {
      start(event) {
        event.interaction.sharedData = { dragged: true };
      }
    }
  })
  .resizable({
    edges: { left: true, right: true },
    listeners: {
      start(event) {
        if (event.interaction.sharedData?.dragged) {
          console.log('Элемент был перетащен ранее');
        }
      }
    }
  });

Рекомендации по структурированию данных

  • Использовать отдельные свойства interaction для каждого типа данных (dragData, resizeData).
  • Очищать данные на событии end или cancel для предотвращения утечек памяти.
  • Для сложных интерфейсов с множественными элементами лучше применять идентификаторы элементов для доступа к хранимым данным.
  • Минимизировать запись данных непосредственно в DOM, чтобы избежать конфликтов с другими библиотеками.

Передача данных между событиями в Interact.js строится вокруг объекта interaction и объекта event, но гибкость библиотека позволяет интегрировать и внешние структуры хранения, обеспечивая устойчивую и контролируемую передачу состояния между различными этапами пользовательского взаимодействия.