SortableJS — это лёгкая и мощная библиотека для реализации перетаскивания элементов на веб-страницах с помощью Drag-and-Drop API. Она поддерживает множество возможностей: сортировку списков, перенос элементов между списками, работу с вложенными структурами, а также оптимистичные обновления данных.
Инициализация
Для начала работы необходимо подключить библиотеку к проекту через npm или CDN:
import Sortable from 'sortablejs';
const list = document.getElementById('items');
Sortable.create(list, {
animation: 150,
ghostClass: 'sortable-ghost'
});
animation — определяет скорость анимации перемещения
элементов.ghostClass — CSS-класс, применяемый к элементу во время
перетаскивания.Пример конфигурации с обработкой событий:
Sortable.create(list, {
animation: 200,
handle: '.handle',
onEnd: function (evt) {
console.log(`Элемент перемещён с позиции ${evt.oldIndex} на ${evt.newIndex}`);
},
onAdd: function (evt) {
console.log('Элемент добавлен в список');
}
});
Оптимистичный подход предполагает немедленное обновление интерфейса при перетаскивании, ещё до подтверждения изменений на сервере. Это обеспечивает плавный пользовательский опыт. В контексте SortableJS оптимистичные обновления реализуются через:
onEnd.Пример оптимистичного обновления списка задач:
const tasks = [
{ id: 1, title: 'Сделать задачу A' },
{ id: 2, title: 'Сделать задачу B' },
{ id: 3, title: 'Сделать задачу C' }
];
const listElement = document.getElementById('tasks');
function renderTasks() {
listElement.innerHTML = '';
tasks.forEach(task => {
const li = document.createElement('li');
li.dataset.id = task.id;
li.classList.add('task-item');
li.innerHTML = `<span class="handle">☰</span> ${task.title}`;
listElement.appendChild(li);
});
}
renderTasks();
Sortable.create(listElement, {
animation: 150,
handle: '.handle',
onEnd: function (evt) {
const [movedTask] = tasks.splice(evt.oldIndex, 1);
tasks.splice(evt.newIndex, 0, movedTask);
// Отправка обновлённого порядка на сервер
fetch('/updateTasksOrder', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(tasks.map(t => t.id))
}).catch(() => {
// Откат изменений при ошибке
tasks.splice(evt.newIndex, 1);
tasks.splice(evt.oldIndex, 0, movedTask);
renderTasks();
});
}
});
Ключевые моменты оптимистичных обновлений:
SortableJS поддерживает перенос элементов между списками. Опция
group позволяет задавать группы и правила перемещения:
Sortable.create(list1, { group: 'shared', animation: 150 });
Sortable.create(list2, { group: 'shared', animation: 150 });
pull контролирует возможность извлечения
элементов из списка.put определяет возможность вставки элементов в
список.filter
позволяет блокировать перетаскивание некоторых элементов.onStart, onMove,
onClone обеспечивают гибкий контроль за поведением
при начале перемещения, во время движения и при клонировании
элемента.nestedSortable упрощает работу с древовидными структурами
данных.requestAnimationFrame для крупных списков
при обновлении элементов.onMove и onEnd.SortableJS легко интегрируется с React, Vue и Angular через специализированные обёртки или прямое использование в жизненном цикле компонентов. Важно поддерживать синхронизацию состояния списка с виртуальным DOM или реактивной моделью данных для корректной работы оптимистичных обновлений.