layui table 不支持行拖拽排序,需用 Sortable.js 管理视觉顺序,拖拽结束时更新 table.cache 并 reload 以保持数据一致性。

layui table 行拖拽排序需要自己实现,官方不支持
layui 的 table 模块本身没有内置行拖拽排序功能,table.render() 也不提供 dragSort 或类似配置项。想实现拖拽重排,必须借助外部拖拽库或原生 DragEvent + 手动 DOM 操作,再同步更新数据源和表格渲染状态。
推荐用 sortablejs 配合 layui table 的 reload
直接操作 tbody 的 tr 节点虽然可行,但容易破坏 layui 的内部索引(比如 data-index、复选框状态、展开行等),导致后续 table.checkStatus() 或 table.getData() 返回错乱。更稳妥的方式是:用 Sortable 管理视觉顺序,仅在拖拽结束时提取新顺序,更新原始数据数组,再调用 table.reload() 重绘。
- 引入
Sortable(v1.15+):<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.0/Sortable.min.js"></script>
- 初始化 table 后,获取其容器
tbody并绑定 Sortable:const sort = new Sortable(document.querySelector('#demo .layui-table tbody'), { animation: 150, handle: '.layui-table-body tr', // 可选:指定拖拽手柄(如加个 drag-icon 列) onEnd({ oldIndex, newIndex }) { // oldIndex/newIndex 是视觉位置,需映射到 data 数组索引 const data = table.cache['demo']; // 'demo' 是你的 table id const movedItem = data.splice(oldIndex, 1)[0]; if (newIndex > oldIndex) { data.splice(newIndex - 1, 0, movedItem); } else { data.splice(newIndex, 0, movedItem); } table.reload('demo', { data }); // 强制重载,保持选中态/分页等一致 } }); - 注意:如果启用了
page: true,拖拽只应在当前页生效;跨页拖拽逻辑需额外处理,且通常不符合 UX 直觉
拖拽后必须更新 data 缓存,不能只改 DOM
很多人尝试直接用 jQuery 或 insertBefore 移动 tr,结果发现 table.checkStatus('demo').data 还是旧顺序,或者翻页后顺序还原——这是因为 layui 的数据源完全来自 data 参数或 url 请求,DOM 只是视图。拖拽只是“看起来”变了,没动源头。
-
table.cache['demo']是当前页渲染所用的数据快照,修改它并reload是最轻量的同步方式 - 若用
url模式加载数据,拖拽后应把新顺序通过 API 提交服务端,再重新reload(避免本地缓存与服务端不一致) - 避免在
onEnd中直接调用table.updateRow()逐行更新:性能差,且无法保证顺序稳定(尤其有固定列时)
移动端拖拽体验差,建议加 fallback 或禁用
原生 DragEvent 在 iOS Safari 和部分安卓 WebView 中支持不稳定,Sortable 的 touch 事件模拟也常出现响应延迟或误触发。生产环境上线前务必真机测试。
- 可在初始化时检测:
if ('ontouchstart' in window) { sort.option('disabled', true); // 或换为点击排序按钮 } - 更推荐方案:PC 端启用拖拽,移动端隐藏拖拽手柄,改用「上移/下移」按钮 +
table.getCheckStatus()获取当前行索引做数组交换 - 拖拽过程中,
.layui-table-body默认有overflow: auto,可能导致拖拽时内容被裁剪,可临时加style="overflow: visible"修复
拖拽排序看似简单,真正落地时最麻烦的是「数据一致性」——DOM、缓存、服务端三者必须对齐。别省略 reload 步骤,也别绕过 table.cache 直接操作 tbody。


















