这个是typescript类型下的自定义拖拽组件,相关api请查看官方文档
引入HTML5Backend
的时候需要注意一下,目前官方文档是直接import HTML5Backend from 'react-dnd-html5-backend';
这么导入的,但是在react-dnd-html5-backend
的版本高于11之后,这么引入会报错Catched error TypeError: backendFactory is not a function
, 然后去github上查看的时候,说是11版本之后,需要import { HTML5Backend } from 'react-dnd-html5-backend';
这样引入才正确。
import React, { useRef } from 'react';
import { useDrop, useDrag } from 'react-dnd';
// 拖拽排序
type DragTagProps = {
id: string;
index: string | number;
onDragEnd: (dragIndex: string | number, hoverIndex: string | number, type: string) => void;
rowKey?: string;
children?: React.ReactNode;
type: string;
}
export const DragTag: React.FC<DragTagProps> = ({
id = '',
index = '',
onDragEnd,
children,
rowKey = '',
type
}) => {
const ref = useRef(null);
// 因为没有定义收集函数,所以返回值数组第一项不要
const [, drop] = useDrop({
accept: 'DragDropBox', // 只对useDrag的type的值为DragDropBox时才做出反应
hover: (item: any) => {
// 这里用节流可能会导致拖动排序不灵敏
if (!ref.current) return;
const dragIndex = item.index;
const hoverIndex = index;
if (dragIndex === hoverIndex) return; // 如果回到自己的坑,那就什么都不做
onDragEnd(dragIndex, hoverIndex, type); // 调用传入的方法完成交换
item.index = hoverIndex; // 将当前当前移动到Box的index赋值给当前拖动的box,不然会出现两个盒子疯狂抖动!
},
collect: monitor => ({
isOver: monitor.isOver({ shallow: true }),
canDrop: monitor.canDrop(),
}),
});
const [{ isDragging }, drag] = useDrag({
type: 'DragDropBox',
item: {
type: 'DragDropBox',
id,
index,
},
collect: (monitor: any) => ({
isDragging: monitor.isDragging(), // css样式需要
}),
});
drop(drag(ref))
return (
// ref 这样处理可以使得这个组件既可以被拖动也可以接受拖动
<span ref={ref} style={{ opacity: isDragging ? 0.5 : 1 }}>
<span key={rowKey}>
{children}
</span>
</span>
);
};
export default DragTag;
然后在外层调用
import React, { useEffect, useState } from 'react';
import { Tag } from 'antd';
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import DragTag from './DragTag';
const dataSource = [
{ key: 23, value: 'ceshi1' },
{ key: 24, value: 'ceshi1' },
{ key: 25, value: 'ceshi1' },
{ key: 26, value: 'ceshi1' },
]
const CustomFormModal: React.FC = () => {
const [tagData, setTagData] = useState<any[]>([]);
const delTag = (key: CheckboxValueType, type: string) => {
console.log(key, type)
};
const onDragEnd = (dragIndex: any, hoverIndex: any, type?: string) => {
const data = cloneDeep(dataSource);
// 两种排序方法
// 直接交换位置
// const temp = data[dragIndex];
// data[dragIndex] = data[hoverIndex];
// data[hoverIndex] = temp;
// 依次往后挪
const [draggedItem] = data.splice(dragIndex, 1);
data.splice(hoverIndex, 0, draggedItem);
setTagData(data)
};
const renderTag = (data: any[], type: string) => {
return data.map((item, index) => {
return (
<DragTag
rowKey={item.key}
index={index}
id={item.key}
type={type}
key={item.key}
onDragEnd={onDragEnd}
>
<Tag
key={item.key}
>
{item.value}
</Tag>
</DragTag>
);
});
};
return (
<DndProvider backend={HTML5Backend}>
{renderTag(tagData, '')}
</DndProvider>
);
};
export default CustomFormModal;