应直接操作 table.cache 数组并调用 table.reload(),因 DOM 移动(如 insertBefore)不改变数据源,会导致分页、选中、排序等状态错乱;table.cache 才是 Layui 维护的数据副本,修改它才能生效。
直接操作 table.cache 数组并调用 table.reload(),而不是移动 dom 元素 —— 否则分页、选中状态、排序字段都会错乱。
为什么不能用 insertBefore 移动 tr 元素
常见错误是监听按钮点击后执行 $(tr).insertBefore($(tr).prev())。这看似“行上移了”,但 Layui 的 table.reload() 会用原始数据全量重绘,你刚挪的 tr 立刻被覆盖;同时 data-index 不变,导致下一次操作索引错位;多选状态、滚动位置、展开行全部丢失。
- DOM 操作只影响当前渲染快照,不改变数据源
-
table.cache['id']是 Layui 内部维护的当前页数据副本,改它才有效 - 若用了服务端分页,
table.cache仅含当前页数据,跨页移动需额外处理
如何安全交换数组元素(上移 / 下移)
拿到当前行在本页的 data-index(字符串),转为数字后做边界判断,再交换 table.cache 中对应下标的两个对象。
- 上移:交换
i和i-1,前提是i > 0 - 下移:交换
i和i+1,前提是i < cache.length - 1 - 别用
splice链式调用,比如arr.splice(i,1,arr.splice(i-1,1,arr[i-1])),极易因返回值类型出错 - 推荐经典三步:
let tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp;
示例(上移):
const cache = table.cache['testReload'];
const idx = parseInt(obj.tr.attr('data-index'));
if (idx > 0) {
const tmp = cache[idx];
cache[idx] = cache[idx - 1];
cache[idx - 1] = tmp;
table.reload('testReload');
}reload 后怎么保住选中和滚动位置
table.reload() 必然清空所有 UI 状态,必须手动恢复。最容易漏的是「只存了数据没存状态」。
- 多选状态:reload 前用
table.checkStatus('id').data拿到已选项 ID 列表,reload 后遍历cache找匹配项,设checked: true并调用table.checkRow() - 滚动位置:reload 前记录
$('.layui-table-box').scrollTop(),done 回调里用setTimeout(() => { ... }, 0)确保 DOM 已更新再设置回去 - 单行高亮:不能靠 class 维持,得在
done回调里重新查data-index对应的tr并加 class
边界情况和性能提醒
500 行以上频繁 reload 会卡顿;开启分页时 data-index 只对当前页有效;服务端排序字段(如 sort_no)未同步会导致下次刷新还原。
- 上移到顶 / 下移到底:不是反复调用上移,而是用
cache.unshift(cache.splice(idx, 1)[0])或cache.push(cache.splice(idx, 1)[0]) - 如果表格启用了
page: true,且需要跨页移动,必须先获取全局唯一 ID,再请求后端调整序号,前端 reload - 高频操作建议改用
table.cache+ 手动 patch DOM(需自行更新tr的data-index和td内容),绕过 reload
真正麻烦的从来不是交换两行,而是 reload 后那一堆要手动兜底的状态 —— 尤其是滚动位置和 checkbox 的 checked 字段,不显式重置就永远不对。


















