ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

React 拖拽排序实战:react-sortablejs 从表格行 handle 到跨列迁移的 4 个场景配置

React 拖拽排序实战:react-sortablejs 从表格行 handle 到跨列迁移的 4 个场景配置 React 拖拽排序实战react-sortablejs 从表格行 handle 到跨列迁移的 4 个场景配置【免费下载链接】openprojectOpenProject is the leading open source project management software for product, project and portfolio management. A powerful Jira alternative with agile planning, issue tracking, roadmaps, Gantt charts, time tracking, collaboration features, and more. Available on premises or in the cloud. ⭐ Star us on GitHub项目地址: https://gitcode.com/GitHub_Trending/op/openproject后台管理界面里让用户自定义排列模块面板和表格行的拖拽排序需求用 react-sortablejs 半天就能落地。本文按表格行排序、审批流跨列迁移、大列表调优、触摸参数四个场景把每个场景该配哪些参数、会踩哪些坑讲清楚。为什么选它OpenProject 官方前端走的是 dragula 与 atlaskit/pragmatic-drag-and-drop 路线见 frontend/package.json并在 frontend/src/common/drag-and-drop/sortable-lists-engine.ts 里包了一层自研引擎。但在 React 子应用里实现同类交互react-beautiful-dnd 已停止维护且只适合简单单列dnd-kit/sortable 跨列迁移要自己拼列表测量逻辑。react-sortablejs 最省事——传一个 React 数组它直接替你重排代价是 API 偏老、维护节奏慢。30 秒跑通最小可运行示例最小配置只需要数据、setList 和一个 handle下面 17 行可以直接放进任何 Vite/CRA 工程import { useState } from react; import { ReactSortable } from react-sortablejs; const MODULES [Backlog, Sprint, This Week, Done, Blocked]; export function ModuleReorder() { const [modules, setModules] useState(MODULES); return ( ReactSortable list{modules} setList{setModules} handle.grip animation{150} {modules.map((name) ( div classNamemodule-row key{name} span classNamegrip aria-label拖拽手柄⋮⋮/span {name} /div ))} /ReactSortable ); }关键 props 各一句话list/setList数据源和 setter拖拽结束后库回调 setList你不需要读 DOM。handle只有匹配选择器的元素能发起拖拽其余区域保持点击语义。animation占位块过渡的毫秒数0–200 之间通常够用。ghostClass原位占位块的 class默认值sortable-ghost没有样式必须自己定义。 场景 A带 handle 的行级局部排序工作包列表动辄几十行用户想把高优先级条目顶到最前但整行可拖会和点击选中/展开冲突所以必须提供独立的拖拽手柄。OpenProject 自身的工作包模块就是这个结构见 frontend/src/app/features/work-packages/。下面这段把行内的编辑按钮区从拖拽范围里排除function WorkPackageTable({ rows, setRows }) { return ( ReactSortable list{rows} setList{setRows} handle.row-grip // 只有左侧手柄能发起拖拽 filter.row-actions // 行内操作按钮区不参与 preventOnFilter {rows.map((row) ( div classNamewp-row key{row.id} span classNamerow-grip⠿/span span classNamewp-idWP-{row.id}/span span classNamewp-subject{row.subject}/span div classNamerow-actionsbutton编辑/button/div /div ))} /ReactSortable ); }关键参数handle.row-grip拖拽的唯一入口行内其他点击不受影响。filter.row-actions命中选择器的元素不触发拖拽。preventOnFilter命中 filter 时阻止默认行为避免误触浏览器缩放/滚动。容器默认是div别把tr直接塞给 ReactSortable用 div 行模拟表格或改成卡片列表。高频坑点拖拽时条目消失→ 默认 ghostClass 无样式占位块高度塌成 0 → 自定义 ghostClass 并保持占位块原高度。handle 不生效→ 手柄元素必须位于拖拽项容器直接子元素内部写在容器外层或祖先上无效。 场景 B审批流节点跨列迁移审批流配置是典型的跨列拖拽节点要在部门负责人审核 / 财务审核 / 归档之间移动。先说清机制内部 onSort 只在 oldIndex 和 newIndex 都落在当前列表范围内才调 setList跨列拖拽必然越界状态不会自动同步必须在 onEnd 里手动合并。下面这段统一管理三列状态跨列时在 onEnd 里搬移function ApprovalFlowBoard() { const [nodes, setNodes] useState({ dept: [{ id: n-11, title: 金额超五万需双人复核 }], finance: [{ id: n-23, title: 付款方式须银行转账 }], archived: [], }); const onEnd (evt) { if (evt.from evt.to) return; // 同列重排setList 已处理 const fromKey evt.from.dataset.stage; const toKey evt.to.dataset.stage; const moved [...nodes[fromKey]]; const [node] moved.splice(evt.oldIndex, 1); const target [...nodes[toKey]]; target.splice(evt.newIndex, 0, node); setNodes({ ...nodes, [fromKey]: moved, [toKey]: target }); }; return [dept, finance, archived].map((key) ( section key{key} ReactSortable list{nodes[key]} setList{(list) setNodes((prev) ({ ...prev, [key]: list }))} group{{ name: approval-chain, pull: true, put: true }} />const RowItem React.memo(function RowItem({ row }) { return div classNamewp-row{row.subject}/div; }); function LargeList({ rows, setRows }) { const onSort useCallback((next) setRows(next), [setRows]); // 稳定引用 return ( ReactSortable list{rows} setList{onSort} forceFallback // CSS transform 克隆避开原生 DnD 的布局抖动 fallbackOnBody animation{0} // 大列表关掉占位动画 {rows.map((row) RowItem key{row.id} row{row} /)} /ReactSortable ); }关键参数forceFallback用 transform 克隆替代原生 HTML5 DnD条目插入/移除时浏览器不做整块布局重排。fallbackOnBody克隆节点挂到 body规避祖先 transform/filter 形成包含块导致克隆偏移。animation{0}大列表关掉占位过渡省一帧过渡计算。React.memouseCallbacksetList 每次渲染都是新函数引用一变库内部会重建 Sortable 实例先稳定引用再谈性能。高频坑点怎么优化都是全行重渲染→ 行组件没 memo 或 setList 引用不稳定整个列表跟着重建 → 先查回调引用是否稳定再 memo 行组件。 场景 D触摸误触与灵敏度调优手机和平板上有两个问题滚动列表误触发拖拽拖拽中手指滑出可视边缘后不会继续滚动跟随。ReactSortable list{cards} setList{setCards} forceFallback // 触摸不支持 HTML5 DnD必须走 fallback delay{150} // 触摸后等 150ms 再判定拖拽 delayOnTouchOnly // delay 只对触摸生效鼠标不受影响 scroll scrollSensitivity{40} scrollSpeed{15} {cards.map((card) ( div key{card.id} classNamesp-card{card.name}/div ))} /ReactSortable关键参数forceFallback触摸设备不支持 HTML5 原生拖拽不开 fallback 幽灵块根本不跟手。delaydelayOnTouchOnly触摸后延迟判定拖拽滚动时不会误触发配合delayOnTouchOnly保证鼠标体验不变慢。scrollSensitivity/scrollSpeed距边缘多少像素触发自动滚动、滚多快必须真机微调。touchStartThreshold拖拽启动前的最小移动像素数默认 5调大降低误触调小提升跟手性。高频坑点delay 调大后鼠标也变迟钝→ delay 默认对鼠标和触摸都生效 → 打开delayOnTouchOnly把延迟限制在触摸端。配置速查表配置项类型默认值一句话用途listT[]—数据源要渲染的 React 数组set【免费下载链接】openprojectOpenProject is the leading open source project management software for product, project and portfolio management. A powerful Jira alternative with agile planning, issue tracking, roadmaps, Gantt charts, time tracking, collaboration features, and more. Available on premises or in the cloud. ⭐ Star us on GitHub项目地址: https://gitcode.com/GitHub_Trending/op/openproject创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表