import React, { memo, useState, useEffect, useCallback } from 'react';
import { EditOutlined, MinusCircleOutlined, MenuOutlined } from '@ant-design/icons';
import { Button } from 'antd';
import {
DragSource,
DropTarget,
DndProvider,
ConnectDropTarget,
DragSourceSpec,
DropTargetConnector,
DragSourceMonitor,
DragSourceConnector,
DropTargetSpec,
ConnectDragSource,
ConnectDragPreview,
} from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import EditorModal from './editorModal';
import { uuid } from '@/utils/tool';
import styles from './index.less';
import { TDataListDefaultType, TDataListDefaultTypeItem } from '../types';
type ListItemProps = DndItemProps & {
isDragging: boolean;
connectDragSource: ConnectDragSource;
connectDragPreview: ConnectDragPreview;
connectDropTarget: ConnectDropTarget;
};
function ListItem(props: ListItemProps) {
const {
title,
desc,
onDel,
onEdit,
// 这些 props 由 React DnD注入,参考`collect`函数定义
isDragging,
connectDragSource,
connectDragPreview,
connectDropTarget,
} = props;
const opacity = isDragging ? 0.5 : 1;
return connectDropTarget(
// 列表项本身作为 Drop 对象
connectDragPreview(
// 整个列表项作为跟随拖动的影像
{title}
{desc}
onEdit()}>
onDel()}>
{connectDragSource(
,
) // 拖动图标作为 Drag 对象
}
,
),
);
}
type DndItemProps = TDataListDefaultTypeItem & {
onDel: Function;
onEdit: Function;
key: number;
find: Function;
move: Function;
type?: number;
};
const type = 'item';
type DragObject = {
id: string;
originalIndex: number;
};
const dragSpec: DragSourceSpec = {
// 拖动开始时,返回描述 source 数据。后续通过 monitor.getItem() 获得
beginDrag: props => ({
id: props.id,
originalIndex: props.find(props.id).index,
}),
// 拖动停止时,处理 source 数据
endDrag(props, monitor) {
const { id: droppedId, originalIndex } = monitor.getItem();
const didDrop = monitor.didDrop();
// source 是否已经放置在 target
if (!didDrop) {
return props.move(droppedId, originalIndex);
}
},
};
const dragCollect = (connect: DragSourceConnector, monitor: DragSourceMonitor) => ({
connectDragSource: connect.dragSource(), // 用于包装需要拖动的组件
connectDragPreview: connect.dragPreview(), // 用于包装需要拖动跟随预览的组件
isDragging: monitor.isDragging(), // 用于判断是否处于拖动状态
});
const dropSpec: DropTargetSpec = {
canDrop: () => false, // item 不处理 drop
hover(props, monitor) {
const { id: draggedId } = monitor.getItem();
const { id: overId } = props;
// 如果 source item 与 target item 不同,则交换位置并重新排序
if (draggedId !== overId) {
const { index: overIndex } = props.find(overId);
props.move(draggedId, overIndex);
}
},
};
const dropCollect = (connect: DropTargetConnector) => ({
connectDropTarget: connect.dropTarget(), // 用于包装需接收拖拽的组件
});
const DndItem = DropTarget(
type,
dropSpec,
dropCollect,
)(DragSource(type, dragSpec, dragCollect)(ListItem));
export type DataListMemo = {
onChange?: (v: TDataListDefaultType) => void;
value?: TDataListDefaultType;
cropRate: number;
};
export type DataListType = DataListMemo & {
connectDropTarget: ConnectDropTarget;
};
const List = function(props: DataListType) {
const { onChange, value, connectDropTarget, cropRate } = props;
const [list, setList] = useState(value);
const [visible, setVisible] = useState(false);
const [curItem, setCurItem] = useState();
const handleDel = (id: string) => {
if (value && onChange) {
let newVal = value.filter(item => id !== item.id);
onChange(newVal);
}
};
const find = (id: string) => {
const item = list!.find(c => `${c.id}` === id)!;
return {
item,
index: list!.indexOf(item!),
};
};
const move = (id: string, toIndex: number) => {
const { item, index } = find(id);
const oldList = [...list!];
oldList.splice(index, 1);
oldList.splice(toIndex, 0, item);
if (onChange) {
onChange(oldList);
return;
}
setList(oldList);
};
const handleCancel = useCallback(() => {
console.log('a');
setVisible(false);
}, []);
const handleEdit = useCallback((item: TDataListDefaultTypeItem) => {
console.log('b');
setVisible(true);
setCurItem(item);
}, []);
const handleSave = useCallback(
(item: TDataListDefaultTypeItem) => {
console.log('c');
setVisible(false);
if (onChange) {
onChange(list!.map(p => (p.id === item.id ? item : p)));
return;
}
setList(prev => prev!.map(p => (p.id === item.id ? item : p)));
},
[list, onChange],
);
const handleAdd = () => {
const item = {
title: '新增项标题',
desc: '新增项描述',
id: uuid(8, 10),
imgUrl: [],
link: '',
};
if (onChange) {
onChange([...list!, item]);
return;
}
setList([...list!, item]);
};
useEffect(() => {
setList(value);
}, [value]);
return connectDropTarget(
{!!(list && list.length) &&
list.map((item, i) => (
handleDel(item.id)}
onEdit={() => handleEdit(item)}
key={i}
id={`${item.id}`}
find={find}
move={move}
/>
))}
,
);
};
const DndList = DropTarget(type, {}, connect => ({
connectDropTarget: connect.dropTarget(),
}))(List);
// 将 HTMLBackend 作为参数传给 DragDropContext
export default memo((props: DataListMemo) => {
return (
);
});