当前位置: 首页 > news >正文

React实现列表拖拽排序

本文主要介绍一下React实现列表拖拽排序方法,具体样式如下图
在这里插入图片描述

首先,简单展示一下组件的数据结构

const CodeSetting = props => {const {$t,                    // 国际化翻译函数vm,                    // 视图模型数据vm: {CodeSet: { Enable = [],    // 启用的编码列表Disable = []    // 停用的编码列表}},getConfig,             // 获取配置的函数save,                  // 保存配置的函数vmChange               // 更新视图模型的函数} = props;
};

完整的数据结构示例

const vm = {CodeSet: {Enable: [{ Compression: "H.264" },{ Compression: "H.265" },{ Compression: "MPEG-4" }],Disable: [{ Compression: "AVC" },{ Compression: "HEVC" }]}
};

主要用到的代码如下,简单看后我将介绍拖拽方法

{Enable.length ? (<Cardtitle={`${$t('com.EnableCode')} (${Enable.length})`}extra={<Buttonsize='small'className='clear-all-btn'type='link'onClick={clearAllEnabled}>{$t('com.ClearAll')}</Button>}>{Enable.map((item, index) => (<divkey={index}className='drag-item'draggableonDragStart={e => {handleDragStart(e, index);}}onDragEnd={handleDragEnd}onDragOver={handleDragOver}onDrop={e => handleDrop(e, index)}><div className='drag-handle'>⋮⋮</div><LabelText text={item.Compression} /><div className='delete-btn-container'><Iconcomponent={remove}onClick={() => codeSetChange('remove', index)}style={{fontSize: '20px'}}/></div></div>))}</Card>

首先用到的组件是Card组件,title是card标题,extra是card后缀

之后遍历Enable数组,将拿到的每一个值渲染到card中

这个组件实现了 HTML5 原生拖拽 API 来实现编码列表的拖拽排序功能。主要使用了以下拖拽事件:

onDragStart - 拖拽开始
onDragOver - 拖拽悬停
onDrop - 拖拽放置
onDragEnd - 拖拽结束

状态管理

const [draggedIndex, setDraggedIndex] = useState(null); // 记录当前拖拽项的索引

拖拽事件处理函数

1 拖拽开始 (handleDragStart)

const handleDragStart = (e, index) => {setDraggedIndex(index);                    // 记录拖拽项的索引e.dataTransfer.effectAllowed = 'move';    // 设置拖拽效果为移动e.currentTarget.classList.add('dragging'); // 添加拖拽样式
};

2 拖拽悬停 (handleDragOver)

const handleDragOver = e => {e.preventDefault();                         // 阻止默认行为e.dataTransfer.dropEffect = 'move';        // 设置放置效果为移动// 清除所有拖拽项的悬停样式const dragItems = document.querySelectorAll('.drag-item');dragItems.forEach(item => {item.classList.remove('drag-over');});// 为当前悬停元素添加悬停样式e.currentTarget.classList.add('drag-over');
};

3 拖拽放置 (handleDrop)

const handleDrop = (e, dropIndex) => {e.preventDefault();e.currentTarget.classList.remove('drag-over');if (draggedIndex === null || draggedIndex === dropIndex) {return;}// 重新排序 Enable 数组const enableList = [...Enable];const draggedItem = enableList[draggedIndex];// 移除拖拽项enableList.splice(draggedIndex, 1);// 在目标位置插入enableList.splice(dropIndex, 0, draggedItem);// 更新vm数据const newCodeSet = {...vm.CodeSet,Enable: enableList};vmChange({ CodeSet: newCodeSet });setDraggedIndex(null);
};

4 拖拽结束 (handleDragEnd)

const handleDragEnd = e => {setDraggedIndex(null);e.currentTarget.classList.remove('dragging');// 清除所有拖拽项的悬停样式const dragItems = document.querySelectorAll('.drag-item');dragItems.forEach(item => {item.classList.remove('drag-over');});
};

5.JSX 结构

<divkey={index}className='drag-item'draggable                                    // 设置为可拖拽onDragStart={e => handleDragStart(e, index)} // 拖拽开始onDragEnd={handleDragEnd}                    // 拖拽结束onDragOver={handleDragOver}                  // 拖拽悬停onDrop={e => handleDrop(e, index)}>          // 拖拽放置<div className='drag-handle'>⋮⋮</div>        // 拖拽手柄<LabelText text={item.Compression} /><div className='delete-btn-container'>{/* 删除按钮 */}</div>
</div>

6. 核心算法

  1. 拖拽排序的核心算法是数组重排序:
  2. 获取拖拽项:从原位置取出拖拽的元素
  3. 移除拖拽项:在原位置删除该元素
  4. 插入新位置:在目标位置插入该元素
  5. 更新状态:将新的数组顺序更新到组件状态

7. 样式处理
组件通过 CSS 类名来管理拖拽状态:
.dragging - 拖拽中的样式
.drag-over - 拖拽悬停的样式
.drag-item - 可拖拽项的基础样式

8.样式代码

    // 拖拽项容器.drag-item {display: flex;align-items: center;cursor: grab;&:hover {background-color: #f5f5f5;}// 拖拽中状态&.dragging {background-color: #e6f7ff;opacity: 0.5;transform: scale(0.95);}// 拖拽悬停状态&.drag-over {background-color: #e6f7ff;border: 1px solid #91d5ff;border-radius: 4px;}}// 拖拽手柄.drag-handle {margin-right: 8px;color: #2f2e2e;font-size: 12px;user-select: none;}
http://www.dtcms.com/a/365305.html

相关文章:

  • PyTorch实战(6)——模型微调详解
  • 落地页测试case(Android视角)
  • Redis突然挂了,数据丢了多少?就看你用RDB还是AOF
  • SecureCRT v9.5.2 Mac SSH终端操作工具
  • C++从入门到实战(二十一)List迭代器实现
  • 行业分享丨基于SimSolid的大型汽车连续冲压模具刚度分析
  • 【Axure高保真原型】区间缩放柱状图
  • JavaScript箭头函数与普通函数:两种工作方式的深度解析
  • android studio打开Android Device Monitor
  • Java 鲁棒性:支撑企业级应用稳定运行的核心密码
  • websoket使用记录
  • 马斯克砸钱造AI,却败给最low的“让离职员工轻松拷走代码”
  • OpenLayers 入门篇教程 -- 章节三 :掌控地图的视野和交互
  • 《计算机网络安全》实验报告一 现代网络安全挑战 拒绝服务与分布式拒绝服务攻击的演变与防御策略(1)
  • 【全息投影】幻影成像技术在展厅中的创新应用
  • 求单源最短路(Dijkstra 算法-迪杰斯特拉算法,SPFA)
  • word文档封面中文件编号等标题和内容无法对齐
  • 关于QSharedPointer
  • 清理磁盘:卸载 GitLab CI/CD Multi-Runner 删除docker相关文件
  • linux服务开机自启动之二(forking方式)
  • undo-log
  • 用 “走楼梯” 讲透动态规划!4 个前端场景 + 4 道 LeetCode 题手把手教
  • MySQL的utf8 、utf8mb3 和 utf8mb4 的区别和排序规则
  • 摄像头现代实现WIFI远程实操画面移动
  • Flutter环境搭建全攻略之-Macos环境搭建
  • 【Layui】Layui Table 底部合计栏实现方案
  • CentOS安装vulhub靶场
  • 不同数据类型for循环
  • 从一道面试题开始:如何让同时启动的线程按顺序执行?
  • 物联网能源管控平台建设方案