Muuri — это мощная библиотека JavaScript для создания сеточных интерфейсов с динамическим размещением элементов. В контексте канбан-доски она позволяет реализовать перетаскиваемые карточки, автоматическое выравнивание элементов и плавную анимацию при изменении структуры доски. Основная идея заключается в том, чтобы каждая колонка канбан-доски представляла собой сетку Muuri, а карточки внутри колонок — элементы сетки.
Ключевые моменты:
Для каждой колонки канбан-доски создается отдельная сетка Muuri. Элементы сетки должны быть обернуты в контейнер с уникальным классом или идентификатором.
Пример структуры HTML:
<div class="kanban-column" id="todo">
<div class="kanban-item">Задача 1</div>
<div class="kanban-item">Задача 2</div>
</div>
<div class="kanban-column" id="in-progress">
<div class="kanban-item">Задача 3</div>
</div>
Инициализация сетки в Jav * aScript:
const todoGrid = new Muuri('#todo', {
dragEnabled: true,
layout: {
fillGaps: true,
horizontal: false
}
});
const inProgressGrid = new Muuri('#in-progress', {
dragEnabled: true,
layout: {
fillGaps: true,
horizontal: false
}
});
Объяснение ключевых опций:
dragEnabled: true — позволяет перетаскивать
элементы.layout.fillGaps: true — автоматически заполняет пустое
пространство при удалении или перемещении карточек.layout.horizontal: false — указывает вертикальное
расположение элементов внутри колонки.Для реализации перемещения карточек между колонками используется
событие dragReleaseEnd. Основная задача — определить новую
сетку, куда перемещается элемент, и обновить обе сетки.
Пример:
const allGrids = [todoGrid, inProgressGrid];
allGrids.forEach(grid => {
grid.on('dragReleaseEnd', (item) => {
const targetColumn = document.elementFromPoint(item.drag.x, item.drag.y).closest('.kanban-column');
if (!targetColumn) return;
const targetGrid = allGrids.find(g => g.getElement() === targetColumn);
if (targetGrid && targetGrid !== grid) {
grid.remove(item, { removeElements: false });
targetGrid.add(item.getElement());
}
});
});
Важные моменты:
removeElements: false предотвращает
удаление DOM-элемента при переносе между сетками.elementFromPoint позволяет точно определить
колонку под курсором.targetGrid.layout(true) для обновления позиции всех
карточек с анимацией.Muuri обеспечивает плавную анимацию при всех изменениях сетки.
Настроить скорость и тип анимации можно через опции
layoutDuration и layoutEasing.
const grid = new Muuri('.kanban-column', {
layoutDuration: 400,
layoutEasing: 'ease',
dragSortInterval: 50
});
Пояснение:
layoutDuration — длительность анимации в
миллисекундах.layoutEasing — функция плавности анимации
('ease', 'linear',
'ease-in-out').dragSortInterval — частота обновления сетки во время
перетаскивания, влияет на отзывчивость.Можно также добавить эффекты при наведении или активации карточки с помощью CSS-трансформаций, которые Muuri корректно учитывает при перерасчете расположения.
Для добавления новой задачи используется метод add:
const newItem = document.createElement('div');
newItem.classList.add('kanban-item');
newItem.textContent = 'Новая задача';
todoGrid.add(newItem);
todoGrid.layout(true);
Для удаления:
const itemToRemove = todoGrid.getItems()[0];
todoGrid.remove(itemToRemove, { removeElements: true });
todoGrid.layout(true);
Особенности:
removeElements: true полностью удаляет элемент из
DOM.layout(true) для корректного перерасчета позиций и
анимации.Muuri поддерживает сортировку и фильтрацию элементов сетки. Это полезно для реализации функционала «фильтр по приоритету» или «сортировка по дате».
Пример фильтрации по классу:
todoGrid.filter(item => item.getElement().classList.contains('high-priority'));
Сортировка по тексту карточки:
todoGrid.sort((a, b) => {
return a.getElement().textContent.localeCompare(b.getElement().textContent);
});
Для больших досок с сотнями карточек важно учитывать производительность:
dragSortPredicate для ограничения сеток,
между которыми может происходить перетаскивание.layout(true) во время
массовых изменений.Muuri позволяет создавать полностью интерактивные канбан-доски с поддержкой перетаскивания, анимаций, сортировки и фильтрации, обеспечивая при этом высокую отзывчивость интерфейса и гибкость настройки.