J'ai codé ce simple tableau glisser-déposer sur une colonne, mais les lignes ne bougent pas lorsque je les fais glisser. Où puis-je corriger ou vérifier cela?
J'utilise React, AntDesign et JavaScript (avec 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 >
);
}
}
Je m'attends à faire glisser des lignes. Le contenu des lignes est effectivement affiché.
Avant de coller mon long blob de code, je veux mentionner quelques choses:
<table>
.onDragSort
, qui est rappelé à chaque fois qu'un tri par glissement se produit. Le paramètre inclut les données triées.Installez d'abord les packages react-dnd
et react-dnd-html5-backend
. Ajoutez ceci à votre 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>
);
};
Ajoutez les styles suivants à votre antd.less
écrase:
.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;
}
Utilisez votre nouvelle table de tri par glisser-déposer comme suit:
<DragSortingTable<Users>
dataSource={props.users}
rowKey='id'
>
<Column
title='Title'
dataIndex='id'
key='id'
/>
</DragSortingTable>