dnd文档

html 拖拽排序
import React, { useState, useRef } from 'react';
import { cloneDeep } from 'lodash';
import styles from './index.less';
const defaultList = [
{
id: 1,
name: '11',
},
{
id: 2,
name: '22',
},
];
export default ({ children = '', arr = [] }) => {
const [list, setList] = useState([...defaultList]);
const startRef = useRef(null);
const changePosition = (dragIndex, hoverIndex) => {
const data = cloneDeep(list);
const temp = data[dragIndex];
// 交换位置
data[dragIndex] = data[hoverIndex];
data[hoverIndex] = temp;
setList(data);
};
const onDragStart = index => {
// console.log('onDragStart', index);
startRef.current = index;
};
const onDragEnd = (e, index) => {
e.preventDefault();
};
const onDragOver = (e, index) => {
e.preventDefault();
};
const onDragEnter = (e, hoverIndex) => {
e.preventDefault();
if (startRef.current === hoverIndex) {
return;
}
startRef.current = hoverIndex; // 将当前当前移动到Box的index赋值给当前拖动的box,不然会出现两个盒子疯狂抖动!
changePosition(startRef.current, hoverIndex);
// console.log('onDragEnd', hoverIndex, '排序');
};
return (
<div className={styles.list_container}>
{list.map((item, index) => {
return (
<div
className={styles.list_item}
draggable
key={item?.id}
onDragStart={$event => onDragStart(index)}
onDragEnd={$event => onDragEnd($event, index)}
onDragEnter={$event => onDragEnter($event, index)}
onDragOver={$event => onDragOver($event, index)}
>
{item.name}
{/* {children} */}
</div>
);
})}
</div>
);
};
拖拽组件封装
import React, { useRef } from 'react';
import { useDrop, useDrag } from 'react-dnd';
import styles from './index.less';
// 拖拽排序
export default ({ id = '', index = '', changePosition = () => {}, className = {}, children, rowKey = '' }) => {
const ref = useRef(null);
// 因为没有定义收集函数,所以返回值数组第一项不要
const [, drop] = useDrop({
accept: 'DragDropBox', // 只对useDrag的type的值为DragDropBox时才做出反应
hover: (item, monitor) => {
// 这里用节流可能会导致拖动排序不灵敏
if (!ref.current) return;
const dragIndex = item.index;
const hoverIndex = index;
if (dragIndex === hoverIndex) return; // 如果回到自己的坑,那就什么都不做
changePosition(dragIndex, hoverIndex); // 调用传入的方法完成交换
item.index = hoverIndex; // 将当前当前移动到Box的index赋值给当前拖动的box,不然会出现两个盒子疯狂抖动!
},
});
const [{ isDragging }, drag] = useDrag({
item: {
type: 'DragDropBox',
id,
index,
},
collect: monitor => ({
isDragging: monitor.isDragging(), // css样式需要
}),
});
return (
// ref 这样处理可以使得这个组件既可以被拖动也可以接受拖动
<div ref={drag(drop(ref))} style={{ opacity: isDragging ? 0.5 : 1 }} className={className.dragBox}>
<span key={rowKey} className={styles.reviewer}>
{children}
</span>
</div>
);
};
使用组件
import React from 'react';
import { DndProvider } from 'react-dnd';
import { useSelector } from 'umi';
import { cloneDeep } from 'lodash';
import HTML5Backend from 'react-dnd-html5-backend';
import ReactDndDragSort from '@/components/ReactDndDragSort';
import styles from './index.less';
export default ({ currentModel, dispatch }) => {
const { reviewerList = [] } = useSelector(state => state[currentModel]);
const changePosition = (dragIndex, hoverIndex) => {
const data = cloneDeep(reviewerList);
const temp = data[dragIndex];
// 交换位置
data[dragIndex] = data[hoverIndex];
data[hoverIndex] = temp;
// setBoxList(data);
dispatch({
type: `${currentModel}/overrideStateProps`,
payload: {
reviewerList: data,
},
});
};
return (
<>
<div className={styles.reviewerContainer}>
<DndProvider backend={HTML5Backend}>
{reviewerList?.length ? (
<div style={{ display: 'flex' }}>
{reviewerList.map((item, index) => {
return (
<ReactDndDragSort
rowKey={item?.id}
index={index}
id={item?.id}
changePosition={changePosition}
>
<span key={item?.id} className={styles.reviewer}>
<div className={styles.reviewerImg}>
<span
className="saas saas-failure1"
onClick={() => {
const listFilter = reviewerList.filter(
(_, itemIndex) => itemIndex !== index,
);
dispatch({
type: `${currentModel}/overrideStateProps`,
payload: {
reviewerList: listFilter,
},
});
}}
/>
</div>
<div className={styles.reviewerTxt}>{item.name}</div>
</span>
</ReactDndDragSort>
);
})}
</div>
) : null}
</DndProvider>
</div>
</>
);
};
ts 版本
import React, { useRef } from "react";
import { useDrop, useDrag } from "react-dnd";
import "./index.less";
// dnd拖拽排序
export default (props: any) => {
const {
id = "",
index = "",
changePosition = () => {},
className = "",
children,
rowKey = "",
} = props;
const ref: any = useRef(null);
// 因为没有定义收集函数,所以返回值数组第一项不要
const [, drop] = useDrop({
accept: "DragDropBox", // 只对useDrag的type的值为DragDropBox时才做出反应
hover: (item: any, monitor: any) => {
// 这里用节流可能会导致拖动排序不灵敏
if (!ref.current) return;
const dragIndex = item.index;
const hoverIndex = index;
if (dragIndex === hoverIndex) return; // 如果回到自己的坑,那就什么都不做
changePosition(dragIndex, hoverIndex); // 调用传入的方法完成交换
item.index = hoverIndex; // 将当前当前移动到Box的index赋值给当前拖动的box,不然会出现两个盒子疯狂抖动!
},
});
const [{ isDragging }, drag] = useDrag(() => ({
type: "DragDropBox",
item: { id, type: "DragDropBox", index },
collect: (monitor) => ({
isDragging: monitor.isDragging(), // css样式需要
}),
}));
const changeRef = drag(drop(ref));
return (
// ref 这样处理可以使得这个组件既可以被拖动也可以接受拖动
<div
//@ts-ignore
ref={changeRef}
style={{ opacity: isDragging ? 0.5 : 1 }}
className="dragBox"
>
<span key={rowKey} className={className}>
{children}
</span>
</div>
);
};
ts使用
import React, { useState } from "react";
import { DndProvider } from "react-dnd";
import { useSelector } from "react-redux";
//@ts-ignore
import { cloneDeep } from "lodash";
import { HTML5Backend } from "react-dnd-html5-backend";
import ReactDndDragSort from "@/components/ReactDndDragSort";
import "./index.less";
console.log("HTML5Backend", HTML5Backend);
export default () => {
const dList = [
{
id: 99,
name: "组1",
},
{
id: 22,
name: "组2",
},
];
const [reviewerList, setReviewerList] = useState(dList);
const changePosition = (dragIndex: any, hoverIndex: any) => {
const data = cloneDeep(reviewerList);
const temp = data[dragIndex];
// 交换位置
data[dragIndex] = data[hoverIndex];
data[hoverIndex] = temp;
console.log("交换完成---", data);
setReviewerList(data);
};
return (
<>
<div className="reviewerContainer">
<DndProvider backend={HTML5Backend}>
{reviewerList?.length ? (
<div>
{reviewerList.map((item: any, index: any) => {
return (
<ReactDndDragSort
rowKey={item?.id}
index={index}
id={item?.id}
changePosition={changePosition}
>
<div key={item?.id} className="reviewer">
<div className="reviewerTxt">{item.name}</div>
</div>
</ReactDndDragSort>
);
})}
</div>
) : null}
</DndProvider>
</div>
</>
);
};