案例
dnd.tsx
import React, { useState, useRef } from 'react'
import "./dnd.less"
// react-dnd核心
import { DndProvider } from "react-dnd"
import { HTML5Backend } from "react-dnd-html5-backend"
import Item from "./components/item"
const dnd: React.FC = (props: any) => {
const types = {
item: 'item',
}
const [list, setlist] = useState([1, 2, 3, 4])
return (
<div className='main'>
{/* 只有<DndProvider backend={HTML5Backend}></DndProvider>的子孙元素才能使用 react-dnd */}
<DndProvider backend={HTML5Backend}>
<div className="list">
{
list.map((item: any, index: any) => {
return <Item key={item} item={item} index={index} type={types.item} list={list} setList={setlist} />
})
}
</div>
</DndProvider>
</div>
)
}
export default dnd
components/item.tsx
import React, { useState, useRef } from 'react'
import { useDrag, useDrop } from "react-dnd"
interface ItemType {
item: number;
index: number;
type: string;
list: any;
setList: any;
}
const dnd: React.FC<ItemType> = (props) => {
const { item, index, type, list, setList } = props
const style = {
padding: '10px',
marginBottom: '10px',
border: '1px solid red',
cursor: 'move',
}
let ref = useRef()
// useDrop的accept和useDrag的type相同才能相互拖拽
const [, drop] = useDrop({
accept: type,
collect: () => ({}),
hover(item: any, monitor: any) {
// 拖拽的索引
const dragIndex = item.index
// 放置目标的索引
const hoverIndex = index
// 如果拖拽目标和放置目标相同就return
if (dragIndex === hoverIndex) return
const { top, bottom } = ref.current.getBoundingClientRect()
// 放置目标半的高度
const halOfHoverHeigth = (bottom - top) / 2
const { y } = monitor.getClientOffset()
const hoverClientY = y - top
// 当移动到防止目标一半时切换位置
if (
(dragIndex < hoverIndex && hoverClientY > halOfHoverHeigth) ||
(dragIndex > hoverIndex && hoverClientY < halOfHoverHeigth)
) {
const dragItem = list[dragIndex]
list.splice(dragIndex, 1)
list.splice(hoverIndex, 0, dragItem)
setList([...list])
item.index = hoverIndex
}
}
})
const [{ isDragging }, drag] = useDrag({
type,
item: () => ({ item, index }),
collect: (monitor) => ({
isDragging: monitor.isDragging()
})
})
const opacity = isDragging ? 0.4 : 1
drag(drop(ref))
return (
<div className='item' ref={ref} style={{ ...style, opacity }}>
{item}
</div>
)
}
export default dnd