Layui 原生 table 组件在处理行拖拽时存在明确限制:它只响应上下方向的拖拽(即垂直重排),左右拖拽在表格行上基本没有语义,浏览器不会触发有效的 drop 区域判断。很多人以为能像 Excel 那样横向拖动行数据,这其实是一个视觉误会——Excel 可以拖拽列宽、列顺序、行高,但行数据左右拖
Layui 原生 table 组件在处理行拖拽时存在明确限制:它只响应上下方向的拖拽(即垂直重排),左右拖拽在表格行上基本没有语义,浏览器不会触发有效的 drop 区域判断。很多人以为能像 Excel 那样横向拖动行数据,这其实是一个视觉误会——Excel 可以拖拽列宽、列顺序、行高,但行数据左右拖拽本身并不存在。实际上的真实需求通常只有两点:上下拖拽调整行顺序,以及列头左右拖拽调整列显示顺序。下面直接进入实操重点。
浏览器对 tr 元素的 dragover 事件只在垂直方向有稳定的触发逻辑。一旦鼠标横向移动,e.clientY 变化微弱,用 getBoundingClientRect().top 判断插入位置很容易失效,结果误判为“同一行内”,导致 DOM 顺序混乱甚至卡死。Layui 渲染出的 tbody 是块级流式布局,没有 display: flex 或 grid 提供的横向坐标锚点,强行计算 left/right 位置基本等同于猜测坐标。
长期稳定更新的攒劲资源: >>>点此立即查看<<<

这是目前最稳定、兼容性最好、移动端也能优雅 fallback 的方案。关键在于“拖完怎么同步数据”,而不是拖拽本身。
table.render() 的 done 回调执行完毕后再初始化拖拽,否则 tbody 还没挂到 DOM 上。Sortable.create(tbody, { ... }),千万不能选择 table.elem —— 那个是 div.layui-table 容器,不是真正的 tbody。onEnd 里不要直接操作 table.cache,应该按照 tr 顺序读取 data-index 或你存储的唯一 ID,重新排列原始数据数组。table.reload('demo', { data: newArr }),而不是 table.reloadData() —— 后者不重置分页状态,翻页后顺序就会全部乱掉。iOS Safari 和安卓 Chrome 完全不触发 dragstart/dragover/drop。你写的 draggable="true" 在手机上等于没写。
'ontouchstart' in window,走 touchstart/touchmove/touchend 流程。touchstart 里立刻 e.preventDefault(),否则 iOS 会抢走事件并滚动页面。touchmove 中用 e.touches[0].clientY 计算位置,并缓存 tr.getBoundingClientRect() 结果,不要在每一帧都重新计算。DOM 已经动了,但 table.config.data 没动,table.cache 还是旧顺序——导出、搜索、分页全部错乱。这不是 bug,而是你缺了一个关键步骤。
tbody tr,读取每个 tr 上的 data-index 属性(渲染时 Layui 自动写入)。newArr = dataIndexList.map(i => originData[i])。table.reload() 的 data 参数是完整的新数组,不是部分 splice 或对象引用。table.cache['demo'] 赋值——reload 会覆盖它,而且 initSort、page 等状态不会自动更新。真正麻烦的从来不是拖拽动画,而是 DOM、内存数组、Layui 内部缓存三者之间那不到 10 行代码的同步时机。少一个 preventDefault(),少一次 reload,或者把 data-index 当成 index() 使用,整个排序就会变成“看起来动了,其实没变”。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述