Одна из наиболее распространённых проблем при работе с библиотекой Shopify Draggable связана с некорректным созданием экземпляра класса. Библиотека требует точного указания контейнера и списка элементов, которые должны участвовать в перетаскивании.
Типичная ошибка заключается в передаче неправильного селектора контейнера.
const draggable = new Draggable('.container', {
draggable: '.item'
});
Если селектор .container отсутствует в DOM или выбран
неправильно, библиотека не сможет привязать обработчики событий.
Корректная проверка существования контейнера:
const container = document.querySelector('.container');
if (container) {
const draggable = new Draggable(container, {
draggable: '.item'
});
}
Ключевые моменты:
draggableПример безопасной инициализации:
document.addEventListener('DOMContentLoaded', () => {
const draggable = new Draggable('.container', {
draggable: '.item'
});
});
Библиотека чувствительна к структуре разметки. Неправильная вложенность элементов часто приводит к непредсказуемому поведению.
Пример проблемной структуры:
<div class="container">
<div class="wrapper">
<div class="item">1</div>
<div class="item">2</div>
</div>
</div>
Если указано:
draggable: '.item'
но библиотека ожидает прямых потомков контейнера, некоторые плагины могут работать некорректно.
Более стабильная структура:
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
</div>
Особенно это важно при использовании модулей сортировки и перемещения между контейнерами.
Shopify Draggable построена на модульной архитектуре. Основные классы:
DraggableSortableDroppableSwappableРаспространённая ошибка — использование функциональности модуля, который не был импортирован.
Пример ошибки:
import { Draggable } from '@shopify/draggable';
const sortable = new Sortable(...);
Класс Sortable не будет доступен.
Правильный импорт:
import { Sortable } from '@shopify/draggable';
Или использование полного набора:
import { Draggable, Sortable, Droppable } from '@shopify/draggable';
В среде сборщиков (Webpack, Vite) необходимо следить за корректностью импортируемых модулей.
Библиотека предоставляет развитую систему событий:
drag:startdrag:movedrag:stopsortable:startsortable:sortedОшибка часто возникает из-за неверного имени события.
Некорректный код:
draggable.on('dragStart', (event) => {
console.log(event);
});
В библиотеке используется формат namespace:event.
Правильная запись:
draggable.on('drag:start', (event) => {
console.log(event);
});
Дополнительная ошибка — попытка обратиться к данным события вне его контекста.
let draggedItem;
draggable.on('drag:start', (event) => {
draggedItem = event.source;
});
Важно учитывать, что event.source представляет исходный
DOM-элемент.
Некоторые стили могут полностью блокировать работу перетаскивания.
Распространённые проблемы:
overflow: hidden.container {
overflow: hidden;
}
Это может препятствовать корректному отображению зеркального элемента (mirror), который создаётся библиотекой во время перетаскивания.
pointer-events: none.item {
pointer-events: none;
}
Элемент перестаёт реагировать на события мыши.
user-selectРекомендуется отключать выделение текста:
.item {
user-select: none;
}
После инициализации библиотеки новые элементы могут не участвовать в перетаскивании.
Пример:
container.insertAdjacentHTML(
'beforeend',
'<div class="item">New</div>'
);
Если элемент добавлен динамически, необходимо убедиться, что он
соответствует селектору draggable.
Библиотека работает через делегирование событий, поэтому повторная инициализация обычно не требуется. Однако ошибки могут возникнуть при:
Опасный сценарий:
container.innerHTML = '';
При полном перерисовывании контейнера рекомендуется заново создать
экземпляр Draggable.
Использование нескольких библиотек перетаскивания одновременно может приводить к конфликтам событий.
Особенно часто проблемы возникают при одновременном использовании:
Причины конфликтов:
mousedownevent.preventDefault()Лучшей практикой является использование только одного drag-and-drop решения в пределах одного интерфейсного модуля.
handleОпция handle ограничивает область, за которую можно
начать перетаскивание.
Ошибка:
const draggable = new Draggable('.container', {
draggable: '.item',
handle: '.drag'
});
Если внутри .item отсутствует элемент
.drag, перетаскивание не будет запускаться.
Правильная структура:
<div class="item">
<span class="drag">☰</span>
Card
</div>
Во время перетаскивания библиотека создаёт зеркальный элемент — копию перетаскиваемого блока.
Этот элемент размещается в document.body.
Иногда это вызывает проблемы:
Ошибка:
.container .item {
width: 200px;
}
Зеркальный элемент находится вне .container, поэтому
стиль не применяется.
Решение:
.item {
width: 200px;
}
При использовании Sortable или Droppable
можно перемещать элементы между контейнерами.
Ошибка возникает, если передан только один контейнер.
Некорректно:
new Sortable(document.querySelector('.container'), {
draggable: '.item'
});
Для межконтейнерной сортировки нужно передать массив:
new Sortable(document.querySelectorAll('.container'), {
draggable: '.item'
});
Пример структуры:
<div class="container"></div>
<div class="container"></div>
После перемещения элементов разработчики часто пытаются обновить состояние вручную, что приводит к рассинхронизации.
Неправильный подход:
draggable.on('sortable:sorted', () => {
saveOrder();
});
Если порядок элементов считывается до завершения DOM-обновления, результат может быть некорректным.
Лучший момент для чтения состояния — событие завершения:
draggable.on('drag:stop', () => {
const items = [...document.querySelectorAll('.item')];
});
При удалении компонентов интерфейса (например, в SPA-приложениях) необходимо корректно уничтожать экземпляр библиотеки.
Ошибка:
container.remove();
Обработчики событий остаются в памяти.
Правильный подход:
draggable.destroy();
container.remove();
Метод destroy():
Это особенно важно при работе с фреймворками интерфейса и частых перерисовках интерфейса.