Управление состоянием

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


Инициализация и базовое состояние

Создание сортируемого списка начинается с вызова конструктора Sortable и передачи ему DOM-элемента списка:

import Sortable from 'sortablejs';

const listElement = document.getElementById('my-list');

const sortable = new Sortable(listElement, {
    animation: 150,
    ghostClass: 'sortable-ghost'
});

Ключевые параметры:

  • animation — скорость анимации при перетаскивании элементов в миллисекундах.
  • ghostClass — CSS-класс, применяемый к элементу во время перетаскивания.
  • draggable — селектор дочерних элементов, которые можно перетаскивать.
  • handle — селектор элемента внутри элемента списка, который служит “ручкой” для перетаскивания.

Базовое состояние списка хранится в DOM-порядке элементов. Для синхронизации с данными приложения рекомендуется использовать методы toArray() и sort().

const order = sortable.toArray(); // Получение текущего порядка элементов по их ID

Эти ID назначаются с помощью атрибута data-id для каждого элемента списка. Это позволяет сохранить уникальную идентификацию элементов при изменении порядка.


Отслеживание изменений состояния

SortableJS предоставляет систему событий для управления состоянием и синхронизации с приложением.

Основные события:

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

Пример отслеживания и сохранения нового порядка:

sortable.option("onEnd", function (evt) {
    const newOrder = sortable.toArray();
    console.log("Новый порядок элементов:", newOrder);
    // Можно обновить состояние приложения или отправить данные на сервер
});

Использование событий onAdd и onRemove позволяет поддерживать состояние нескольких связанных списков, обеспечивая точное отражение изменений в данных.


Синхронизация с моделью данных

Для большинства приложений важно, чтобы изменения в DOM отражались в структуре данных. Обычно это делается через массив объектов, где каждый объект соответствует элементу списка:

let items = [
    { id: 1, name: 'Элемент 1' },
    { id: 2, name: 'Элемент 2' },
    { id: 3, name: 'Элемент 3' }
];

Для синхронизации после перетаскивания применяется метод toArray():

sortable.option("onEnd", function () {
    const order = sortable.toArray(); // ['2', '1', '3']
    items.sort((a, b) => order.indexOf(String(a.id)) - order.indexOf(String(b.id)));
});

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


Работа с несколькими списками

SortableJS поддерживает перетаскивание элементов между списками через параметр group. Группы могут быть настроены с опциями pull и put для контроля направления перемещения:

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

new Sortable(listB, {
    group: 'shared'
});
  • pull — определяет, можно ли вытаскивать элементы из этого списка.
  • put — определяет, можно ли добавлять элементы в этот список.

Использование событий onAdd и onRemove позволяет корректно обновлять состояние обоих списков после перемещения элемента.


Сохранение состояния между сессиями

Для долговременного хранения состояния списка часто используют локальное хранилище (localStorage) или серверные запросы. Пример сохранения и восстановления порядка:

// Сохранение
sortable.option("onEnd", function () {
    localStorage.setItem('listOrder', JSON.stringify(sortable.toArray()));
});

// Восстановление
const savedOrder = JSON.parse(localStorage.getItem('listOrder'));
if (savedOrder) {
    savedOrder.forEach(id => {
        const element = document.querySelector(`[data-id='${id}']`);
        if (element) listElement.appendChild(element);
    });
}

Это гарантирует, что после перезагрузки страницы порядок элементов будет соответствовать последнему сохраненному состоянию.


Управление ограничениями и блокировкой элементов

SortableJS позволяет блокировать отдельные элементы или ограничивать перетаскивание с помощью CSS-классов и параметров:

  • draggable — ограничивает элементы, которые можно перетаскивать.
  • filter — предотвращает перетаскивание элементов с заданным селектором.
  • disabled — полная блокировка списка.

Пример фильтрации:

new Sortable(listElement, {
    filter: '.no-drag',
    onMove: function (evt) {
        return !evt.related.classList.contains('no-drag');
    }
});

Элементы с классом no-drag не будут участвовать в перетаскивании, сохраняя неизменное состояние.


Динамическое обновление состояния

SortableJS предоставляет методы для динамического изменения опций и состояния после инициализации:

  • sortable.option('disabled', true) — временно блокирует перетаскивание.
  • sortable.sort(newOrder) — программно изменяет порядок элементов.
  • sortable.destroy() — полностью удаляет функциональность сортировки, оставляя DOM нетронутым.

Программное изменение порядка через sort():

sortable.sort(['3', '1', '2']); // Устанавливает новый порядок по ID элементов

Этот подход удобен для синхронизации с внешними источниками данных, API или событиями приложения.


Ключевые моменты управления состоянием

  • Состояние списка в SortableJS определяется порядком элементов в DOM.
  • Использование data-id и toArray() обеспечивает безопасную синхронизацию с массивами данных.
  • События onEnd, onUpdate, onAdd, onRemove — основной инструмент отслеживания изменений.
  • Группы позволяют организовывать несколько взаимосвязанных списков.
  • Локальное хранилище или серверное API обеспечивает сохранение состояния между сессиями.
  • Методы sort(), option() и destroy() позволяют динамически управлять поведением и состоянием списка.

Эти механизмы делают SortableJS гибким инструментом для управления состоянием интерактивных списков и интеграции их в любые приложения на JavaScript.