Shopify Draggable предоставляет гибкий API для реализации перетаскивания элементов в интерфейсе. Одной из важных возможностей является клонирование элементов при начале перетаскивания, что особенно полезно для реализации функционала перемещения с сохранением исходного элемента или создания визуального эффекта “копирования”.
Для реализации клонирования используется опция mirror и
событие mirror:created. При активации клонирования
Draggable создаёт зеркало элемента
(mirror), которое визуально повторяет исходный элемент, но
при этом остаётся независимым от него в DOM.
Пример базовой инициализации с клонированием:
import { Draggable } from '@shopify/draggable';
const container = document.querySelector('.draggable-container');
const draggable = new Draggable(container, {
draggable: '.draggable-item',
mirror: {
constrainDimensions: true
}
});
Пояснение ключевых параметров:
draggable — селектор элементов, которые можно
перетаскивать.mirror.constrainDimensions — ограничивает размеры
зеркала размерами исходного элемента, что улучшает визуальное
соответствие.Shopify Draggable генерирует несколько событий, связанных с зеркалом:
mirror:created — вызывается после
создания зеркала.mirror:move — вызывается при
перемещении зеркала.mirror:destroy — вызывается при
завершении перетаскивания.Пример кастомизации внешнего вида клона при создании:
draggable.on('mirror:created', (event) => {
const mirror = event.mirror;
mirror.style.backgroundColor = '#f0f0f0';
mirror.style.border = '2px dashed #999';
mirror.style.opacity = '0.8';
});
Здесь event.mirror — это DOM-элемент зеркала, который
можно стилизовать независимо от исходного элемента.
Если требуется, чтобы исходный элемент оставался на месте, а перемещался только клон, используется стандартное поведение зеркала. В этом случае исходный элемент не меняется, а пользователь видит перемещаемый клон.
Для реализации эффекта “перетаскивание копии” можно дополнительно внедрить создание нового элемента в контейнере после окончания перемещения:
draggable.on('drag:stop', (event) => {
const original = event.source;
const newItem = original.cloneNode(true);
newItem.classList.add('cloned');
document.querySelector('.target-container').appendChild(newItem);
});
Пояснение:
event.source — исходный элемент, с которого началось
перетаскивание.cloneNode(true) — создаёт глубокую копию элемента со
всеми его дочерними узлами.При клонировании элементов важно помнить о событиях и
интерактивных компонентах, встроенных в исходный элемент.
Простое клонирование через cloneNode(true) копирует
HTML-структуру, но не привязанные слушатели событий. Чтобы сохранить
интерактивность, можно:
Пример с повторной инициализацией draggable на новом элементе:
draggable.on('drag:stop', (event) => {
const clone = event.source.cloneNode(true);
document.querySelector('.draggable-container').appendChild(clone);
const newDraggable = new Draggable(document.querySelector('.draggable-container'), {
draggable: '.draggable-item'
});
});
Draggable позволяет одновременно реализовать перетаскивание и
сортировку элементов с клонированием. Для этого используется
класс Sortable:
import { Sortable } from '@shopify/draggable';
const sortable = new Sortable(document.querySelectorAll('.sortable-container'), {
draggable: '.sortable-item',
mirror: {
constrainDimensions: true
}
});
Shopify Draggable предоставляет возможность полного контроля
над клоном через mirror:create и
mirror:move. Это позволяет:
Пример с динамическим масштабированием зеркала:
draggable.on('mirror:move', (event) => {
const mirror = event.mirror;
const scale = 1 + event.sensorEvent.deltaY / 200;
mirror.style.transform = `scale(${scale})`;
});
Здесь event.sensorEvent.deltaY — величина смещения
курсора, позволяющая анимировать масштаб клона в зависимости от
перемещения.
Использование клонирования при перетаскивании с Shopify Draggable обеспечивает гибкость в создании интерфейсов с копированием элементов, drag-and-drop корзинами и динамическими эффектами. Контроль над зеркалом и правильная работа с событиями позволяют реализовать сложные сценарии без потери производительности и интерактивности.