Interact.js предоставляет мощный набор инструментов для работы с перетаскиванием, масштабированием и другими взаимодействиями с элементами DOM. Одной из ключевых возможностей библиотеки является работа с вложенными контейнерами, когда элементы находятся внутри других элементов, каждый из которых может иметь собственные ограничения и правила взаимодействия.
Вложенные контейнеры позволяют:
Interact.js использует концепцию dropzones и draggable elements, где контейнеры могут быть одновременно зоной сброса для одного уровня и родителем для другого.
Для создания вложенных перетаскиваемых элементов используется базовый синтаксис:
interact('.draggable')
.draggable({
modifiers: [
interact.modifiers.restrictRect({
restriction: 'parent',
endOnly: true
})
],
listeners: {
move(event) {
const target = event.target;
target.style.transform = `translate(${event.pageX}px, ${event.pageY}px)`;
}
}
});
modifiers.restrictRect обеспечивает ограничение
движения внутри родительского контейнера.restriction: 'parent' автоматически связывает границы с
ближайшим контейнером-родителем.endOnly: true предотвращает сдвиг до конца
перетаскивания, сохраняя плавность интерфейса.При работе с несколькими уровнями вложенности важно назначать уникальные селекторы для каждого уровня, чтобы ограничения применялись корректно.
Dropzone — это элемент, в который можно «сбрасывать» другие элементы. Для вложенных контейнеров настройка выглядит следующим образом:
interact('.dropzone')
.dropzone({
accept: '.draggable',
overlap: 0.5,
ondropactivate(event) {
event.target.classList.add('active-dropzone');
},
ondrop(event) {
event.target.appendChild(event.relatedTarget);
event.relatedTarget.style.transform = 'translate(0, 0)';
},
ondragleave(event) {
event.target.classList.remove('active-dropzone');
}
});
accept задаёт, какие элементы могут быть сброшены.overlap определяет минимальное перекрытие для
срабатывания события drop.ondrop позволяет переместить элемент внутрь нового
контейнера, корректно сбрасывая предыдущие трансформации.Для вложенных контейнеров можно использовать несколько dropzone на разных уровнях, что позволяет создавать комплексные интерфейсы с независимыми зонами перетаскивания.
Interact.js позволяет фильтровать события по иерархии элементов, предотвращая конфликт между родительским и дочерним контейнерами. Например:
interact('.nested-draggable')
.draggable({
listeners: {
move(event) {
const target = event.target;
let x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx;
let 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);
}
}
});
data-x и data-y позволяет
хранить абсолютные координаты элемента относительно родителя.translate по event.pageX/Y может привести к
смещению за пределы родительского контейнера.Interact.js поддерживает масштабирование (resize) элементов с сохранением ограничений родительских контейнеров:
interact('.resizable')
.resizable({
edges: { left: true, right: true, bottom: true, top: true },
modifiers: [
interact.modifiers.restrictEdges({
outer: 'parent',
}),
interact.modifiers.restrictSize({
min: { width: 50, height: 50 },
max: { width: 500, height: 500 }
})
],
listeners: {
move(event) {
let { x, y } = event.target.dataset;
x = parseFloat(x) || 0;
y = parseFloat(y) || 0;
Object.assign(event.target.style, {
width: `${event.rect.width}px`,
height: `${event.rect.height}px`,
transform: `translate(${x}px, ${y}px)`
});
}
}
});
restrictEdges гарантирует, что элемент не выйдет за
пределы родителя.restrictSize предотвращает чрезмерное увеличение или
уменьшение.restriction и restrictEdges.data-x/data-y или через state, чтобы избежать
накопления ошибок трансформации.Эта структура позволяет создавать интерфейсы с динамическими, интерактивными элементами внутри вложенных контейнеров, где каждый элемент сохраняет свои ограничения и поведение, а библиотека Interact.js обеспечивает плавное и предсказуемое взаимодействие.