Оптимизация больших списков

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

import Sortable from 'sortablejs';

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

Ключевые опции:

  • animation — скорость анимации перемещения элементов в миллисекундах.
  • handle — селектор, задающий область перетаскивания.
  • ghostClass — класс, применяемый к элементу, который временно отображается во время перемещения.

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

При работе с тысячами элементов стандартная инициализация SortableJS может вызывать значительные задержки. Основные методы оптимизации включают:

1. Использование делегирования событий

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

const sortable = new Sortable(list, {
    handle: '.handle',
    filter: '.disabled',
    onMove: (evt) => {
        return !evt.related.classList.contains('disabled');
    }
});

onMove вызывается на каждом перемещении, поэтому лучше минимизировать в нём вычисления.

2. Виртуализация списка

Для списков с тысячами элементов имеет смысл использовать виртуализацию, когда в DOM присутствует только видимая часть элементов. SortableJS совместим с виртуализированными списками, но важно правильно синхронизировать индексы:

// Использование виртуализатора (например, виртуального скролла)
const visibleItems = virtualScroll.getVisibleItems();
const sortable = new Sortable(container, {
    draggable: '.item',
    animation: 100
});

В этом случае библиотека перетаскивает только реально отображаемые элементы, что существенно снижает нагрузку на браузер.

3. Ограничение перетаскиваемой области

Опция draggable позволяет выбрать только подмножество элементов, которые могут быть перемещены. Это сокращает количество обработчиков событий и ускоряет работу:

const sortable = new Sortable(list, {
    draggable: '.draggable-item',
});

4. Минимизация DOM-операций

Каждое изменение позиции элемента приводит к перерисовке. Рекомендуется использовать классы для стилизации вместо частого изменения inline-стилей и минимизировать вызовы appendChild и insertBefore.


Расширенные события

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

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

Для больших списков важно избегать сложных операций внутри этих обработчиков. Например, обновление интерфейса или обращение к серверу лучше делать асинхронно или через requestAnimationFrame.

sortable.option("onEnd", function(evt) {
    requestAnimationFrame(() => {
        updateOrderInDatabase(evt.oldIndex, evt.newIndex);
    });
});

Использование групп и связки списков

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

const sortable1 = new Sortable(list1, {
    group: 'shared',
    animation: 150,
});

const sortable2 = new Sortable(list2, {
    group: 'shared',
    animation: 150,
});

Для оптимизации рекомендуется:

  • Ограничивать количество списков в одной группе.
  • Минимизировать проверку на допустимость перемещения (pull и put).

Кастомизация визуальных эффектов

Ghost и clone элементы

  • ghostClass — для временного отображения элемента при перетаскивании.
  • setData и onClone — для создания копий элементов без полного пересоздания DOM.
const sortable = new Sortable(list, {
    animation: 150,
    ghostClass: 'ghost',
    onClone: (evt) => {
        evt.clone.style.background = '#f0f0f0';
    }
});

Это помогает снизить нагрузку на браузер при больших списках, так как не происходит лишних манипуляций с DOM.


Практические рекомендации

  1. Ограничивать число одновременно инициализированных Sortable на странице.
  2. Использовать минимальный набор опций, отключать анимацию для огромных списков.
  3. Для списков более 1000 элементов рассматривать виртуализацию или ленивую подгрузку.
  4. События onMove и onSort должны выполнять только легкие вычисления.
  5. Избегать вложенных списков с высокой глубиной без необходимости, так как это резко увеличивает количество пересчетов стилей.

Эти подходы позволяют поддерживать плавное перетаскивание и отзывчивость интерфейса даже при работе с десятками тысяч элементов.