react Dnd结合antd table实现跨表格拖拽放置和组内拖拽改变顺序
封装通用的可拖拽表格
import React, { useState, useCallback, useRef, useEffect } from 'react';
import { DndProvider, useDrag, useDrop } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import { message, Table } from 'antd';
import update from 'immutability-helper';
const ItemTypes = {
ROW: 'row',
};
function DragTable(props) {
const {
dataSource,
columns,
onChange,
is,
k,
rowSelection,
pagination,
...tableProps
} = props;
const [list, setList] = useState([]);
const [error, setError] = useState('');
useEffect(() => {
setList(dataSource);
}, [dataSource]);
const handleDrag = useCallback(
(col, hoverIndex) => {
if (k !== col.record.key) {
console.log(k, col.record.key);
message.error('不同库不允许操作');
return;
}
let dragItem = col.record;
let newList = [];
let flag = list.some((v, i) => {
if (v.id === dragItem.id) {
return true;
} else {
return false;
}
});
if (flag) {
//组内交换顺序
newList = update(list, {
$splice: [
[col.index, 1],
[hoverIndex, 0, dragItem],
],
});
} else {
//跨表格拖拽
newList = [...list];
newList.splice(hoverIndex, 0, dragItem);
}
setList(newList);
onChange(newList, dragItem, is, k, flag);
},
[list]
);
const DraggableRow = (props) => {
const {
index,
record,
handleDrag,
rowSelection,
pagination,
...restProps
} = props;
const ref = useRef(null);
// 接收
const [{ isOver, canDrop }, drop] = useDrop({
accept: ItemTypes.ROW,
drop: (col) => handleDrag(col, index),
canDrop: (item) => {
setError(undefined);
const filter = list.filter((it) => it.id === item.id);
if (!!filter.length) {
setError('数据已经被放置');
return false;
}
return true;
},
collect: (monitor) => ({
isOver: monitor.isOver(),
canDrop: monitor.canDrop(),
}),
});
const rowStyle = { ...restProps.style };
if (isOver && canDrop) {
rowStyle.background = '#f0f4f8';
}
// 拖拽
const [{ isDragging }, drag] = useDrag({
// item: { type: ItemTypes.ROW, record, index },
type: ItemTypes.ROW,
item: () => {
return { record, index };
},
collect: (monitor) => ({
isDragging: monitor.isDragging(),
}),
});
const opacity = isDragging ? 0 : 1;
drag(drop(ref));
return <tr ref={ref} {...restProps} style={{ ...rowStyle, opacity }}></tr>;
};
const components = {
body: {
row: DraggableRow,
},
};
return (
<DndProvider backend={HTML5Backend}>
<Table
className="single-table"
{...tableProps}
components={components}
dataSource={list}
columns={columns}
onRow={(record, index) => ({
record,
index,
handleDrag,
})}
/>
</DndProvider>
);
}
export default DragTable;
import DragTable from './dragTable';
handleTableDrag = (newList, dragItem, is, k, flag) => {
let arr = deepClone(this.state.list) || [];
let d = arr.filter((v) => v.key === k)?.[0]?.data;
if (flag) {
//组内交换顺序,赋新值
d[is].libraryList = newList;
} else {
//跨表格拖拽
d = d.map((v, i) => {
v.libraryList = v.libraryList.filter((vs, is) => {
return vs.id !== dragItem.id;
});
return v;
});
d[is].libraryList = newList;
}
this.setState({ list: arr });
};
<DragTable
is={is}
k={v.key}
dataSource={dataSource}
columns={columns}
onChange={this.handleTableDrag}
/>