项目要求
制作工作台页面:模块可根据后端配置动态展示,各模块可根据个人喜好进行拖拽布局,并保存。大致效果如下:
![在这里插入图片描述](https://img-blog.csdnimg.cn/f41856c76f5e4b20aabc443067b58896.png)
大致实现步骤
-
整体布局。首先需要对设计稿进行分析,大致分为左右两部分,可根据后端配置动态展示左右两模块的展示内容,各模块相对独立,各自发送请求根据返回数据展示模块内数据。(此处样式布局方式不做赘述,但要注意考虑后期左右模块可通过拖拽方式更换位置,宽度可能变化,需注意各模块布局内容的自适应问题
)
-
为页面布局添加 react-beautiful-dnd
拖拽组件。(组件的内部结构及参数API可查看文章末尾的参考文章)
实现代码
1.页面布局:
<div className={styles.workbench}>
<DragDropContext onDragEnd={onDragEnd}>
{/* 左侧中心布局 */}
<Droppable droppableId="centerModule">
{(provided) => (
<div className={styles.centerLayout} ref={provided.innerRef} {...provided.droppableProps}>
{renderDragItem(centerModuleList)}
{provided.placeholder}
</div>
)}
</Droppable>
{/* 右侧布局 */}
<Droppable droppableId="rightModule">
{(provided) => (
<div className={styles.rightLayout} ref={provided.innerRef} {...provided.droppableProps}>
{renderDragItem(rightModuleList)}
{provided.placeholder}
</div>
)}
</Droppable>
</DragDropContext>
</div>
2.拖拽结束的排序 js:
// 中心模块数据
const [centerModuleList, setCenterModuleList] = useState(Object.values(userWorkBenchConfig.centerModuleList));
// 右侧模块数据
const [rightModuleList, setRightModuleList] = useState(Object.values(userWorkBenchConfig.rightModuleList));
// 深拷贝
const deepClone = (orig) => {
var copy = Object.create(Object.getPrototypeOf(orig))
copyOwnPropertiesFrom(copy, orig);
return copy;
}
const copyOwnPropertiesFrom = (target, source) => {
Object.getOwnPropertyNames(source)
.forEach(ele => {
// 获取到每个属性的所有描述,然后重新定义对象的属性并返回此对象。
var desc = Object.getOwnPropertyDescriptor(source, ele);
Object.defineProperty(target, ele, desc)
});
return target;
}
// 拖拽结束放置 - 若拖拽位置或布局有一定规则,可在此处进行判断校验,最后将排序好的布局存储起来
const onDragEnd = (result) => {
// source 为源位置数据,destination 为目标位置数据
const { destination, source } = result;
const sourceIndex = source.index;
const destinationIndex = destination.index;
// 默认布局配置 - 默认中心布局为目标位置,右侧布局为源位置
let targetModuleList = centerModuleList;
let targetFn = setCenterModuleList;
let sourceModuleList = rightModuleList;
let sourceFn = setRightModuleList;
// 若拖拽源和目标在同一Droppable中,则只需重新排序一个Droppable;
// 若不在同一Droppable中,则两个模块都需重新排序
if (destination.droppableId === source.droppableId) {
if (sourceIndex === destinationIndex) {
return;
}
if (destination.droppableId === 'rightModule') {
targetModuleList = rightModuleList;
targetFn = setRightModuleList;
}
const userList = deepClone(targetModuleList);
const [draggedItem] = userList.splice(sourceIndex, 1);
userList.splice(destinationIndex, 0, draggedItem);
targetFn(userList);
} else {
if (destination.droppableId === 'rightModule') {
targetModuleList = rightModuleList;
targetFn = setRightModuleList;
sourceModuleList = centerModuleList;
sourceFn = setCenterModuleList;
}
// 深拷贝
const targetList = deepClone(targetModuleList);
const sourceList = deepClone(sourceModuleList);
// 从源数据中取出放入目标数据中
const [draggedSourceItem] = sourceList.splice(sourceIndex, 1);
targetList.splice(destinationIndex, 0, draggedSourceItem);
targetFn(targetList);
sourceFn(sourceList);
}
};
![在这里插入图片描述](https://img-blog.csdnimg.cn/00f29659bb5042beaa1548bd2dd28aaa.png)
参考文章:
组件标签结构参考:https://blog.csdn.net/dongliang3164/article/details/118905576
组件参数API参考:https://blog.csdn.net/tianxintiandisheng/article/details/107109890