项目需求中,要求实现表格拖拽排序后,返回排序后数据顺序提交保存,多处使用。
曾尝试通过对Table组件的 columns 属性进行包裹,以期达到封装 DragSource 和 DropTarget 的效果,但后来发现,antd根部不会识别这样的修改。
antd官方文档提供了Table单一表格的行拖拽排序,并没有暴露出更多可详细配置的API。
在拖拽排序的案例中,BodyRow既是DragSource,也是DopTarget。那么既然如此,理应也允许针对BodyRow进行二次封装,达到DragSource与DropTarget的独立,从而实现跨表格的行(row)或列(column)的拖拽。
查阅ant Design,react相关排序,得出结论,ant Design table组件 + react-dnd结合可实现。
提供组件属性含义:
- 可设置“dataSource”绑定表格数据。
- 可设置“columns”定义表格列名。
- 可通过“setList获取排序后数据。
- 其余表格属性同ant Design相关属性设置全选、滚动、样式等一致。
// 表格拖拽排序组件
// antd-table + react-dnd
import React, {
useRef } from 'react';
import {
DndProvider, DragSource, DropTarget } from 'react-dnd';
import {
HTML5Backend } from 'react-dnd-html5-backend';
import update from 'immutability-helper';
import {
Table } from "antd";
import {
useEffect } from 'react';
let dragingIndex = -1; // 用于设置拖拽Row时样式
let moverow = null; //定义move事件,解决warn
const BodyRow = (props) => {
const {
isOver, connectDragSource, connectDropTarget, move, ...restProps } = props;
moverow = move;
const ref = useRef(null);
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';
}
}
connectDragSource(
connectDropTarget(ref)
);
return <tr {
...restProps} ref={
ref} className={
className} style={
style}></tr>;
};
// DragSource 拖拽事件的方法对象
const rowSource = {
beginDrag(props) {
dragingIndex = props.index;
return {
index: props.index
};
}
};
// DropTarget 拖拽事件的方法对象
const rowTarget = {
drop(props, monitor) {
const dragIndex = monitor.getItem().index;
const hoverIndex = props.index;
if (dragIndex === hoverIndex) {
return;
}
moverow(dragIndex, hoverIndex);
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)
);
/**
* 拖拽表格
* @param {表格数据} dataSource
* @param {表格columns} columns
* @param {设置数据} setList 设置数据方法
*/
function DragTable({
dataSource, columns, setList, ...tableProps }) {
const components = {
body: {
row: DragableBodyRow }
};
const moveRow = (dragIndex, hoverIndex) => {
const dragItem = dataSource[dragIndex];
const newList = update(dataSource, {
$splice: [
[dragIndex, 1],
[hoverIndex, 0, dragItem]
]
});
setList(newList);
};
useEffect(() => {
setList(dataSource);
}, [dataSource]);
return (
<DndProvider backend={
HTML5Backend}>
<Table
{
...tableProps}
components={
components}
dataSource={
dataSource}
columns={
columns}
pagination={
false}
onRow={
(record, index) => {
return {
record: record, index: index, move: moveRow };
}} />
</DndProvider>
);
}
export default DragTable;
使用方法:
import React, {
useState, useEffect } from 'react';
import DragTable from '../component/dragTable/index.jsx'; // 引入拖拽组件
const TableDrag = () => {
const [dataSource, setDataSource] = useState([]);
const columns = [
{
title: '姓名',
dataIndex: 'name'
},
{
title: '姓别',
dataIndex: 'sex'
},
{
title: '年龄',
dataIndex: 'age'
},
{
title: '手机号',
dataIndex: 'phone'
}
];
useEffect(() => {
const data = [
{
id: 1,
name: '张三',
sex: '男',
age: 10,
phone: 12345678974
}, {
id: 2,
name: '李四',
sex: '男',
age: 15,
phone: 56789451234
}, {
id: 3,
name: '王五',
sex: '男',
age: 46,
phone: 12345678974
}, {
id: 4,
name: '赵六',
sex: '男',
age: 60,
phone: 12345678974
}, {
id: 5,
name: '李七',
sex: '男',
age: 25,
phone: 12345678974
}
];
setDataSource(data);
}, []);
return <div className='ui_container_box'>
<h1>表格拖拽排序</h1>
<b>使用ant Design 表格,结合react-dnd实现拖拽排序。</b><br />
<span>1、可设置“<b>dataSource</b>”绑定表格数据。</span><br />
<span>2、可设置“<b>columns</b>”定义表格列名。</span><br />
<span>3、可通过“<b>setList</b>获取排序后数据。</span><br />
<span>4、可设置ant design相关属性设置全选、滚动、样式等。</span><br />
<DragTable dataSource={
dataSource} columns={
columns} rowKey='id' setList={
setDataSource} />
</div>;
}
export default TableDrag;