demo效果
此demo主要是做一个拖拽排序功能,运用的场景比如轮播图展示的顺序等。
实现的大体思路是这样的:
- 先将可拖拽的区域最外层用 DndProvider组件并添加属性backend={HTML5Backend} 包裹,提供react dnd功能
- 然后定义拖拽 (useDrag) 和放置区 (useDrop) 的属性和方法,通过 drop(drag(ref)) 来给拖拽组件设置成可放置可拖拽组件
- 通过拖拽组件end方法获取当前拖拽组件的item对象的Index值和放置区drop函数返回的结果Index值,回调endFunc函数执行数组排序逻辑处理并更新页面
详细过程看一下代码,此代码结合了react框架 dva 进行编写;
import React, { useRef } from 'react'
import { connect } from 'dva'
import { DndProvider, useDrop, useDrag } from 'react-dnd'
import { HTML5Backend } from 'react-dnd-html5-backend'
function Box({ name, obj, idx, endFunc }) {
const ref = useRef(null);
//先定义一个推拽组件
const [{ isDragging, handlerId }, drag] = useDrag(() => ({
// { isDragging }一个包含从 collect 函数收集的属性的对象。如果没有collect定义函数,则返回一个空对象。
type: "BOX",//作用:只有为相同类型注册的放置目标才会对此项目做出反应
item: { index: idx },//必须要有的,相当于id
end: (item, monitor) => {//end 在被拖拽的组件被放下后执行
// monitor.getDropResult()返回表示最后记录的放置drop result对象(拖拽元素放下时的结果)
const dropResult = monitor.getDropResult();//如果dropResult为null,代表拖拽组件没有放到指定区域,有则返回该区域的
console.log(item, dropResult);
if (item && dropResult) {//如果拖拽组件结束位置在规定区域则alert
endFunc(item, dropResult, obj);
}
},
//收集器:负责监听收集拖拽组件的状态
collect: (monitor) => ({
isDragging: monitor.isDragging(),//是否拖拽状态
}),
}));
const [{ isOver }, drop] = useDrop(() => ({
//accept:只接受类型为BOX的拖拽组件,否则不能感应
accept: "BOX",
drop: () => ({ index: obj.Index }),//放置区组件的结果(数据信息),此数据信息会被拖拽组件end方法的monitor.getDropResult()获取
}));
return (<div ref={drop(drag(ref))} role="Box" style={{ height: 200, width: 400, backgroundColor: obj.color, opacity: 1, fontSize: 40, textAlign: 'center' }} >
{name}
</div>);
};
const Container = (props) => {
return (
props.state.data.map((item, index) => <Box key={index} name={item.name} obj={item} endFunc={props.endFunc} idx={index} />)
)
}
function NewDndController({ dispatch, dnd: state }) {
// 当拖拽对象放置后触发,进行元素排序
function endFunc(before, last) {
let beforeIndex = before.index, lastIndex = last.index;
let data = JSON.parse(JSON.stringify(state.data));
state.data[beforeIndex] = data[lastIndex];
state.data[beforeIndex].Index = beforeIndex;
state.data[lastIndex] = data[beforeIndex];
state.data[lastIndex].Index = lastIndex;
dispatch({ type: 'dnd/save', payload: { ...state } })
}
return (
<div style={{ width: '100vw', height: '100vh', padding: 50 }}>
<DndProvider backend={HTML5Backend}>
<div style={{ display: "flex", flexWrap: "wrap", justifyContent: "space-around", border: "1px solid #BDBBBB", padding: 20, }}>
<Container state={state} endFunc={endFunc} />
</div>
</DndProvider>
</div >
)
}
function mapStateToProps(state) {
return { dnd: state.dnd }
}
export default connect(mapStateToProps)(NewDndController)