Vue.js интеграция

Для интеграции Interact.js в проект на Vue.js можно использовать стандартный подход через npm:

npm install interactjs

После установки библиотеку импортируют в компонент или основной файл:

import interact from 'interactjs';

В случае глобального использования можно подключить библиотеку через <script> в index.html:

<script src="https://cdn.jsdelivr.net/npm/interactjs/dist/interact.min.js"></script>

Использование в компонентах Vue

Вариант с mounted

В компонентах Vue взаимодействие с DOM должно происходить после монтирования, чтобы элементы были доступны для Interact.js:

export default {
  data() {
    return {
      position: { x: 0, y: 0 }
    };
  },
  mounted() {
    interact(this.$refs.draggable)
      .draggable({
        listeners: {
          move: this.dragMoveListener
        }
      });
  },
  methods: {
    dragMoveListener(event) {
      this.position.x += event.dx;
      this.position.y += event.dy;
      event.target.style.transform = `translate(${this.position.x}px, ${this.position.y}px)`;
    }
  }
};

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

  • Использование $refs обеспечивает прямой доступ к элементу DOM.
  • event.dx и event.dy отражают смещение за текущее событие.
  • Состояние позиции хранится в data, что позволяет синхронизировать с реактивными данными Vue.

Интерактивные зоны и ограничение движения

Interact.js позволяет задавать ограничения на перемещение элементов через restrict:

interact(this.$refs.draggable)
  .draggable({
    modifiers: [
      interact.modifiers.restrictRect({
        restriction: 'parent',
        endOnly: true
      })
    ],
    listeners: { move: this.dragMoveListener }
  });

Разбор параметров:

  • restriction: 'parent' – элемент не выйдет за пределы родителя.
  • endOnly: true – проверка ограничений выполняется только при завершении перетаскивания.

Для сложных сценариев можно передавать кастомный объект ограничения с координатами:

restriction: { top: 0, left: 0, bottom: 400, right: 600 }

Масштабирование и вращение элементов

Interact.js поддерживает мульти-тач и работу с gesturable:

interact(this.$refs.resizable)
  .gesturable({
    listeners: {
      move: (event) => {
        const scale = (this.scale || 1) * (1 + event.ds);
        this.rotation = (this.rotation || 0) + event.da;
        this.scale = scale;

        event.target.style.transform = `rotate(${this.rotation}deg) scale(${this.scale})`;
      }
    }
  });
  • event.ds – изменение масштаба.
  • event.da – изменение угла вращения.
  • Данные scale и rotation сохраняются в data для реактивного обновления состояния.

Перетаскивание с привязкой к сетке

Для реализации привязки к сетке используется snap модификатор:

interact(this.$refs.draggable)
  .draggable({
    modifiers: [
      interact.modifiers.snap({
        targets: [
          interact.createSnapGrid({ x: 50, y: 50 })
        ],
        range: Infinity,
        relativePoints: [{ x: 0, y: 0 }]
      })
    ],
    listeners: { move: this.dragMoveListener }
  });
  • createSnapGrid({ x, y }) – задает шаг сетки.
  • range: Infinity позволяет элементу привязываться в любом радиусе.
  • relativePoints управляет точкой привязки, чаще всего используют { x: 0, y: 0 } для верхнего левого угла элемента.

Интеграция с динамическими компонентами

При динамическом создании компонентов через v-for необходимо повторно инициализировать Interact.js для новых элементов. Пример с использованием nextTick:

this.$nextTick(() => {
  this.items.forEach(item => {
    interact(this.$refs[`item_${item.id}`])
      .draggable({ listeners: { move: this.dragMoveListener } });
  });
});
  • $refs для массивов компонентов возвращает массив элементов.
  • nextTick гарантирует, что DOM обновлен перед применением Interact.js.

События Interact.js и реактивные данные Vue

Для полного взаимодействия между библиотекой и Vue важно хранить состояние элементов в реактивных свойствах и обновлять DOM через style.transform или классы.

Пример с двухмерным массивом координат для нескольких элементов:

data() {
  return {
    elements: [
      { id: 1, x: 0, y: 0 },
      { id: 2, x: 100, y: 50 }
    ]
  };
},
mounted() {
  this.elements.forEach((el, index) => {
    interact(this.$refs[`el_${el.id}`])
      .draggable({
        listeners: {
          move: (event) => {
            this.elements[index].x += event.dx;
            this.elements[index].y += event.dy;
            event.target.style.transform = `translate(${this.elements[index].x}px, ${this.elements[index].y}px)`;
          }
        }
      });
  });
}
  • Позволяет синхронизировать состояние с Vuex или локальными реактивными данными.
  • Обеспечивает поддержку Undo/Redo или сохранение позиции на сервере.

Взаимодействие с Vue Transition и анимацией

Interact.js можно комбинировать с Vue Transition для плавного появления или скрытия интерактивных элементов:

<transition name="fade">
  <div ref="draggable" v-if="showElement" class="box"></div>
</transition>

В methods при перемещении элемента применяется transform, а анимация появления управляется Vue Transition через CSS:

.fade-enter-active, .fade-leave-active {
  transition: opacity 0.3s;
}
.fade-enter, .fade-leave-to {
  opacity: 0;
}

Советы по производительности

  • Ограничивать количество прослушивателей draggable и gesturable для большого количества элементов.
  • Использовать requestAnimationFrame при обновлении transform для плавного рендеринга.
  • Хранить координаты и состояние в реактивных данных Vue для удобного взаимодействия с компонентами и сторонними библиотеками.

Эти подходы позволяют построить полноценную интерактивную среду с поддержкой перетаскивания, масштабирования, вращения и сеток в Vue.js, используя всю мощь Interact.js.