Antd可拖拽排序需要引入的其他的库配合实现,具体demo在antd官网也给了,下面是针对一些特殊的产品需求的实现及需要注意的事项,具体的要实现的功能如下图:
这个表格内容分为两部分,即图中的第一部分和第二部分,并且上下两部分内容可以互相拖动,并且表格中的带箭头的所在行是可以展开和关闭,拖动后不能改变展开行顺序,在antd中的表格通过引入其他库可以实现拖动的功能,但是需要合并展开功能,某行不能拖动,某行独占一行的功能。
columns = [
{
title: '列名1',
key: 'code',
dataIndex: 'rank',
render: (text, record, index) => {
if (record.name) {
return {
children: <a>{record.name}</a>,
props: {
colSpan: 4,
},
};
}
return record.index;
}
}
]
DragSource(type, spec, collect):用于包装你需要拖动的组件,使组件能够被拖拽。
DropTarget(type, spec, collect):用于包装接收拖拽元素的组件,使组件能够放置。
type参数:当source组件的type和target组件的type一致时,target组件可以接受source组件。其值类型可以使string, symbol,也可以是一个函数来返回该组件的其他props。
spec参数:spec是用来定义特定方法的一个对象,如source组件的spec可以定义拖动相关的事件,target组件的spec可以定义放置相关的事件。具体如下:
DragSource speObj:
beginDrag(props, monitor, component) 拖动开始时触发的事件,required。返回与props相关的对象。
endDrag(props, monitor, component) 拖动结束时触发的事件,optional。
canDrag(props, monitor) 当前是否可以拖拽的事件,optional。
isDrag(props, monitor) 拖拽时触发的事件,optional。
// DragSource源组件的 spec 属性
const dragSpec = {
beginDrag(props) {
console.log('%c beginDrag...', 'color: #F8B400', props);
},
endDrag(props, monitor) {
const item = monitor.getItem();
const dropResult = monitor.getDropResult();
console.log(item, dropResult, 'endDrag...');
},
};
DropTarget specObj:
drop(props, monitor, component) 组件被放下时触发的事件,optional。
hover(props, monitor, component) 组件在DropTarget上方时响应的事件,optional。
canDrop(props, monitor) 组件可以被放置时触发的事件,可选。
// DropTarget目标组件
const targetSpec = {
drop(props, monitor) {
// dropTarget 行的值
const { record } = props.children[0].props;
// dragSource 行的值
const dragItem = monitor.getItem();
},
};
其中,specObj这个对象方法中的相关参数为:
props:组件当前的props。
monitor:查询当前的拖拽状态,比如当前拖拽的item和他的type,当前拖拽的offsets,当前是否dropped。
component:当前组件的实例。
collect
collect是一个函数,默认有两个参数:connect 和 monitor。该函数将返回一个对象,这个对象会被注入到props中,也就是说,我们可以在目标组件中通过 this.props 获取到通过collect注入进来的所有属性。
// TODO 封装 DropTarget 组件
const DropBodyRow = DropTarget(Types.CARD, targetSpec, (connect, monitor) => {
return {
// 由 collect 函数返回的对象中的API,可以在组件中利用 this.props 获取
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver(),
canDrop: monitor.canDrop(),
};
})(BodyRow);
// 在组件中通过使用 this.props 获取API
class BodyRow extends PureComponent {
render() {
const { connectDropTarget, isOver, canDrop } = this.props;
return connectDropTarget(
<tr {...restProps} />
);
}
}
在 collect 函数的两个参数中:
connect
source组件 的 collect 中的 connect 是DragSourceConnector 的实例,它内置了两个方法:dragSource() 和 dragPreview() 。dragSource() 返回一个方法,将source组件传入这个方法,可以将 source DOM 和 React DnD backend 连接起来;dragPreview() 返回一个方法,可以将其传入节点,作为拖拽预览时的角色。
target组件 的 collect 中 connect 是 DropTargetConnector 的实例。内置的方法 dropTarget() 对应 DragSource(),返回可以将 drop target 和 React DnD backend 连接起来的方法。
通过看完这些相关的API,我们可以看出我们需要修改的地方是在canDrog方法中定义哪些行是不能拖动的(需求中的第一部分和第二部分内容所在行),在drop方法中我们可以定义拖动到那一行我们不能释放(不能拖放在展开行上),这样就已经完成了大多数的功能,最后一个就是拖动时候如果展开了某行那么拖动后需要改动多行数据,这里主要分为两种情况,如果是从下往上拖动,就直接先删除拖动的这条数据,然后在需要放置的这行数据前面插入即可,如果从上往下拖动需要先计算拖动和放入这两栏的展开项有多少,删除时需加上拖动行和拖动行的展开项,然后再重新放到需要插入的行