这是一个模态框里带有拖拽排序的组件(获取链接:github),排序完成之后可以更新父组件里的排序数据,组件的图形界面如下:
主要用到的前端库有:Ant Design、React DnD.
此组件的结构图如下:
上图中,AntDesign的组件:SettingOutlined、Modal
ReactDnD的组件:DnDProvider,
自己设计的组件:DragSortingTable、DragableBodyRow
此组件的实现思路如下:
- 父组件DragSortingTableModalBtn下有最外层的2个组件:
- SettingOutlined设置icon按钮
- Modal模态对话框
父组件里控制排序数据变量data以及拖拽DragableBodyRow触发的事件moveRow,调用此父组件的上层组件则控制模态对话框的显示与隐藏。
class DragSortingTableModalBtn extends React.Component {
constructor(props) {
super(props);
this.state = {
data: props.dataList||[] //排序数据变量
};
}
moveRow(dragIndex, hoverIndex) { //拖拽事件
let { data } = this.state;
const dragRow = data[dragIndex];
let newData = update(data, {
$splice: [
[dragIndex, 1],
[hoverIndex, 0, dragRow],
],
});
this.setState({
data: newData
});
}
render() {}
}
- DragSortingTable会在DndProvider组件下加载出拖拽元素组件DragableBodyRow,而一系列的拖拽事件处理是在DragableBodyRow内进行处理。
const DragSortingTable = ({ data, moveRow }) => {
const renderRow = (item, index) => {
return (
<DragableBodyRow
key={item.key}
index={index}
id={item.key}
text={item.text}
moveRow={moveRow}
/>
)
};
return (
<div className="DragSortingTable">
<DndProvider backend={HTML5Backend}>
{ data.map((item, i) => renderRow(item, i)) }
</DndProvider>
</div>
);
}
- DragableBodyRow内部处理拖拽行为事件,而拖拽的关键处理是由
React-DnD
的useDrag, useDrop
进行处理的,简单介绍下useDrag
以及useDrop
的语法(官网链接):
useDrag:
参数:
-
spec
一个特殊对象Object
或创建特殊对象Object
的方法。特殊对象Object的说明参见下方。 -
deps
一个用作存储的依赖数组。
返回值数组: -
[0] - Collected Props
:collect
方法返回的对象数据object。若collect
方法未定义,则返回的是空对象。 -
[1] - DragSource Ref
:拖拽源的连接器方法。此方法必须依附于DOM元素的拖拽部分。 -
[2] - DragPreview Ref
:拖拽预览的连接器方法。此方法必须依附于DOM元素的预览部分。
特殊对象Object
成员:
-
type
:必须。类型为字符串,拖拽目标的注册类型,只有类型相同才会响应。 -
item
:必须(object或function) 拖拽对象的内部数据定义 -
previewOptions
:可选。预览项 -
options
:可选。拖拽的操作行为对象数据-
dropEffect
:拖拽的影响:move或copy是可选项
-
-
end(item, monitor)
:可选。当拖拽停止时,此方法会被调用。 -
canDrag(monitor)
:可选。用此方法定义拖拽在当前是否被允许。 -
isDragging(monitor)
:可选。拖拽时的方法。 -
collect
:可选。收集方法。返回一个对象数据注入你的组件。
useDrop:
参数:
-
spec
一个特殊对象Object
或创建特殊对象Object
的方法。特殊对象Object的说明参见下方。 -
deps
一个用作存储的依赖数组。
返回值数组: -
[0] - Collected Props
:collect
方法返回的对象数据object。若collect
方法未定义,则返回的是空对象。 -
[1] - DropTarget Ref
:拖动源的连接器方法。此方法必须依附于DOM元素的拖动部分。
特殊对象Object
成员:
-
accept
:必须。类型为字符串,数组或方法,拖动目标的接受类型,只有类型相同才会响应。 -
options
:可选。 -
drop(item, monitor)
:可选。当兼容目标item
被拖动到目标上,此方法会被调用。 -
hover(item, monitor)
:可选。当item
悬浮到组件上,此方法会被调用。 -
canDrag(monitor)
:可选。用此方法定义拖动在当前是否被允许。 -
collect
:可选。收集方法。返回一个对象数据注入你的组件。
组件DragableBodyRow对于useDrag
以及useDrop
的处理如下:
const DragableBodyRow = ({ id, text, index, moveRow }) => {
const ref = useRef();
const [{ isOver, dropStyle }, drop] = useDrop({
//定义拖拽的类型
accept: ItemType,
collect: monitor => {
const { index: dragIndex } = monitor.getItem() || {};
// 如果拖拽目标和放置目标相同的话,停止执行
if (dragIndex === index) {
return {};
}
return {
isOver: monitor.isOver(),
dropStyle: dragIndex < index ? dropDownStyle : dropUpStyle,
};
},
drop: item => {
const dragIndex = item.index;
const hoverIndex = index;
moveRow(dragIndex, hoverIndex);
}
},
[index]
);
let _dropStyle = isOver ? dropStyle : {};
const [{ opacity }, drag] = useDrag({
type: ItemType,
item: { id, index },
collect: monitor => ({
isDragging: monitor.isDragging(),
opacity: monitor.isDragging() ? 0.5 : 1
})
},
[index]
);
drag(drop(ref));
return (
<div
ref={ref}
style={{ ...style, opacity, ..._dropStyle }}
>
<div className='row-item' dangerouslySetInnerHTML={{ __html: text }}></div>
</div>
)
}
以上就是对于模态框里的拖拽排序组件
的全部介绍,完整代码请前往github获取。