Библиотека Shopify Draggable предоставляет мощный инструмент для реализации перетаскивания элементов на странице с поддержкой сортировки, группировки и управления событиями. Ключевой аспект работы с Draggable — корректное позиционирование элементов, так как от этого зависит плавность анимаций, правильное отображение при взаимодействии и точность работы с событиями.
При создании Draggable важно учитывать исходное CSS-положение элементов:
.draggable-item {
position: relative;
display: inline-block;
}
position: relative позволяет элементу сохранять поток
документа, но при этом легко перемещаться с помощью
transform.position: absolute используется для элементов, которые
должны полностью выходить из потока и перемещаться независимо.В Draggable элементы при перетаскивании по умолчанию перемещаются
через CSS-трансформацию
(transform: translate(x, y)), что обеспечивает плавность
анимации без перерасчета layout браузера. Поэтому исходное
позиционирование relative идеально подходит для списков и
сеток.
Контейнер, в котором находятся draggable-элементы, определяет ограничения движения:
const draggable = new Draggable.Sortable(document.querySelectorAll('.container'), {
draggable: '.draggable-item',
delay: 0,
mirror: {
constrainDimensions: true,
},
});
mirror.constrainDimensions гарантирует, что
копия элемента при перетаскивании (mirror) сохранит свои
размеры относительно исходного элемента.Draggable предоставляет объект события с данными координат:
draggable.on('drag:move', (event) => {
const { originalEvent, mirror } = event;
const { clientX, clientY } = originalEvent;
mirror.style.transform = `translate(${clientX}px, ${clientY}px)`;
});
clientX и clientY содержат координаты
курсора относительно окна браузера.getBoundingClientRect() для
проверки коллизий и ограничений контейнера.При перетаскивании создаётся mirror-элемент — копия исходного. Его поведение управляется через конфигурацию:
mirror: {
appendTo: document.body,
constrainDimensions: true,
xAxis: true,
yAxis: true
}
appendTo определяет, куда добавляется mirror — часто
используют document.body для свободного
позиционирования.xAxis и yAxis позволяют ограничить
перемещение по одной оси.При перетаскивании важно управлять z-index, чтобы элемент оставался сверху остальных:
.draggable-mirror {
position: absolute;
z-index: 1000;
pointer-events: none;
}
pointer-events: none предотвращает блокировку событий
для элементов под mirror.draggable.on('drag:start', (event) => {
event.mirror.style.zIndex = 9999;
});
Для вложенных Draggable (nested lists) важно правильно
управлять координатами относительно родительского контейнера:
const parentDraggable = new Draggable.Sortable(document.querySelectorAll('.parent'), {
draggable: '.parent-item',
});
const childDraggable = new Draggable.Sortable(document.querySelectorAll('.child'), {
draggable: '.child-item',
mirror: { constrainDimensions: true },
});
getBoundingClientRect()
родительского контейнера и добавляют смещение к координатам
курсора.Draggable автоматически анимирует элементы при перестановке, используя CSS-трансформации. Важно:
draggable.on('sortable:stop', (event) => {
const movedElement = event.data.dragEvent.source;
const newPosition = movedElement.getBoundingClientRect();
// Дополнительно можно анимировать через GSAP или CSS transition
});
Draggable позволяет ограничивать перемещение элементов через sensors и modifiers:
containment)xAxis, yAxis)grid snapping)Пример ограничения по сетке 50px:
draggable.on('drag:move', (event) => {
const mirror = event.mirror;
const step = 50;
const x = Math.round(event.sensorEvent.clientX / step) * step;
const y = Math.round(event.sensorEvent.clientY / step) * step;
mirror.style.transform = `translate(${x}px, ${y}px)`;
});
top/left
для mirror — это приводит к перерасчёту layout и снижает
производительность.transform: translate(),
чтобы элементы оставались на GPU и анимации были плавными.offsetWidth,
getBoundingClientRect) производить один раз перед
анимацией, чтобы избежать thrashing.Эти правила позиционирования позволяют создавать сложные интерфейсы с Draggable, обеспечивая плавные анимации, точное перемещение и корректное взаимодействие с DOM.