Изоляция контекста

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

Изоляция контекста достигается за счёт создания отдельных экземпляров Interactable для каждого элемента или группы элементов, а также использования scope для разделения событий и настроек.


Создание отдельных Interactable объектов

Каждый элемент, к которому необходимо применить интерактивное поведение, должен быть представлен отдельным объектом Interactable:

const draggableItem = interact('.draggable');
draggableItem.draggable({
  listeners: {
    start (event) {
      console.log('Начало перетаскивания', event.target);
    },
    move (event) {
      const target = event.target;
      const x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx;
      const y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;

      target.style.transform = `translate(${x}px, ${y}px)`;
      target.setAttribute('data-x', x);
      target.setAttribute('data-y', y);
    }
  },
  modifiers: [
    interact.modifiers.restrictRect({
      restriction: 'parent'
    })
  ],
  inertia: true
});

Ключевые моменты:

  • Каждый вызов interact(selector) создаёт отдельный контекст для элемента.
  • Настройки модификаторов (modifiers) применяются только к этому экземпляру.
  • События (listeners) изолированы, что предотвращает конфликты с другими элементами.

Использование scope для изоляции событий

Interact.js позволяет создавать раздельные области (scope), чтобы события и настройки одного набора элементов не пересекались с другим:

const scopeA = interact.scope.new();

const boxA = scopeA.interact('.box-a');
boxA.draggable({
  listeners: { move: event => console.log('Box A двигается') }
});

const scopeB = interact.scope.new();
const boxB = scopeB.interact('.box-b');
boxB.draggable({
  listeners: { move: event => console.log('Box B двигается') }
});

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

  • Полная независимость событий и модификаторов между различными группами элементов.
  • Возможность иметь различные настройки перетаскивания, жестов и инерции для разных контекстов.
  • Упрощает масштабирование приложений с большим количеством интерактивных объектов.

Изоляция модификаторов

Модификаторы Interact.js, такие как restrictRect, snap и restrictEdges, применяются к конкретному объекту Interactable и не влияют на другие элементы, даже если они используют аналогичные настройки:

interact('.resizable').resizable({
  edges: { left: true, right: true, bottom: true, top: true },
  modifiers: [
    interact.modifiers.snapSize({
      targets: [interact.snappers.grid({ width: 20, height: 20 })]
    }),
    interact.modifiers.restrictSize({
      min: { width: 50, height: 50 },
      max: { width: 300, height: 300 }
    })
  ],
  inertia: true
});

Особенности изоляции модификаторов:

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

Комбинирование draggable и resizable в изолированном контексте

Для сложных интерфейсов часто требуется объединять разные интерактивные действия на одном элементе. Использование отдельного Interactable обеспечивает безопасную комбинацию:

const panel = interact('.panel');

panel.draggable({
  listeners: {
    move(event) {
      const target = event.target;
      const x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx;
      const y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;

      target.style.transform = `translate(${x}px, ${y}px)`;
      target.setAttribute('data-x', x);
      target.setAttribute('data-y', y);
    }
  }
});

panel.resizable({
  edges: { left: true, right: true, bottom: true, top: true },
  modifiers: [
    interact.modifiers.restrictEdges({
      outer: 'parent'
    }),
    interact.modifiers.restrictSize({
      min: { width: 100, height: 100 },
      max: { width: 600, height: 400 }
    })
  ],
  inertia: true
});

Выводы по изоляции:

  • Перетаскивание и изменение размера управляются независимо.
  • Модификаторы и ограничения для resizable не влияют на draggable и наоборот.
  • Любые изменения конфигурации для одного действия не затрагивают другое.

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

  1. Всегда создавать отдельный Interactable для каждой группы элементов с уникальными требованиями.
  2. Использовать scope для разделения контекста событий в сложных приложениях.
  3. Настраивать модификаторы на уровне конкретного Interactable, избегая глобальных правил.
  4. Комбинировать draggable, resizable и gesture только через один экземпляр элемента для безопасной синхронизации событий.
  5. Хранить состояние позиции и размера элемента в data- атрибутах или отдельной модели данных для обеспечения независимости.

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