news 2026/9/11 6:13:16

React 拖拽排序别再用原生 DOM 了:React SortableJS 10 分钟上手指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
React 拖拽排序别再用原生 DOM 了:React SortableJS 10 分钟上手指南

React 拖拽排序别再用原生 DOM 了:React SortableJS 10 分钟上手指南

【免费下载链接】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是SortableJS之上的React绑定层,负责把DOM拖拽事件和你的组件状态对齐。做拖拽列表或看板时,你不用手写鼠标、触摸、滚动的逻辑,装包、包一层组件就能用。

它替你省掉了什么

手写拖拽用addEventListener很麻烦:拖一项状态跟不上还闪;卸载组件监听还在、会泄漏;触摸、滚动也得自己搞。React SortableJS把这三个坑收走了——传数组和setter就行,剩下的它代劳。你不用去读它的内部实现,装完就能把精力放回业务逻辑上,列表顺序、后端同步这些才是你真正要操心的事。

⚡ react-sortablejs 教程:从装包到第一个能拖的列表

最快的验证方式,就是先让三行字动起来。一行装包:

npm install react-sortablejs sortablejs

再写一个最小组件:

import { useState } from "react"; import { ReactSortable } from "react-sortablejs"; export function TaskList() { const [tasks, setTasks] = useState([ { id: "a", title: "写需求" }, { id: "b", title: "评审方案" }, { id: "c", title: "开始开发" }]); return ( <ReactSortable list={tasks} setList={setTasks} animation={150}> {tasks.map((t) => <div key={t.id}>{t.title}</div>)} </ReactSortable> ); }

改 list / setList / animation 三个 prop 就能接你自己的业务:list 是你的数组,setList 是你数组对应的 setter,animation 是落位过渡的毫秒数。拖完 React 会调用 setList 把新顺序写回状态,列表就跟着变了,你不用碰任何 DOM。

📋 React 拖拽列表的高频配置速查

能跑起来之后你会被一堆 prop 淹没,我平时只记这几个,够覆盖 90% 的场景:

prop干什么推荐值一句话备注
list / setList数据源与写回你的数组 + setState拖拽生效的一对,必填
animation落位过渡时长150太快生硬、太慢发飘
ghostClass拖拽时"空位"样式sortable-ghost控制那个洞长什么样
handle限定可拖区域的选择器.drag-handle只让把手能拖,防误触
group跨列联动开关{ name: "tasks" }列名一致才能互相放
delay / delayOnTouchStart按住多久才起拖100 / true移动端必加,否则挡滚动
forceFallback用 CSS 变换模拟拖拽大列表开 true避免真实 DOM 拖动卡顿
onEnd拖拽结束回调(e) => 保存在这里把新顺序同步后端

📊 看板拖拽多列联动怎么写

从单列表进真实产品,一般就两种需求:多列之间搬项目,或者单列里带约束地重排。先看看板,两列都挂同一个 group 名:

<ReactSortable list={todo} setList={setTodo} group={{ name: "kanban", pull: true, put: true }} animation={150}> {todo.map((t) => <div key={t.id}>{t.title}</div>)} </ReactSortable> <ReactSortable list={doing} setList={setDoing} group={{ name: "kanban", pull: true, put: true }} animation={150}> {doing.map((t) => <div key={t.id}>{t.title}</div>)} </ReactSortable>

这里 group 的 name 必须两列一致,SortableJS 靠它判断两个容器属不属于同一组,名字不同就认不出来,自然放不进去;pull / put 都设 true 是允许"既能拉出、又能放进来",只开一个方向就会变成单向通道。列与列之间不直接通信,它们都只监听同一个 group 名,这是看板拖拽实现的要害。顺便说,移动端还要补 delay={100} delayOnTouchStart,不然手指一触就起拖,跟上下滚列打架,体验会很糟。

第二个场景是单列表带把手重排,我一般直接这样配,既防误触又能锁住个别行:

<ReactSortable list={rows} setList={setRows} handle=".row-drag" filter=".row-actions" preventOnFilter onMove={(e) => !rows[e.relatedIndex]?.locked} animation={150}> {rows.map((r) => ( <div key={r.id} className="row"> <span className="row-drag" />{r.title} </div> ))} </ReactSortable>

handle 把可拖区域锁死在左侧把手上,点行内正文或按钮就不会误触发拖拽;filter 加 preventOnFilter 把操作列排除掉,同时避免点击事件被吞。onMove 里判断目标行是否 locked,返回 false 就拦下这次放置,于是"有的行不让动"这种约束一行就写完了,不用自己监听拖拽过程。

🕳 react 列表拖拽四个我踩过的坑

坑一:症状是拖完某行,文字内容错位了,像串到了别的行。根因是 key 用了 index,React 调和时复用了旧节点。修复:key={item.id}。

坑二:症状是手机上列表要么滑不动、要么一碰就拖。根因是触摸设备没设延迟,拖拽和滚动在抢同一个手势。修复:补上 delay={100} delayOnTouchStart。

坑三:症状是看板两列之间拖过去又弹回来,或者根本放不进去。根因是两列 group 的 name 不一致,或 put 是 false。修复:统一成 group={{ name: "kanban", pull: true, put: true }}。

坑四:症状是两百行的列表一拖就掉帧,整页都在重渲染。根因是每次拖拽都更新数组,子项组件跟着全部重算。修复:把行组件用 React.memo 包一层,并保证 id 稳定。

接下来看什么

到这里,你页面上已经有一个能拖、能同步状态的 React 拖拽排序列表了。想看看真实产品里拖拽是怎么落地、以及这个仓库前端的目录约定,可以直接翻下面两处,比啃教程更快。

  • 通用拖拽控制器实现:generic-drag-and-drop.controller.ts
  • 前端开发约定:frontend/doc/README.md

【免费下载链接】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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 6:13:01

让 HeyGem.ai 在 WSL 中用上 GPU:Docker 数字人服务部署与排障

让 HeyGem.ai 在 WSL 中用上 GPU&#xff1a;Docker 数字人服务部署与排障 【免费下载链接】Duix-Avatar &#x1f680; Truly open-source AI avatar(digital human) toolkit for offline video generation and digital human cloning. 项目地址: https://gitcode.com/GitHu…

作者头像 李华
网站建设 2026/9/11 6:11:57

国产FPGA一次点亮全流程:从RDP架构到产线落地

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 6:10:15

MicroPython轻量级日志模块设计:级别、轮转与过滤实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 6:01:35

物联网STM32图书馆管理系统:RFID借书、ESP8266透传与上位机联动实践

简介&#xff1a;面向毕业设计场景的物联网图书管理系统项目包&#xff0c;融合STM32嵌入式、RFID识别与Java后端技术&#xff0c;兼顾嵌入式开发与后台管理需求&#xff0c;解决书店图书库存实时更新与信息化管理问题&#xff0c;适合计算机、物联网专业学生用于课程设计或毕设…

作者头像 李华