React/AntDesign 如何使行可拖动? (表格拖动排序)
Posted
技术标签:
【中文标题】React/AntDesign 如何使行可拖动? (表格拖动排序)【英文标题】:React/AntDesign How to make rows draggable? (Table Drag Sorting) 【发布时间】:2019-12-20 06:22:35 【问题描述】:我一直在编写这个简单的单列拖放表,但是当我拖动它们时行并没有移动。我在哪里修复或检查?
我正在使用 React、AntDesign 和 javascript(使用 TypeScript)
import * as React from 'react';
import ReactDOM from "react-dom";
import Table from "antd";
import DndProvider, DragSource, DropTarget from "react-dnd";
import html5Backend from "react-dnd-html5-backend";
import update from "immutability-helper";
let dragingIndex = -1;
interface propsDD
isOver: any,
connectDragSource: any,
connectDropTarget: any,
moveRow: any,
restProps:
readonly [x: string]: any;
children?: React.ReactNode;
className: any,
index: any,
class BodyRow extends React.Component<propsDD>
render()
const isOver, connectDragSource, connectDropTarget, moveRow, ...restProps = this.props;
const style = ...restProps, 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: any)
dragingIndex = props.index;
return
index: props.index,
;
,
;
const rowTarget =
drop(props: any, monitor: any)
const dragIndex = monitor.getItem().index;
const hoverIndex = props.index;
if (dragIndex === hoverIndex)
return;
props.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)
);
const columns = [
title: 'Orden de Ejecución',
dataIndex: 'attributes.name',
key: 'name',
,
];
type propsFromList =
receivedTasks: Task[],
onReceivedTasks: (tasks: Task[]) => void,
export default class DDTasks extends React.Component<propsFromList, State>
public state: State =
data: [],
;
components =
body:
row: DragableBodyRow,
,
;
onReceivedTasks(tasks: Task[]): void
this.setState(
data: this.props.receivedTasks,
as State)
moveRow = (dragIndex: any, hoverIndex: any) =>
const data = this.state;
const dragRow = data[dragIndex];
this.setState(
update(this.state,
data:
$splice: [[dragIndex, 1], [hoverIndex, 0, dragRow]]
)
);
;
render()
return (
< DndProvider backend=HTML5Backend >
<Table
rowKey="id"
bordered=true
pagination=false
columns=columns
dataSource=this.props.receivedTasks
components=this.components
onRow=(index) => (
index,
moveRow: this.moveRow,
)
/>
</DndProvider >
);
我希望拖动行。实际显示的是行的内容。
【问题讨论】:
我已经添加了拖拽效果的 CSS 样式(drop-over-downward & drop-over-upward)。 这里是实际行为的 gif makeagif.com/i/TIw7Qx 【参考方案1】:这是一个简单的例子,我根据我在网上找到的许多不同的东西提出了一个简单的例子,并最终制定了一些适用于我的代码的东西:
基本上这是被调用的反应组件表的主体,我正在通过索引映射一个位置列表,并且每一行都是可拖动的,以允许用户修改表。我还包括了与属性关联的函数调用
return (
<Tbody>
items.map((item, index) => (
<Tr key=index className="item.name"
draggable=true
onDragStart=this.dragstart
onDragEnd=this.dragend
onDragLeave=this.dragend
onDragEnter=this.dragend
onDrop=this.drop
onDragOver=this.dragend
id=index >
<Td><span>item.name</span></Td>
<Td><span>item.latitude</span></Td>
<Td><span>item.longitude</span></Td>
<Td type="data"><span>this.checkForZero(this.props.propDistances[index])</span></Td>
<Td type="data"><span>this.checkForZero(this.props.propCumulativeDist[index])</span></Td>
</Tr>
))
this.finishItineraryTable()
</Tbody>
);
dragstart(event)
let dataTransfer = event.dataTransfer;
let node = event.target;
dataTransfer.setData('text/plain',node.innerHTML);
dataTransfer.setData('id',node.id);
event.stopPropagation();
dragend(event)
event.preventDefault();
drop(event)
event.preventDefault();
let dragObjHtml = event.dataTransfer.getData("text/plain");
let dragObjId = document.getElementById(event.dataTransfer.getData("id"));
let dropTarget = event.target.closest("tr");
let temp = dropTarget.innerHTML;
dropTarget.innerHTML = dragObjHtml;
dragObjId.innerHTML = temp;
【讨论】:
【参考方案2】:在粘贴我的长长的代码之前,我想提几点:
它很大程度上基于original drag sorting example。 幸运的是,React DnD 具有完美的 TypeScript 支持,因为它是用 TypeScript 编写的。 下面的代码是 Ant 设计<table>
的替代代码。
这是通用的。
它使用功能组件和钩子。
有一个onDragSort
,每次发生某些拖动排序时都会回调它。该参数包括排序后的数据。
首先安装包react-dnd
和react-dnd-html5-backend
。将此添加到您的DragSortingTable.tsx
:
import * as React from 'react';
import Table, TableProps, TableComponents from 'antd/lib/table';
import DndProvider, DropTarget, DragSource, DragElementWrapper, DropTargetSpec from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
let dragingIndex = -1;
interface BodyRowProps
isOver: boolean;
connectDragSource: DragElementWrapper<>;
connectDropTarget: DragElementWrapper<>;
style?: React.CSSProperties;
index: number;
className?: string;
const BodyRow: React.FC<BodyRowProps> = props =>
const style = ...props.style, cursor: 'move' ;
let className = props;
if (props.isOver)
if (props.index > dragingIndex)
className += ' drop-over-downward';
if (props.index < dragingIndex)
className += ' drop-over-upward';
return props.connectDragSource(
props.connectDropTarget(
<tr className=className style=style>
props.children
</tr>
)
);
;
const rowSource =
beginDrag(props)
dragingIndex = props.index;
return
index: props.index
;
;
interface DropProps
index: number;
moveRow: (dragIndex: number, hoverIndex: number) => void;
const rowTarget: DropTargetSpec<DropProps> =
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<DropProps>('row', rowTarget, (connect, monitor) => (
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver()
))(
DragSource('row', rowSource, connect => (
connectDragSource: connect.dragSource()
))(BodyRow)
);
interface DragSortingTableProps<T> extends TableProps<T>
onDragSort?: (sortedData: T[]) => void;
type extractTableType<T> = T extends DragSortingTableProps<infer T> ? T : never;
export const DragSortingTable: <T>(
props: DragSortingTableProps<T>
) => React.ReactElement<DragSortingTableProps<T>> = props =>
const [dataSource, setDataSource] = React.useState(props.dataSource);
React.useEffect(() =>
setDataSource(props.dataSource);
, [props.dataSource]);
const components: TableComponents =
body:
row: DragableBodyRow
;
const moveRow: DropProps['moveRow'] = (dragIndex, hoverIndex) =>
const dragRow = dataSource[dragIndex];
const remaining = dataSource.filter(i => i !== dragRow);
const sorted = [...remaining.slice(0, hoverIndex), dragRow, ...remaining.slice(hoverIndex)];
setDataSource(sorted);
if (props.onDragSort)
props.onDragSort(sorted);
;
const tableProps: TableProps<extractTableType<typeof props>> =
...props,
className: props.className ? props.className + ' drag-sorting-table' : 'drag-sorting-table',
components,
dataSource,
onRow: (_record, index) => ( index, moveRow )
;
return (
<DndProvider backend=HTML5Backend>
<Table ...tableProps>props.children</Table>
</DndProvider>
);
;
将以下样式添加到您的 antd.less
覆盖:
.drag-sorting-table tr.drop-over-downward td
border-bottom: 2px dashed @primary-color;
.drag-sorting-table tr.drop-over-upward td
border-top: 2px dashed @primary-color;
按如下方式使用您的新拖动排序表:
<DragSortingTable<Users>
dataSource=props.users
rowKey='id'
>
<Column
title='Title'
dataIndex='id'
key='id'
/>
</DragSortingTable>
【讨论】:
【参考方案3】:你添加了antd sortable table的CSS来展示拖拽效果吗?
#components-table-demo-drag-sorting tr.drop-over-downward td
border-bottom: 2px dashed #1890ff;
#components-table-demo-drag-sorting tr.drop-over-upward td
border-top: 2px dashed #1890ff;
这里是sandbox link
【讨论】:
是的,正如你所说,我已经添加了 CSS 样式。在之前的测试中,显示了拖拽效果,但是在这个版本中没有。 你用的是哪个版本的antd,能不能更新一下你的antd版本再查看 我不太确定我使用的是哪个 AntD 版本,但是,这是我试图复制的原始源代码:ant.design/components/table/#components-table-demo-drag-sorting【参考方案4】:我也在寻找类似的功能 并在 antd 表的帮助下开发了我自己的支持多行拖放的组件。
拖放表格行以重新排序表格数据。
用户可以通过“cntrl + click”选择多行
https://github.com/sojinantony01/react-multi-row-dragable-table-antd
【讨论】:
以上是关于React/AntDesign 如何使行可拖动? (表格拖动排序)的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Visual Studio 中从数据库中获取数据(使用 C#)时使 HTML 行可点击
JQuery UI Sortable + Laravel Collection Chunk:行可拖动而不是单个元素