Interact.js — это мощная библиотека для обработки взаимодействий с элементами DOM, таких как перетаскивание, масштабирование и жесты. Одним из ключевых аспектов её использования является хранение состояния элементов, чтобы отслеживать их положение, размер и другие параметры между событиями. В Interact.js состояние элементов не хранится автоматически; его нужно управлять вручную через объекты и структуры данных.
Для отслеживания позиции элемента обычно используют объект с
координатами x и y:
let position = { x: 0, y: 0 };
При обработке события dragmove эти координаты
обновляются на основе смещения, предоставляемого библиотекой:
interact('.draggable')
.draggable({
listeners: {
move(event) {
position.x += event.dx;
position.y += event.dy;
event.target.style.transform =
`translate(${position.x}px, ${position.y}px)`;
}
}
});
Здесь event.dx и event.dy — это смещение от
предыдущего события, а объект position хранит накопленные
значения, которые позволяют элементу сохранять своё положение при
последующих перемещениях.
Для масштабируемых элементов необходимо хранить не только координаты, но и размеры:
let state = {
x: 0,
y: 0,
width: 100,
height: 100
};
При событии resizemove обновление может выглядеть
следующим образом:
interact('.resizable')
.resizable({
edges: { left: true, right: true, bottom: true, top: true },
listeners: {
move(event) {
state.width = event.rect.width;
state.height = event.rect.height;
state.x += event.deltaRect.left;
state.y += event.deltaRect.top;
Object.assign(event.target.style, {
width: `${state.width}px`,
height: `${state.height}px`,
transform: `translate(${state.x}px, ${state.y}px)`
});
}
}
});
Ключевой момент — использование event.deltaRect для корректного вычисления смещений при изменении размеров. Это гарантирует точное позиционирование элемента независимо от направления изменения его границ.
Для долгосрочного хранения состояния между сессиями можно применять
HTML-атрибуты data-*. Например:
function saveState(element, state) {
element.dataset.x = state.x;
element.dataset.y = state.y;
element.dataset.width = state.width;
element.dataset.height = state.height;
}
function loadState(element) {
return {
x: parseFloat(element.dataset.x) || 0,
y: parseFloat(element.dataset.y) || 0,
width: parseFloat(element.dataset.width) || 100,
height: parseFloat(element.dataset.height) || 100
};
}
Это позволяет синхронизировать внутреннее состояние с DOM, что особенно удобно при динамически создаваемых элементах или при необходимости сериализации состояния для сохранения в локальное хранилище.
Для постоянного хранения состояния на стороне клиента можно
использовать localStorage:
function persistState(key, state) {
localStorage.setItem(key, JSON.stringify(state));
}
function retrieveState(key) {
const data = localStorage.getItem(key);
return data ? JSON.parse(data) : null;
}
Это позволяет при перезагрузке страницы восстановить позиции и размеры всех элементов. В связке с Interact.js можно применять следующую схему:
const saved = retrieveState('draggableBox');
if (saved) {
const box = document.querySelector('.draggable');
Object.assign(box.style, {
width: `${saved.width}px`,
height: `${saved.height}px`,
transform: `translate(${saved.x}px, ${saved.y}px)`
});
state = saved;
}
Interact.js поддерживает одновременное использование различных действий (drag, resize, gesture). Для этого целесообразно объединять состояние в единый объект:
let elementState = {
position: { x: 0, y: 0 },
size: { width: 100, height: 100 },
rotation: 0
};
Обновление состояния может выполняться в разных обработчиках:
dragmove — обновление positionresizemove — обновление size и
корректировка positiongesturemove — обновление rotationТакой подход обеспечивает централизованное управление состоянием, упрощает сохранение в localStorage и работу с анимациями.
Для множества интерактивных элементов удобно использовать коллекцию
состояний, например, объект с ключами по id или массив
объектов:
let states = {};
document.querySelectorAll('.draggable').forEach(el => {
const id = el.id;
states[id] = { x: 0, y: 0 };
});
При событии dragmove можно обновлять конкретное
состояние:
move(event) {
const id = event.target.id;
states[id].x += event.dx;
states[id].y += event.dy;
event.target.style.transform =
`translate(${states[id].x}px, ${states[id].y}px)`;
}
Хранение состояния в объекте позволяет легко интегрировать его с CSS-анимациями:
event.target.style.transition = 'transform 0.2s ease';
event.target.style.transform = `translate(${state.x}px, ${state.y}px)`;
Преимущество такого подхода — плавная анимация изменений без потери точности позиции и размеров элемента.
Для оптимизации производительности и правильного сохранения состояния
удобно использовать события dragend,
resizeend:
listeners: {
end(event) {
saveState(event.target, state);
persistState('draggableBox', state);
}
}
Это позволяет фиксировать финальное состояние элемента после завершения взаимодействия, минимизируя лишние записи в localStorage во время движения или изменения размеров.
Хранение состояния в Interact.js — это комбинация аккуратного управления объектами состояния, использования встроенных свойств событий и правильной интеграции с DOM и локальным хранилищем. Такой подход обеспечивает точное отслеживание элементов, устойчивость к обновлениям страницы и поддержку сложных взаимодействий.