Миграция с других библиотек

SortableJS — современная, лёгкая и высокоэффективная библиотека для реализации функционала drag-and-drop в веб-приложениях. Она отличается простотой интеграции, поддержкой touch-устройств и широкими возможностями кастомизации. Переход с других библиотек требует внимательного подхода, чтобы сохранить существующую функциональность и минимизировать изменение бизнес-логики.


Отличия архитектуры SortableJS от популярных альтернатив

Основные библиотеки для drag-and-drop, с которыми чаще всего выполняют миграцию:

  • jQuery UI Sortable Использует jQuery как основу, оперирует событиями start, stop, update. Сильно завязан на DOM-структуру и jQuery-события.

  • Dragula Простая в использовании, работает с контейнерами, поддерживает перенос элементов между списками, но ограничена в тонкой настройке анимаций и фильтров.

  • Interact.js Более общий инструмент для drag-and-drop и жестов, с богатым API, но менее специализирован для сортируемых списков.

SortableJS сочетает лучшие черты этих библиотек: лёгкость Dragula, гибкость Interact.js и понятный API jQuery UI Sortable.


Основные концепции SortableJS

Инициализация выполняется через создание экземпляра Sortable на DOM-элементе-контейнере:

const sortable = new Sortable(containerElement, {
    animation: 150,
    handle: '.handle',
    ghostClass: 'sortable-ghost',
    chosenClass: 'sortable-chosen',
    onEnd: function(evt) {
        console.log(`Элемент ${evt.item.textContent} перемещён с позиции ${evt.oldIndex} на ${evt.newIndex}`);
    }
});
  • animation — плавность анимации перемещения элементов.
  • handle — селектор элемента, за который можно тянуть item.
  • ghostClass — класс для “призрачного” элемента во время перетаскивания.
  • chosenClass — класс выбранного элемента.
  • onEnd — событие завершения сортировки.

В отличие от jQuery UI Sortable, события имеют унифицированные объекты с полями item, from, to, oldIndex, newIndex, что упрощает обработку и интеграцию с данными.


Преобразование событий и обработчиков

jQuery UI Sortable использует:

$('#list').sortable({
    update: function(event, ui) {
        console.log(ui.item.index());
    }
});

SortableJS эквивалентно:

new Sortable(document.getElementById('list'), {
    onEnd: function(evt) {
        console.log(evt.newIndex);
    }
});

Особенности миграции:

  • ui.itemevt.item
  • ui.item.index()evt.oldIndex / evt.newIndex
  • updateonEnd
  • jQuery-события полностью убираются; используется нативный DOM.

Работа с множественными списками

SortableJS поддерживает объединение списков через group:

const listA = new Sortable(document.getElementById('listA'), {
    group: 'shared',
    animation: 150
});

const listB = new Sortable(document.getElementById('listB'), {
    group: 'shared',
    animation: 150
});
  • Элементы можно перетаскивать между списками.
  • Настройка pull и put позволяет контролировать направление перемещения.

Пример ограничения:

group: {
    name: 'shared',
    pull: 'clone', // клонирование при перетаскивании
    put: false     // запрещаем вставку в данный список
}

Это особенно важно при миграции с Dragula, где подобные правила задавались через функции фильтрации.


Фильтры и запрет на перетаскивание

SortableJS позволяет блокировать определённые элементы через filter и событие onMove:

const sortable = new Sortable(container, {
    filter: '.no-drag',
    onMove: function(evt) {
        return !evt.related.classList.contains('no-drop');
    }
});
  • filter предотвращает начало перетаскивания по заданному селектору.
  • onMove контролирует возможность перемещения элемента на конкретное место.

Это заменяет jQuery UI cancel и Dragula invalid.


Синхронизация с данными

Сортировка в SortableJS возвращает индекс элемента, но для синхронизации с массивами часто используется следующий подход:

let items = ['a', 'b', 'c', 'd'];

new Sortable(container, {
    onEnd: function(evt) {
        const movedItem = items.splice(evt.oldIndex, 1)[0];
        items.splice(evt.newIndex, 0, movedItem);
    }
});
  • Поддержка двух направлений: визуальная перестановка и обновление данных.
  • Для сложных структур (объекты с id) достаточно использовать dataset элементов для сопоставления с массивом.

Настройка анимаций и визуальных эффектов

SortableJS предоставляет гибкую систему CSS-классов и анимаций:

  • ghostClass — стиль элемента-пустышки.
  • chosenClass — выделение выбранного элемента.
  • dragClass — опционально, для перетаскиваемого элемента.

Пример плавной анимации при перестановке:

new Sortable(container, {
    animation: 200,
    easing: 'cubic-bezier(0.25, 0.8, 0.25, 1)'
});

Анимации в Dragula реализуются вручную, в jQuery UI через jQuery .animate(). SortableJS интегрирует их напрямую, что упрощает поддержку и снижает зависимость от внешних библиотек.


Расширение функционала

SortableJS поддерживает расширения и плагины:

  • AutoScroll — автоматическая прокрутка при перетаскивании к краю контейнера.
  • Swap — меняет элементы местами без перетаскивания через пространство.
  • MultiDrag — выбор и перемещение нескольких элементов одновременно.

Пример подключения MultiDrag:

import Sortable from 'sortablejs/modular/sortable.esm.js';
import MultiDrag from 'sortablejs/plugins/MultiDrag';

Sortable.mount(new MultiDrag());

new Sortable(container, {
    multiDrag: true,
    selectedClass: 'selected'
});

Миграция с библиотек, не поддерживающих мультидраг, требует адаптации интерфейса, но API остаётся последовательным и читаемым.


Особенности миграции с точки зрения производительности

  • SortableJS оптимизирован для работы с большими списками.
  • Использует requestAnimationFrame для анимаций, минимизируя перерасчёты DOM.
  • Не требует jQuery, что снижает нагрузку и уменьшает размер бандла.

Для приложений, ранее использующих jQuery UI Sortable на сотнях элементов, переход к SortableJS улучшает отзывчивость интерфейса и сокращает время загрузки.