由于项目中需要使用拖曳组件(需求:全局,跨组件,跨数据),我选择了react-dnd
React DnD 是一组 React 高阶组件,我们在使用的时候只需要将目标元素进行包裹,就可以实现目标元素具有拖动或接受拖动的功能。它将整个拖动的事件完整的描述了出来,这使得我们在使用的过程变得简单易用和扩展上有了无限的可能,在处理复杂拖曳和丰富需求的时候强烈建议使用它。
官网 https://react-dnd.github.io/react-dnd/
导入npm install react-dnd react-dnd-html5-backend
初始化
import { HTML5Backend } from 'react-dnd-html5-backend'; <DndProvider backend={HTML5Backend}> .... </>
组件参数type.ts
export type DragProps = { name: string; //名称标记 type: string; //暂用于标记拖拽类型,接收者和发送者一致 role: string; // data: any; //绑定的数据用于拖曳后操作数据 content: JSX.Element; //绑定的元素 onDragFinished: Function; //拖动结束回调. }; export type AcceptorProps = { name: string; //名称标记 type: string; //暂用于标记拖拽类型,接收者和发送者一致 role: string; // data: any; //绑定的数据用于拖曳后操作数据 content: JSX.Element; //绑定的元素 styleType: 'background' | 'border'; // customStyle:{ // canDrop:string, // isActive:string // } onHover: Function; //移入区域. };
组件MyDrag.ts
import { useDrag, useDrop } from 'react-dnd'; import { DragProps, AcceptorProps } from './type'; export const Dragger = function Dragger(option: DragProps) { const { name, data, type, onDragFinished } = option; const [{ isDragging }, drag] = useDrag(() => ({ type: type, item: { name: name, data: data }, end: (item, monitor, ...arg) => { console.log(arg); const dropResult = monitor.getDropResult(); if (item && dropResult) { console.log('source:', item); console.log('target:', dropResult); } if (onDragFinished) { onDragFinished(item, dropResult); } }, collect: (monitor) => ({ isDragging: monitor.isDragging(), handlerId: monitor.getHandlerId(), }), })); const opacity = isDragging ? 0.4 : 1; return ( <div ref={drag} role={option.role} style={{ opacity }} data-id={`${option.name}`} > {option.content} </div> ); }; export const Acceptor = (option: AcceptorProps) => { const { name, data, type, styleType, onHover } = option; const [{ canDrop, isOver }, drop] = useDrop(() => ({ accept: type, drop: () => option, hover: () => { if (onHover) { onHover(); } }, collect: (monitor) => ({ isOver: monitor.isOver(), canDrop: monitor.canDrop(), }), })); const isActive = canDrop && isOver; let backgroundColor = '#222'; let borderBottom = '0px solid rgba(31, 92, 206, 0)'; if (isActive) { backgroundColor = 'rgba(64, 224, 208, 0.3)'; borderBottom = '1px solid #26BD11'; } else if (canDrop) { backgroundColor = 'rgba(100, 149, 277, 0.3)'; borderBottom = '1px solid #2063AF'; } return ( <div ref={drop} role={'Acceptor'} style={ styleType === 'background' ? { backgroundColor } : { borderBottom } } > {option.content} </div> ); }; //同一list之间拖动 export const dragList = ( list: Array<any>, crtIndex: number, willIndex: number, ) => { let targetItem = list[crtIndex]; let delIndex = crtIndex < willIndex ? crtIndex : crtIndex + 1; list.splice(willIndex, 0, targetItem); list.splice(delIndex, 1); return list; }; //来自不同list之间拖动,1.删除原来 2不删除原来 export const dragToList = ( list: Array<any>, targetList: Array<any>, crtIndex: number, willIndex: number, del: 1 | 2, ) => { let targetItem = list[crtIndex]; targetList.splice(willIndex, 0, targetItem); if (del === 1) { list.splice(crtIndex, 1); } return { list, targetList }; };
具体使用
import { Dragger, Acceptor, dragList } from '@/components/Drag'; //同列表之间拖曳 handleDrag(crt: number, target: number) { conslog.log(dragList(newPanels, crt, target);) } renderDrag(item: ItemProps, children) { <Acceptor key={item.type} name={item.title} data={item} type="xxx" role="xxxAccept" onHover={() => {}} content={ <Dragger name={item.title} data={item} type="xxx" role="xxxDrag" content={children} onDragFinished={(source: any, target: any) => { console.log(source, target, '回调'); if (target) { this.handleDrag( source.data.sort, target.data.sort, ); } }} /> } styleType="border" /> }