SortableJS — мощная библиотека для реализации функционала перетаскивания элементов списка (drag-and-drop) в веб-приложениях на JavaScript. Она позволяет не только сортировать элементы внутри одного списка, но и создавать связанные списки, где элементы можно переносить между разными контейнерами с сохранением порядка и реакцией на события.
Для создания связанных списков требуется инициировать Sortable на каждом контейнере. Ключевой момент — указание общего group. Это позволяет элементам свободно перемещаться между списками, принадлежащими одной группе.
const listA = document.getElementById('listA');
const listB = document.getElementById('listB');
Sortable.create(listA, {
group: 'shared', // Группа, объединяющая списки
animation: 150, // Плавная анимация перемещения
ghostClass: 'sortable-ghost', // CSS-класс для элемента во время перетаскивания
});
Sortable.create(listB, {
group: 'shared',
animation: 150,
ghostClass: 'sortable-ghost',
});
Ключевые моменты:
group может быть строкой (одна группа) или объектом для
более гибкой настройки.animation делает перемещение элементов визуально более
плавным.ghostClass позволяет стилизовать перетаскиваемый
элемент.Группы поддерживают расширенные опции через объект:
Sortable.create(listA, {
group: {
name: 'shared',
pull: 'clone', // Элемент копируется при переносе
put: true // Разрешение на вставку элементов из других списков
},
animation: 150
});
Разбор опций:
pull: true | false | 'clone' Управляет поведением
при перетаскивании.
true — элемент можно переносить.'clone' — создается копия элемента, оригинал остаётся
на месте.put: true | false | [имена групп] Разрешает вставку
элементов из других групп. Можно указать массив групп, чтобы разрешить
выборочно.
SortableJS предоставляет множество событий для работы со связанными списками:
onAdd — срабатывает, когда элемент
добавлен в список.onRemove — элемент удален из текущего
списка.onUpdate — элемент изменил позицию
внутри текущего списка.onEnd — завершается процесс
перетаскивания.Пример использования:
Sortable.create(listB, {
group: 'shared',
animation: 150,
onAdd: function (evt) {
console.log('Элемент добавлен:', evt.item);
},
onRemove: function (evt) {
console.log('Элемент удалён:', evt.item);
},
onUpdate: function (evt) {
console.log('Порядок изменён внутри списка:', evt.to);
}
});
Эти события позволяют динамически обновлять данные на сервере, менять состояние интерфейса или производить анимации.
При работе с связанными списками важно поддерживать актуальность данных. Стандартная практика — использовать массивы, представляющие элементы каждого списка:
let dataA = ['Элемент 1', 'Элемент 2'];
let dataB = ['Элемент 3', 'Элемент 4'];
function updateData(evt) {
const fromList = evt.from.id === 'listA' ? dataA : dataB;
const toList = evt.to.id === 'listA' ? dataA : dataB;
const movedItem = fromList.splice(evt.oldIndex, 1)[0];
toList.splice(evt.newIndex, 0, movedItem);
console.log('Списки после перемещения:', dataA, dataB);
}
Sortable.create(listA, {
group: 'shared',
onEnd: updateData
});
Sortable.create(listB, {
group: 'shared',
onEnd: updateData
});
Преимущества такой схемы:
Фильтрация элементов Исключение определённых элементов из перетаскивания:
filter: '.non-draggable',
preventOnFilter: true
Элементы с классом .non-draggable будут
статичными.
Кастомные анимации Используя CSS и классы
ghostClass, chosenClass,
dragClass можно создавать уникальные визуальные
эффекты.
Перетаскивание по условию Возможность
динамически включать или отключать перемещение через
disabled:
sortable.option("disabled", true);Сложные иерархические списки В связке с плагинами или собственным кодом можно создавать вложенные списки с поддержкой drag-and-drop между уровнями.
<ul id="listA" class="sortable-list">
<li>Элемент 1</li>
<li>Элемент 2</li>
</ul>
<ul id="listB" class="sortable-list">
<li>Элемент 3</li>
<li>Элемент 4</li>
</ul>
Стилизация может включать:
.sortable-list {
border: 1px solid #ccc;
padding: 10px;
min-height: 50px;
width: 200px;
list-style: none;
}
.sortable-ghost {
opacity: 0.4;
}
Такой подход создаёт чёткую визуальную и функциональную структуру, позволяющую реализовать полные возможности связанных списков.
Этот метод организации позволяет создавать динамичные интерфейсы с перемещаемыми элементами между разными контейнерами, при этом сохраняя контроль над данными и стилями.