唯一稳定可行的路径是在done回调中手动操作dom合并表格行:遍历tbody tr,用textcontent.trim()比对连续相同值,独立为每列维护状态,清除旧属性,禁用height避免虚拟滚动错位。
不能靠 cols 配置项实现,必须在 done 回调里手动操作 dom;所有“自动合并”幻想都会在分页、排序、重载后失效。
在 done 回调中遍历 tbody tr 合并行
这是唯一稳定可行的路径:表格渲染完成、数据已就位、DOM 可安全操作。此时遍历 tbody 下的 tr,比对目标列的 textContent 是否连续相同,再设 rowspan 并隐藏后续 td。
- 必须用
document.querySelector('.layui-table-body tbody')定位——$("#demo")找不到真实数据表,Layui 把它塞进了.layui-table-body > table里 - 目标列索引不是
cols数组下标,而是最终tr > td的位置(比如前面有复选框列,field: 'deptName'实际可能是第 2 列) - 比对值必须用
td.textContent.trim(),不能用innerHTML,否则带图标或空格的字段永远不相等 - 每次执行前先清除旧的
rowspan和display: none,否则翻页后会叠加错乱
合并多列时要分别计算,不能共用同一套计数器
不同字段的合并跨度完全独立。例如按 deptName 合并 3 行,category 却只重复 2 次,强行共用 mark 变量会导致错位甚至 DOM 异常。
- 每列合并需独立遍历一遍
tr,或一次遍历中为每列维护各自的currentVal、startRow、rowspan - 不要写成
if (data[i].deptName === data[i-1].deptName && data[i].category === data[i-1].category)—— 这是「同时相同」,不是「各自相同」 - 若某列含
undefined或null,需显式判断:!val && !prevVal才算相等,否则null === undefined为 true 但语义错误
开启 height 或 scroll 时合并会错位
虚拟滚动复用 tr 元素,导致 rowspan 被挂到错误行上。这不是 bug,是设计使然——Layui 不承诺滚动区域内的 DOM 稳定性。
- 禁用
height是最干脆的解法;如必须启用,改用table.setRowData()+ 自定义模板,在templet中用缓存逻辑输出空字符串(仅适用于单列、且不依赖排序后 DOM 顺序的场景) - 不要试图在
scroll模式下用done合并,即使成功也只对首屏有效,滚动后立即失效 - 如果项目必须支持滚动+合并,建议换用原生
<table> + <code>fetch分页,放弃 Layui table 的自动渲染能力最易被忽略的是:合并逻辑必须处理空字段、跨页边界、固定列分离这三类情况。哪怕只漏一种,上线后就会在特定数据组合下突然崩掉——而这种问题往往不会出现在测试数据里。











