依赖版本
"react-dnd": "^11.1.3",
"react-dnd-html5-backend": "^11.1.3",
// 提供 TypeScript 类型定义
"@types/react-dnd": "^3.0.2",
"@types/react-dnd-html5-backend": "^3.0.2",
可拖拽行 — <DraggableRow/>
import React from 'react';
import { useDrag, useDrop } from 'react-dnd';
const type = 'DraggableRow';
const DraggableRow = ({ index, moveRow, className, style, selectedIndices = [], moveRows, ...restProps }) => {
const ref = React.useRef();
const [{ isOver, dropClassName }, drop] = useDrop({
accept: type,
collect: (monitor) => {
const { index: dragIndex } = monitor.getItem() || {};
if (dragIndex === index) {
return {};
}
return {
isOver: monitor.isOver(),
dropClassName: dragIndex < index ? ' drop-over-downward' : ' drop-over-upward',
};
},
drop: (item) => {
// item: { index, type, selectedIndices }
if (selectedIndices.includes(item.index) && typeof moveRows === 'function') {
const dragIndices = [];
let addFlag = true, deleteFlag = true, position = 1
while (addFlag || deleteFlag) {
if (addFlag && selectedIndices.includes(item.index + position)) {
dragIndices.push(item.index + position);
} else {
addFlag = false;
}
if (deleteFlag && selectedIndices.includes(item.index - position)) {
dragIndices.unshift(item.index - position);
} else {
deleteFlag = false
}
position++;
}
moveRows(selectedIndices, index);
} else {
moveRow(item.index, index);
}
},
});
const [, drag] = useDrag({
type: type,
item: { index, type },
collect: (monitor) => ({
isDragging: monitor.isDragging(),
}),
});
drop(drag(ref));
return (
<tr
ref={ref}
className={`${className}${isOver ? dropClassName : ''}`}
style={{ cursor: 'move', ...style }}
{...restProps}
/>
);
};
export default DraggableRow;
拖拽单行
const moveRows = (dragIndices, hoverIndex) => {
const newData = [...data];
newData.splice(dragIndices[0], dragIndices.length);
newData.splice(hoverIndex, 0, ...dragIndices.map(index => data[index]));
setData(newData);
};
拖拽多行
使用多选框,拖拽时将连续被选择的部分统一拖拽
const moveRows = (dragIndices, hoverIndex) => {
const newData = [...data];
const hoverKey = newData[hoverIndex].key;
newData.splice(dragIndices[0], dragIndices.length);
const _hoverIndex = newData.findIndex((item) => item.key === hoverKey);
newData.splice(_hoverIndex, 0, ...dragIndices.map(index => data[index]));
setData(newData);
};
应用在 Table 中 — <DraggableTable/>
import React, { useState } from 'react';
import { Table } from 'antd';
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import DraggableRow from './DraggableRow';
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
},
{
title: 'Age',
dataIndex: 'age',
key: 'age',
},
{
title: 'Address',
dataIndex: 'address',
key: 'address',
},
];
const DraggableTable = () => {
const [data, setData] = useState([
{
key: '1',
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
},
{
key: '2',
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
},
{
key: '3',
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
},
{
key: '4',
name: 'Jim Red',
age: 18,
address: 'London No. 2 Lake Park',
},
{
key: '5',
name: 'Jake White',
age: 18,
address: 'Dublin No. 2 Lake Park',
},
]);
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
const components = {
body: {
row: DraggableRow,
},
};
const moveRow = (dragIndex, hoverIndex) => {
const dragRow = data[dragIndex];
const newData = [...data];
newData.splice(dragIndex, 1);
newData.splice(hoverIndex, 0, dragRow);
setData(newData);
};
const moveRows = (dragIndices, hoverIndex) => {
const newData = [...data];
newData.splice(dragIndices[0], dragIndices.length);
newData.splice(hoverIndex, 0, ...dragIndices.map(index => data[index]));
setData(newData);
};
const rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
setSelectedRowKeys(selectedRowKeys);
},
getCheckboxProps: record => ({
disabled: record.name === 'Disabled User', // Column configuration not to be checked
name: record.name,
}),
selectedRowKeys
};
return (
<DndProvider backend={HTML5Backend}>
<Table
columns={columns}
dataSource={data}
components={components}
rowSelection={Object.assign({ type: "checkbox" }, rowSelection)}
onRow={(record, index) => ({
index,
moveRow,
moveRows,
selectedIndices: selectedRowKeys.map((key) => data.findIndex((item) => item.key === key)),
})}
rowKey="key"
/>
</DndProvider>
);
};
export default DraggableTable;