Разработка канбан-доски с использованием react-dnd
Канбан-доска
Drag-and-Drop — одна из замечательных функций HTML5. Раньше мы полагались на события мыши javascript для достижения перетаскивания. Но HTML5 упростил рабочий процесс. Но заставить работать перетаскивание в среде React сложно. Потому что может возникнуть конфликт между прямым манипулированием DOM и виртуальным DOM, поддерживаемым React. Здесь на сцену выходит react-dnd — простая и прямая библиотека, которая помогает нам работать с перетаскиванием HTML5 в среде реагирования.
Код, используемый в этом руководстве, доступен по адресу
Также вы можете проверить это в приведенных ниже кодах и коробке.
Для начала нам нужно добавить две библиотеки.
$ npm install react-dnd react-dnd-html5-backend
$ npm install react-dnd react-dnd-html5-backend
- реагировать-днд обеспечивает всю логику и
- реагировать-dnd-html5-бэкэнд привязывает логику к API html5.
Для завершения рабочего процесса необходимо обработать три узла dom или компонент jsx.
- перетаскиваемые объекты : В нашем примере с доской Канбан каждый элемент задачи является перетаскиваемым объектом. Предметы, которые мы можем перетаскивать.
- сбрасываемые контейнеры: Каждый столбец на канбан-доске представляет собой переносной контейнер. Мы можем перетащить любой элемент задачи и поместить их в этот контейнер.
- Перетащите контекст: Оболочка, в которой заключены все перетаскиваемые объекты и выпадающие контейнеры. Это необходимо для установки границы и инициализации сцены. Можно иметь несколько перетаскиваний, имея несколько неперекрывающихся контекстов.
Все эти три функции реализованы как компоненты более высокого порядка, охватывающие компоненты представления.
import { DragDropContext, DropTarget, DragSource } from "react-dnd";
import HTML5Backend from "react-dnd-html5-backend";
Плата представлена нижеследующей структурой. Это может показаться немного сложным, но позвольте мне выделить некоторые моменты.
<section>
{channels.map(channel => (
<KanbanColumn status={channel}>
<div>
<div>{labelsMap[channel]}</div>
<div>
{tasks.filter(item => item.status === channel)
.map(item => (
<KanbanItem id={item._id} onDrop={this.update}>
<div style={classes.item}>{item.title}</div>
</KanbanItem>
))}
</div>
</div>
</KanbanColumn>
))}
</section>
У нас есть двухуровневый вложенный цикл dom с использованием Array.map, первый отображает столбцы доски канбан, а второй отображает элементы задачи. Также обратите внимание, что есть два компонента, которые я объясню позже. Но перед этим корневой компонент канбана должен быть связан с react-dnd, как показано ниже.
export default DragDropContext(HTML5Backend)(Kanban);
Выпадающий контейнер
Компонент колонки канбан-доски представлен ниже.
const boxTarget = {
drop(props) {
return { name: props.status };
}
};
class KanbanColumn extends React.Component {
render() {
return this.props.connectDropTarget(
<div>{this.props.children}</div>
);
}
}
KanbanColumn = DropTarget("kanbanItem", boxTarget,
(connect, monitor) => ({
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver(),
canDrop: monitor.canDrop()
}))(KanbanColumn);
коробкаЦель объект имеет коллекцию событий, которые нас интересуют. Здесь нас интересует только событие ‘drop’. Как только происходит событие удаления, мы сообщаем, что элемент задачи удаляется в конкретном столбце, который доступен в ‘props.status’.
Компонент KanbanColumn не содержит пользовательского интерфейса, вместо этого он передается как дочерний элемент.
Перетаскиваемый элемент
const boxSource = {
beginDrag(props) {
return {
name: props.id
};
},
endDrag(props, monitor) {
const item = monitor.getItem();
const dropResult = monitor.getDropResult();
if (dropResult) {
props.onDrop(monitor.getItem().name, dropResult.name);
}
}
};
class KanbanItem extends React.Component {
render() {
return this.props.connectDragSource(
<div>{this.props.children}</div>
);
}
}
KanbanItem = DragSource("kanbanItem", boxSource,
(connect, monitor) => ({
connectDragSource: connect.dragSource(),
isDragging: monitor.isDragging()
}))(KanbanItem);
Он похож на предыдущий компонент, но имеет кое-что дополнительное.
boxИсточник объект представляет собой интересующую нас коллекцию слушателей. На самом деле нас интересуют два события. Когда начинается перетаскивание, мы собираем идентификатор перетаскиваемого элемента. И когда сброс завершается, мы собираем имя столбца, на который он сбрасывается.
Всякий раз, когда происходит перетаскивание, нас интересуют две информации. Что тянут? А где предмет выпадает? Когда у нас есть оба, мы передаем их родительскому компоненту ( реквизит.onDrop )
И ответственность за изменение состояния лежит на родителе. В нашем примере мы используем библиотеку immutability-helper. Но есть много способов справиться с этим.
И последнее замечание. Это нормально работает только на компьютерах, а не на сенсорных экранах, потому что перетаскивание html5 изначально недоступно на сенсорных устройствах. Но есть и другие альтернативы бэкенду, которые отлично сочетаются с react-dnd.