- Published on
实现个简单的React拖拽组件
- Authors
- Name
- Et cetera
darggable
API
HTML5<div draggable="true"></div>
一些对应处理拖拽事件的函数:
ondrag
拖放进行中ondragend
/ondragstart
开始拖放和结束拖放ondragover
当元素或选中的文本被拖到一个目标目标上(每 100 毫秒触发一次)ondragenter
/ondragleave
源对象开始进入/离开目标对象范围内ondrop
源对象被拖放到目标对象上
数据的传输,使用 event.dataTransfer,又有如下 api:
setData
添加拖拽数据,这个方法接收两个参数,第一个参数是数据类型(可自定义),第二个参数是对应的数据getData
反向操作,获取数据,只接收一个参数,即数据类型clearData
清除数据setDragImage
可自定义拖放过程中鼠标旁边的图像effectAllowed
属性指定拖放操作所允许的一个效果.copy 操作用于指示被拖动的数据将从当前位置复制到放置位置 _move 操作用于指定被拖动的数据将被移动。link_操作用于指示将在源和放置位置之间创建某种形式的关系或连接
React 实现下基本的几个组件
Drag 组件
Drag.tsx
import types { FC, ReactNode } from "react";
interface DragProps {
index: number;
id: string | number;
children?: ReactNode
}
const Drag: FC<DragProps> = ({id, index, children}) => {
const startDrag = (ev) => {
// 传输数据
ev.dataTransfer.setData("index", index);
ev.dataTransfer.setData("id", id);
};
return (
<div draggable onDragStart={startDrag}>
{children}
</div>
);
};
export default Drag;
Drop 组件
Drop.tsx
import { FC, useContext } from "react";
import { Context } from "./DndContext";
interface DrapProps {
index: number;
id: string | number;
children?: ReactNode
}
const Drop: FC<DrapProps> = ({ children }) => {
const { onDragOver, onDragEnd } = useContext(Context);
const dragOver = (ev) => {
ev.preventDefault();
if (onDragOver) onDragOver();
};
const drop = (ev) => {
// 获取数据
const oldIndex = ev.dataTransfer.getData("index");
// 获取拖拽结束时的Y轴坐标
const Y = ev.clientY;
// 简便计算,设定高度为20
// 我这里很偷懒,实际计算情况很复杂
//一般有两种实现思路,一种就是根据位置计算,另外一种就是给拖拽源设置可放置,然后获取
const height = 20;
const newIndex = Math.floor(Y / height);
if (oldIndex) {
if (onDragEnd) onDragEnd(Number(oldIndex), newIndex);
}
};
return (
<div onDragOver={dragOver} onDrop={drop}>
{children}
</div>
);
};
export default Drop;
DndContext.tsx
import { createContext, FC } from "react";
export interface TContext {
onDragOver: () => void;
onDragEnd: (oldIndex: number, newIndex: number) => void;
}
const Context = createContext<TContext>({} as TContext);
const DndContext: FC<TContext> = (props) => {
return (
<Context.Provider
value={{
onDragEnd: (oldIndex, newIndex) => {
props.onDragEnd(oldIndex, newIndex);
},
onDragOver: () => {
props.onDragOver();
}
}}
>
{props.children}
</Context.Provider>
);
};
export { Context };
export default DndContext;
使用展示
<DndContext
onDragEnd={(oldIndex, newIndex) => {
setData(arrayMove(data, oldIndex, newIndex))
}}
onDragOver={() => {}}
>
<Drop>
{data.map((i, index) => (
<Drag key={i.id} id={i.id} index={index}>
<div className="item">{i.text}</div>
</Drag>
))}
</Drop>
</DndContext>