В Shopify Draggable вложенные списки позволяют реализовать сложные интерфейсы перетаскивания с иерархической структурой элементов. Каждый элемент списка может содержать дочерние элементы, которые сами являются draggable-элементами. Такая структура особенно полезна для управления категориями, меню и деревьями объектов в приложениях e-commerce.
Для работы с вложенными списками используются два ключевых компонента Draggable: Draggable и Sortable. Sortable наследует возможности Draggable и добавляет поддержку сортировки элементов в пределах контейнера.
import {Sortable} from '@shopify/draggable';
const sortable = new Sortable(document.querySelectorAll('.nested-list'), {
draggable: '.draggable-item',
swapAnimation: {
duration: 200,
easingFunction: 'ease-in-out',
},
handle: '.drag-handle',
});
Здесь:
.nested-list — контейнер верхнего уровня, который может
содержать другие списки;.draggable-item — элемент, который можно
перемещать;handle — элемент, за который можно “хватать” объект;
без handle весь элемент перетаскивается при клике на любую его
часть;swapAnimation отвечает за плавное перемещение
элементов.Правильная структура DOM — ключ к корректной работе вложенных
списков. Обычно используется вложение и
:
-
Пункт 1
- Подпункт 1.1
- Подпункт 1.2
- Пункт 2
Важно, чтобы все вложенные элементы имели одинаковый класс для
draggable (.draggable-item) и были частью родительского
контейнера (.nested-list). Draggable автоматически
определяет дочерние элементы и позволяет им быть sortable внутри своих
родительских списков.
Draggable поддерживает сортировку внутри контейнера и между контейнерами. Для вложенных списков можно задать несколько уровней, используя containers:
const nestedSortable = new Sortable(document.querySelectorAll('.nested-list'), {
draggable: '.draggable-item',
handle: '.drag-handle',
swapAnimation: {
duration: 200,
easingFunction: 'ease-in-out',
},
mirror: {
constrainDimensions: true,
},
containers: Array.from(document.querySelectorAll('.nested-list')),
});
Параметр containers указывает, где разрешено перемещать
элементы. Для вложенных списков это особенно важно: можно ограничить
перемещение элементов только в пределах родительского контейнера или
разрешить перенос между уровнями.
Элемент mirror — это копия перетаскиваемого объекта, которая следует за курсором. Для вложенных списков важно правильно настроить mirror, чтобы избежать визуальных сбоев при перемещении дочерних элементов:
mirror: {
constrainDimensions: true, // сохраняет размер оригинала
appendTo: 'body', // добавляет mirror в body, чтобы не ломать структуру DOM
},
Дополнительно можно использовать CSS для mirror:
.draggable-mirror {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
border-radius: 4px;
background-color: #fff;
}
Draggable предоставляет события для управления логикой при перетаскивании элементов. Для вложенных списков наиболее полезны:
sortable:stop — срабатывает после завершения
перемещения элемента;sortable:sort — срабатывает при каждом изменении
позиции;sortable:swap — когда элементы меняются местами.Пример привязки событий:
nestedSortable.on('sortable:stop', (event) => {
const item = event.data.dragEvent.source;
const parent = item.parentElement;
console.log('Элемент перемещен:', item.textContent, 'в родителя:', parent);
});
Эти события позволяют обновлять данные на сервере или синхронизировать структуру с внутренним состоянием приложения.
-
☰ Пункт 1
- ☰ Подпункт 1.1
- ☰ Подпункт 1.2
- ☰ Пункт 2
const nestedSortable = new Sortable(document.querySelectorAll('.nested-list'), {
draggable: '.draggable-item',
handle: '.drag-handle',
swapAnimation: {duration: 200, easingFunction: 'ease-in-out'},
mirror: {constrainDimensions: true, appendTo: 'body'},
containers: Array.from(document.querySelectorAll('.nested-list')),
});
Эта структура обеспечивает корректное перетаскивание на всех уровнях вложенности, плавную анимацию и визуальное сопровождение при перемещении элементов.