Ограничения области перетаскивания

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


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

По умолчанию элементы Muuri могут перетаскиваться свободно внутри контейнера сетки. Чтобы ограничить область перемещения, используется свойство dragContainer. Оно определяет DOM-элемент, внутри которого перетаскиваемый элемент может перемещаться:

const grid = new Muuri('.grid', {
  dragEnabled: true,
  dragContainer: document.querySelector('.drag-area')
});

Ключевые моменты:

  • dragContainer может быть любым элементом DOM, включая сам контейнер сетки или отдельный блок внутри страницы.
  • Если dragContainer не указан, по умолчанию областью перетаскивания считается вьюпорт страницы.
  • Ограничение контейнера предотвращает выход элементов за пределы указанного блока, сохраняя визуальную целостность интерфейса.

Ограничение перетаскивания по осям

Muuri позволяет контролировать движение элементов по горизонтали и вертикали с помощью опции dragAxis. Значения могут быть следующими:

  • 'x' — движение только по горизонтали.
  • 'y' — движение только по вертикали.
  • null — разрешено движение по обеим осям.

Пример:

const grid = new Muuri('.grid', {
  dragEnabled: true,
  dragAxis: 'y'
});

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


Ограничение области через события drag

Для более тонкого контроля над перетаскиванием Muuri предоставляет события dragStart, dragMove и dragEnd. С их помощью можно динамически ограничивать позицию элемента:

grid.on('dragMove', function (item, event) {
  const dragElement = item.getElement();
  const bounds = dragElement.parentElement.getBoundingClientRect();
  const mouseX = event.clientX;
  const mouseY = event.clientY;

  if (mouseX < bounds.left) event.preventDefault();
  if (mouseX > bounds.right) event.preventDefault();
  if (mouseY < bounds.top) event.preventDefault();
  if (mouseY > bounds.bottom) event.preventDefault();
});

Примечания:

  • Событие dragMove вызывается при каждом движении мыши, что позволяет проверять текущие координаты элемента.
  • Использование event.preventDefault() останавливает перемещение элемента за пределами границ.

Ограничение перетаскивания по сетке

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

  • dragSort — включает сортировку элементов при перетаскивании.
  • dragSortPredicate — позволяет задавать логику определения позиции элемента.

Пример ограничения элементов только внутри текущей строки:

const grid = new Muuri('.grid', {
  dragEnabled: true,
  dragSort: true,
  dragSortPredicate: {
    threshold: 50,
    action: 'move',
    sortBy: 'y'
  }
});

Особенности:

  • threshold задает минимальное смещение, необходимое для перемещения элемента.
  • sortBy: 'y' гарантирует, что элементы будут перемещаться только по вертикальной оси, сохраняя горизонтальные позиции.

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

Иногда достаточно использовать CSS-свойства контейнера, чтобы предотвратить выход элементов за пределы области:

.drag-area {
  overflow: hidden;
  position: relative;
}
.grid-item {
  position: absolute;
}

Преимущества:

  • Простое решение без необходимости сложной логики в JavaScript.
  • Совместимо с dragContainer и событиями dragMove.

Минусы:

  • Не блокирует полностью движение элемента на уровне Muuri, только визуально обрезает его.
  • Требует сочетания с другими методами для точного контроля.

Ограничение перетаскивания для отдельных элементов

Muuri позволяет задавать индивидуальные ограничения для каждого элемента, используя опцию dragEnabled на уровне элемента и события dragMove:

grid.getItems().forEach(item => {
  if (item.getElement().classList.contains('fixed')) {
    item.disableDrag();
  }
});

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


Комбинирование всех методов

На практике чаще всего используется комбинация трёх подходов:

  1. dragContainer — ограничивает физическую область перемещения.
  2. dragAxis — ограничивает направление движения.
  3. dragMove + проверки координат — точная настройка границ для сложных интерфейсов.

Пример комплексной конфигурации:

const grid = new Muuri('.grid', {
  dragEnabled: true,
  dragContainer: document.querySelector('.drag-area'),
  dragAxis: 'x'
});

grid.on('dragMove', function(item, event) {
  const bounds = item.getElement().parentElement.getBoundingClientRect();
  if (event.clientX < bounds.left || event.clientX > bounds.right) {
    event.preventDefault();
  }
});

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