Библиотека Shopify Draggable предоставляет удобный интерфейс для реализации drag-and-drop взаимодействий в веб-приложениях. Одним из ключевых инструментов является симуляция событий, позволяющая программно инициировать действия пользователя, такие как перетаскивание и сортировка элементов, без прямого взаимодействия с DOM. Это особенно важно для автоматизированного тестирования и создания сложных интерфейсных сценариев.
Для симуляции событий в Draggable используются стандартные
DOM-события, которые можно создавать через конструктор
CustomEvent или Event. Важно понимать, что
Draggable реагирует на собственные пользовательские
события, такие как:
drag:startdrag:movedrag:stopsortable:swapsortable:sortedКаждое событие передает объект с ключевой информацией:
{
source: HTMLElement, // исходный элемент
sensorEvent: Event, // оригинальное DOM-событие (например mousemove)
mirror: HTMLElement, // копия перетаскиваемого элемента
}
Для генерации события используется метод dispatchEvent
на контейнере Draggable:
const container = document.querySelector('.draggable-container');
const customEvent = new CustomEvent('drag:start', {
detail: { source: document.querySelector('.item:first-child') }
});
container.dispatchEvent(customEvent);
Такой подход позволяет инициировать drag:start без
реального перемещения мыши.
Симуляция полноценного drag-and-drop состоит из последовательного вызова событий:
drag:start — начало перетаскивания.drag:move — перемещение элемента.drag:stop — завершение операции.Пример пошаговой симуляции:
const item = document.querySelector('.item:first-child');
const container = document.querySelector('.draggable-container');
container.dispatchEvent(new CustomEvent('drag:start', { detail: { source: item } }));
const moveEvent = new CustomEvent('drag:move', {
detail: {
source: item,
sensorEvent: new MouseEvent('mousemove', { clientX: 150, clientY: 100 })
}
});
container.dispatchEvent(moveEvent);
container.dispatchEvent(new CustomEvent('drag:stop', { detail: { source: item } }));
Важно, что drag:move можно вызывать несколько раз с
разными координатами, создавая плавное движение.
Draggable поддерживает сортировку элементов с событиями
sortable:swap и sortable:sorted. Симуляция
этих событий позволяет программно изменять порядок элементов и запускать
соответствующую логику.
Пример симуляции swap:
const draggable = new Draggable.Sortable(document.querySelector('.list'), {
draggable: '.item'
});
const source = document.querySelector('.item:first-child');
const over = document.querySelector('.item:nth-child(2)');
draggable.container.dispatchEvent(new CustomEvent('sortable:swap', {
detail: { source, over }
}));
draggable.container.dispatchEvent(new CustomEvent('sortable:sorted', {
detail: { source, over }
}));
Эта последовательность гарантирует, что все внутренние слушатели Draggable корректно отработают, включая обновление позиции в DOM и вызов коллбеков.
Draggable использует систему сенсоров, которые
обрабатывают события мыши, касания или клавиатуры. Для корректной
симуляции необходимо учитывать, какой сенсор используется. Например, для
мыши создаются события mousedown, mousemove,
mouseup, а для touch — touchstart,
touchmove, touchend.
Пример с имитацией сенсора мыши:
const mouseDownEvent = new MouseEvent('mousedown', { clientX: 0, clientY: 0 });
item.dispatchEvent(mouseDownEvent);
const mouseMoveEvent = new MouseEvent('mousemove', { clientX: 100, clientY: 50 });
document.dispatchEvent(mouseMoveEvent);
const mouseUpEvent = new MouseEvent('mouseup');
document.dispatchEvent(mouseUpEvent);
Этот подход обеспечивает работу стандартных сенсоров Draggable без вмешательства в их внутреннюю логику.
drag:stop до
drag:move) может привести к некорректной работе
библиотеки.clientX и
clientY.drag:stop для корректного обновления DOM.Можно комбинировать симуляцию drag-and-drop с таймерами или анимацией для имитации реального пользовательского поведения:
const steps = [
{ x: 10, y: 0 },
{ x: 20, y: 5 },
{ x: 40, y: 10 },
];
steps.forEach((step, index) => {
setTimeout(() => {
container.dispatchEvent(new CustomEvent('drag:move', {
detail: {
source: item,
sensorEvent: new MouseEvent('mousemove', { clientX: step.x, clientY: step.y })
}
}));
}, index * 50);
});
setTimeout(() => {
container.dispatchEvent(new CustomEvent('drag:stop', { detail: { source: item } }));
}, steps.length * 50);
Такой подход позволяет создавать точные сценарии перемещения, полезные для демо-эффектов или сложного UI-тестирования.
detail.start → move → stop → swap → sorted) обеспечивает
стабильное выполнение логики перетаскивания и сортировки.