Состояния элементов

В библиотеке Shopify Draggable управление состояниями элементов является ключевым аспектом при создании интерактивных интерфейсов. Состояние элемента определяет, как он реагирует на действия пользователя, такие как перетаскивание, захват, отпускание или нахождение над зоной-дропом. Понимание этих состояний позволяет строить более гибкие и отзывчивые UI-компоненты.


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

Draggable выделяет несколько стандартных состояний элементов:

  1. Idle (покой) Элемент находится в нормальном состоянии, не взаимодействует с пользователем. В этом состоянии отсутствуют активные события перетаскивания. Обычно это исходное состояние всех элементов.

  2. Dragging (перетаскивание) Элемент находится под воздействием действия пользователя: зажат и перемещается. В этом состоянии можно изменить визуальное отображение, добавив тени, изменив прозрачность или масштаб.

    draggable.on('drag:start', (event) => {
        event.source.classList.add('is-dragging');
    });
    
    draggable.on('drag:stop', (event) => {
        event.source.classList.remove('is-dragging');
    });

    Здесь event.source — это DOM-элемент, который перетаскивается.

  3. Mirror (зеркало) Когда элемент перетаскивается, Draggable создаёт mirror-элемент, который визуально повторяет оригинальный. Mirror позволяет пользователю видеть, что элемент активен, без непосредственного изменения исходного DOM-узла. Mirror создаётся автоматически, но его поведение можно настраивать через события:

    draggable.on('mirror:create', (event) => {
        event.mirror.classList.add('custom-mirror');
    });
    
    draggable.on('mirror:destroy', (event) => {
        event.mirror.classList.remove('custom-mirror');
    });
  4. Over (над дроп-зоной) Когда перетаскиваемый элемент находится над зоной-дропом, он попадает в состояние over. Это состояние удобно использовать для визуального подсвечивания зоны, куда можно переместить элемент.

    draggable.on('droppable:over', (event) => {
        event.related.classList.add('is-over');
    });
    
    draggable.on('droppable:out', (event) => {
        event.related.classList.remove('is-over');
    });

    Здесь event.related — это DOM-элемент зоны-дропа.


Настройка пользовательских состояний

Помимо стандартных, можно создавать свои состояния для более сложной логики. Например, выделение элементов, которые можно перемещать только при определённых условиях:

draggable.on('drag:start', (event) => {
    if (!event.source.classList.contains('draggable-enabled')) {
        event.cancel(); // предотвращает начало перетаскивания
    } else {
        event.source.classList.add('is-active');
    }
});

Взаимодействие между состояниями

Состояния элементов могут переключаться динамически. Например, mirror-элемент всегда создаётся в момент начала перетаскивания и уничтожается при отпускании. Если элемент одновременно находится над зоной-дроп, mirror может наследовать визуальные эффекты over.

Важно учитывать порядок событий:

  1. drag:start – элемент начинает перетаскиваться, создаётся mirror.
  2. mirror:create – mirror получает стили и позиции.
  3. drag:move – обновление позиции mirror.
  4. droppable:over/droppable:out – смена состояния зоны-дропа.
  5. drag:stop – завершение перетаскивания.
  6. mirror:destroy – уничтожение mirror.

Правильная синхронизация этих состояний обеспечивает плавный пользовательский опыт.


Управление стилями через классы

Draggable рекомендует использовать CSS-классы для отображения состояний. Основные подходы:

  • .is-dragging – для активного перетаскивания.
  • .is-over – для зоны-дропа при наведении.
  • .is-active – для элементов, доступных к перетаскиванию.
  • .custom-mirror – для mirror с пользовательской стилизацией.

Пример CSS:

.is-dragging {
    opacity: 0.6;
    transform: scale(1.05);
    z-index: 1000;
}

.is-over {
    border: 2px dashed #3498db;
    background-color: rgba(52, 152, 219, 0.1);
}

.custom-mirror {
    box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
    pointer-events: none;
}

Состояния в комплексных интерфейсах

В многоуровневых интерфейсах можно комбинировать несколько Draggable-инстансов с разными состояниями. Например, списки внутри вкладок, где элементы одних списков можно перемещать только внутрь своего списка. Для этого применяются условия в событиях:

draggable.on('drag:move', (event) => {
    if (!event.over || event.over.dataset.listId !== event.source.dataset.listId) {
        event.cancel();
    }
});

Такой подход обеспечивает строгий контроль над доступными состояниями и действиями пользователя.


Рекомендации по оптимизации

  • Ограничивать количество mirror-элементов и следить за их уничтожением.
  • Использовать CSS-переходы для плавного изменения состояний.
  • Минимизировать DOM-операции внутри событий drag:move, чтобы избежать лагов.
  • Явно управлять состояниями зон-дропа, чтобы предотвратить конфликт визуальных эффектов.

С помощью грамотного управления состояниями элементов в Shopify Draggable можно создавать интерфейсы, где пользовательский опыт будет максимально интуитивным и отзывчивым, а логика взаимодействия — чёткой и предсказуемой.