最近项目中要做一个拖动排序功能,首先想到的是之前项目中用过的antd自带的tree和table的拖动排序,但是只能在对应的组建里使用。这里用的是自定义组件,随意拖动排序,所以记录一下实现流程
- react-dnd antd组件的拖动排序都是用的这个库,使用比较灵活,但是要配置的东西比较多,需求复杂时使用这个库;
class BodyRow extends React.Component { render() { const { isOver, connectDragSource, connectDropTarget, moveRow, ...restProps } = this.props; const style = { ...restProps.style, cursor: 'move' }; let { className } = restProps; if (isOver) { if (restProps.index > dragingIndex) { className += ' drop-over-downward'; } if (restProps.index < dragingIndex) { className += ' drop-over-upward'; } } return connectDragSource( connectDropTarget(<tr {...restProps} className={className} style={style} />), ); } } const rowSource = { beginDrag(props) { dragingIndex = props.index; return { index: props.index, }; }, }; const rowTarget = { drop(props, monitor) { const dragIndex = monitor.getItem().index; const hoverIndex = props.index; // Don't replace items with themselves if (dragIndex === hoverIndex) { return; } // Time to actually perform the action props.moveRow(dragIndex, hoverIndex); // Note: we're mutating the monitor item here! // Generally it's better to avoid mutations, // but it's good here for the sake of performance // to avoid expensive index searches. monitor.getItem().index = hoverIndex; }, }; const DragableBodyRow = DropTarget('row', rowTarget, (connect, monitor) => ({ connectDropTarget: connect.dropTarget(), isOver: monitor.isOver(), }))( DragSource('row', rowSource, connect => ({ connectDragSource: connect.dragSource(), }))(BodyRow), ); <DndProvider backend={HTML5Backend}> <Table columns={columns} dataSource={this.state.data} components={this.components} onRow={(record, index) => ({ index, moveRow: this.moveRow, })} /> </DndProvider>
- react-beautiful-dnd 在项目中看到引用了这个库,使用起来也不算复杂,就试着用了这个库,不过只支持水平或垂直拖动,一行或者一列元素时可以使用,可惜这个需求时两行多列元素,也没办法用;
<DragDropContext onDragEnd={this.onDragEnd}> <Droppable droppableId='phone-droppable'> {droppableProvided => ( <div ref={droppableProvided.innerRef} {...droppableProvided.droppableProps}> {this.state.phoneImages.map((image, index) => ( <Draggable key={image||'upload'} draggableId={image||'upload'} index={index}> {(provided, snapshot) => ( <div ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps} style={{ ...provided.draggableProps.style, opacity: snapshot.isDragging ? 0.8 : 1, display: 'inline-block' }} > <img src={img}/> </div> )} </Draggable> ))} {droppableProvided.placeholder} </div> )} </Droppable> </DragDropContext>
- react-sortable-hoc 最后在网上搜索的时候,又看到这个库,使用起来比较简单,使用SortableList包裹要拖拽元素的容器,SortableElement包裹要拖拽的子元素,设置容器拖拽方向
axis={'xy'}
即可使grid布局的多个元素支持水平和竖直方向拖动排序;const SortableItem = SortableElement(({children}) => ( <div>{children}</div> )); const SortableList = SortableContainer(({children}) => { return ( <div style={{display: 'grid', gridTemplateRows: '117px 117px', gridTemplateColumns: '120px 120px 120px 120px'}}> {children} </div> ); }); <SortableList onSortEnd={this.onPadSortEnd} helperClass={Styles.sortableHelper} axis={'xy'}> {this.state.padImages.map((image, index) => ( <SortableItem key={`pad-item-${index}`} index={index} className={Styles.sortableItem}> <img src={img}/> </SortableItem> ))} </SortableList>
好久没更新博客了,最近工作比较忙,差不多每天都要加班,中间有经历搬家,没时间坐下来总结学到的东西。工作的时候因为这块花费了一些时间,想到可能别人也会遇到类似问题,所以就记录下来了