Стратегии миграции

SortableJS — это лёгкая и мощная библиотека на JavaScript, позволяющая создавать интерактивные списки с поддержкой drag-and-drop. Библиотека работает с любыми HTML-элементами, обеспечивая высокую производительность и гибкость. Основной объект взаимодействия — это Sortable, который инициализируется на контейнере элементов.

import Sortable from 'sortablejs';

const list = document.getElementById('items');
const sortable = new Sortable(list, {
    animation: 150,
    ghostClass: 'sortable-ghost',
});

Здесь ключевые параметры:

  • animation — скорость анимации при перемещении элементов (в миллисекундах).
  • ghostClass — CSS-класс, применяемый к перемещаемому элементу для визуального эффекта.

Настройка поведения перетаскивания

SortableJS предоставляет множество опций для тонкой настройки поведения:

  • handle — определяет, за какую часть элемента можно захватывать его для перетаскивания.
  • filter — исключает элементы из перетаскивания по селектору.
  • draggable — задаёт, какие дочерние элементы контейнера могут быть перетаскиваемыми.
  • group — позволяет объединять несколько списков, обеспечивая перетаскивание между ними.

Пример:

new Sortable(list, {
    handle: '.handle',
    filter: '.non-draggable',
    draggable: '.item',
    group: 'shared',
});

События и их обработка

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

  • onStart — вызывается при начале перемещения элемента.
  • onEnd — вызывается по завершении перемещения, даже если элемент вернулся на место.
  • onAdd — срабатывает, когда элемент добавлен из другого списка.
  • onUpdate — срабатывает, когда элемент перемещён внутри текущего списка.
  • onRemove — вызывается при удалении элемента из списка.

Пример использования событий:

sortable.option('onEnd', function(evt) {
    console.log(`Элемент ${evt.item.textContent} перемещён с позиции ${evt.oldIndex} на ${evt.newIndex}`);
});

Миграция данных и интеграция с состоянием

SortableJS не хранит состояние элементов. Для синхронизации с массивами данных необходимо обновлять их вручную. Наиболее надёжная стратегия — обработка событий onEnd или onUpdate:

const items = ['Яблоко', 'Банан', 'Апельсин'];

const list = document.getElementById('items');
const sortable = new Sortable(list, {
    onEnd: function(evt) {
        const movedItem = items.splice(evt.oldIndex, 1)[0];
        items.splice(evt.newIndex, 0, movedItem);
        console.log(items);
    }
});

Таким образом, массив items всегда отражает текущее положение элементов в DOM.

Сложные сценарии: несколько списков

SortableJS поддерживает работу с группами, что позволяет реализовать перетаскивание между списками. При этом используется опция group, которая может быть объектом с настройками:

const listA = document.getElementById('listA');
const listB = document.getElementById('listB');

new Sortable(listA, {
    group: { name: 'shared', pull: 'clone', put: true },
    animation: 150
});

new Sortable(listB, {
    group: 'shared',
    animation: 150
});
  • pull: 'clone' — при перетаскивании из списка создаётся копия элемента.
  • put: true — разрешает помещать элементы из других списков.

Для обновления данных при перемещении между списками необходимо обрабатывать событие onAdd:

onAdd: function(evt) {
    const item = evt.item.textContent;
    const fromArray = evt.from.id === 'listA' ? arrayA : arrayB;
    const toArray = evt.to.id === 'listA' ? arrayA : arrayB;
    
    fromArray.splice(evt.oldIndex, 1);
    toArray.splice(evt.newIndex, 0, item);
}

Поддержка сложных элементов

SortableJS корректно работает с элементами любой структуры, включая вложенные контейнеры, таблицы и списки с изображениями. Рекомендуется использовать CSS-класс handle для перетаскивания конкретных областей, чтобы избежать случайного перемещения при кликах внутри элемента.

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

Для списков с большим количеством элементов важно:

  • Использовать минимальные DOM-операции внутри событий onUpdate и onEnd.
  • Ограничивать CSS-анимации, которые могут влиять на перерисовку страницы.
  • Использовать animation: 0 при массовых перемещениях, например при динамическом обновлении данных.

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

SortableJS можно интегрировать с фреймворками:

  • React: через создание обёртки ref на контейнер.
  • Vue: через директиву v-sortable или обёртку компонента.
  • Angular: через прямое связывание с ViewChild.

Также библиотека поддерживает плагины, например AutoScroll, который автоматически прокручивает контейнер при перетаскивании элемента к краю области.

Работа с сериализацией и восстановлением состояния

Для сохранения порядка элементов в локальном хранилище или на сервере удобно использовать массив данных, синхронизированный с DOM:

function saveOrder(array) {
    localStorage.setItem('itemsOrder', JSON.stringify(array));
}

function loadOrder() {
    return JSON.parse(localStorage.getItem('itemsOrder') || '[]');
}

При инициализации списка можно восстановить порядок:

const savedOrder = loadOrder();
savedOrder.forEach(text => {
    const li = document.createElement('li');
    li.textContent = text;
    list.appendChild(li);
});

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

Стратегии миграции между версиями

При обновлении SortableJS или переходе между проектами важно учитывать:

  • Смена API опций (onEnd и onUpdate иногда меняют структуру события).
  • Обновление обработчиков для нескольких списков.
  • Корректная миграция массивов данных при изменении структуры DOM.
  • Проверка совместимости с используемыми плагинами.

Подходящий метод — сначала создать обёртку для работы с DOM, а затем привязать события к массивам данных, чтобы при изменении версии библиотеки минимизировать изменение бизнес-логики.