layui table不支持行拖拽排序,需手动绑定原生drag事件并同步更新DOM与table.cache数据,移动端应改用touch事件模拟,且每次拖拽后须立即持久化新顺序。
layui table 行拖拽排序需要自己写,官方没提供
layui 的 table 模块本身不支持行拖拽排序,连 dragsort 这类配置项都不存在。你看到的“拖拽效果”,基本是靠监听 mousedown/mousemove + 手动操作 dom + 重绘数据实现的,本质是模拟,不是内置能力。
真正能用的路径只有一条:在表格渲染后,给 tbody 或每行 tr 绑定原生拖拽事件(dragstart/dragover/drop),再配合 table.cache 或你维护的数据源做顺序交换。
- 别试图在
table.render()里加参数开启拖拽——没这个开关 - 别依赖
table.on('sort(...)'),那是列头点击排序,和拖拽无关 - 如果用了
table.setColsWidth()或固定列,拖拽时容易错位,得手动重置tr的style
拖拽时 tbody tr 顺序变了但数据没变,页面就乱了
这是最常踩的坑:DOM 层面拖动了 tr,但 table.cache['yourId'] 里的数组顺序完全没动。下次调用 table.reload() 或触发筛选/分页,表格立刻回滚到原始顺序,甚至报 Uncaught TypeError: Cannot read property 'children' of null。
必须同步更新两处:一是 DOM 中 tr 的位置,二是对应的数据缓存。推荐直接操作 table.cache,再调用 table.reload() 刷新视图(轻量且稳定)。
- 在
drop事件里,用Array.splice()移动table.cache['id']中的目标项 - 移动前先用
tr.dataset.index或tr.rowIndex定位源/目标行索引 - 别用
innerHTML += ...拼接新tbody,会丢失事件绑定和 layui 内部状态 - 如果开启了分页,
table.cache只存当前页数据,拖拽跨页会失效——得先加载全量数据或改用前端全量管理
移动端拖拽体验差,手指一滑就触发浏览器默认滚动
在 iOS 或安卓 WebView 里,dragstart 很难触发,手指稍一偏移就会变成页面滚动,drop 根本收不到。这不是 layui 的问题,是移动端对原生 drag API 支持极弱。
务实解法是放弃原生 drag,改用 touchstart/touchmove/touchend + CSS transform: translateY() 模拟拖拽视觉反馈,松手后才真正交换数据并重绘。
- 给每行
tr加touch-action: none,阻止默认手势干扰 -
touchmove中用event.touches[0].clientY计算偏移,动态设置被拖行的transform - 松手时遍历其他
tr的getBoundingClientRect().top,判断插入位置 - 别依赖
dragenter,移动端基本不触发
reload 后拖拽状态丢失,排序结果不持久
table.reload() 会清空所有自定义 DOM 状态,包括你加的 draggable="true"、data-dragging="1" 这类标记。如果用户拖完还没提交,切个页签再回来,排序就没了。
关键动作是:拖拽完成那一刻,就把新顺序存到你可控的地方——比如全局变量、localStorage,或者直接发请求落库。别等用户点“保存”按钮才处理。
- 每次成功交换后,立刻执行
localStorage.setItem('tableSortOrder', JSON.stringify(newOrder)) - 在
table.render()前,先读取localStorage并按顺序重组原始数据数组 - 如果后端要求排序字段(如
sort_order),拖拽完就得调axios.post('/api/sort', { ids: [101, 205, 302] }),别攒着 - 注意
table.cache是响应式引用,直接改它再reload即可,不用深克隆
拖拽排序不是加个插件就能跑的事,核心在于你是否愿意接管数据生命周期——从 DOM 位移、内存顺序、本地缓存到服务端落库,每个环节断掉,用户就会觉得“刚排好的又乱了”。最易忽略的是:没在 done 回调里重新绑定拖拽事件,reload 后新生成的 tr 是没事件的。


















