Layui表格行合并必须在done回调中手动操作DOM,因组件不支持原生rowspan配置,需遍历tr/td比对数据、设置rowspan并隐藏重复td,且分页排序后需重新执行。
行合并必须在 done 回调里手动操作 DOM
layui 的 table.render() 不支持配置项直接写 rowspan,所有动态行合并逻辑必须放在 done 回调中执行。这是因为表格 dom 是异步渲染的,done 是唯一能确保 tbody 已生成、数据已挂载的时机。
常见错误包括:
- 在
init或render调用前就查$('td')—— 查不到,返回空集合 - 把合并逻辑写在
cols配置里加rowspan: 2—— layui 会忽略该属性 - 用 CSS 隐藏重复
td(如visibility: hidden)却不设rowspan—— 视觉错位,打印/导出异常
如何安全定位目标 table 和 tr
动态表格渲染后,Layui 会在容器内生成两层 table:外层是带 layui-table-main 的包裹容器,内层才是真实数据表格。直接用 $('#demo') 选中的是外层,容易误操作。
正确做法是限定父容器范围,再找内层 table:
done: function(res, curr, count) {
const $table = $('#container').find('.layui-table-main table'); // ✅ 推荐
// const $table = $('.layui-table-body table'); // ✅ 也可,但多表格时易冲突
const $trs = $table.find('tbody tr'); // 只操作 tbody 行,跳过表头
}注意:$trs 索引从 0 开始,但第 0 行通常是表头(thead),所以遍历时应从 $trs.eq(1) 或过滤掉 thead 后再处理。
合并逻辑的关键三步:比对、计数、设置
核心不是“让某几行看起来连在一起”,而是基于原始数据连续性,用 JS 手动计算跨行数并写死 rowspan + 隐藏后续单元格。
- 比对字段值是否与上一行相同(不能只看 DOM 文本,要和
res.data对齐,避免格式化干扰) - 用
mark累计相同值的连续行数,遇到不同就重置 - 给首行对应
td设置rowspan=mark,其余同行td设display: none
示例片段(合并第 2 列,即索引 index: 2):
function mergeByField($trs, data, field, colIndex) {
let mark = 1;
let mergeStart = 0;
for (let i = 1; i < data.length; i++) {
if (data[i][field] === data[i - 1][field]) {
mark++;
} else {
$trs.eq(mergeStart).find('td').eq(colIndex).attr('rowspan', mark);
for (let j = 1; j < mark; j++) {
$trs.eq(mergeStart + j).find('td').eq(colIndex).css('display', 'none');
}
mergeStart = i;
mark = 1;
}
}
// 处理最后一组
if (mark > 1) {
$trs.eq(mergeStart).find('td').eq(colIndex).attr('rowspan', mark);
for (let j = 1; j < mark; j++) {
$trs.eq(mergeStart + j).find('td').eq(colIndex).css('display', 'none');
}
}
}分页、排序、搜索后合并失效怎么办
只要触发重绘(翻页、点列头排序、输入搜索关键词),Layui 就会销毁并重建 tbody,所有手动加的 rowspan 和 display: none 全部丢失。
解决方法只有一个:每次 done 都重新跑一遍合并逻辑,且必须幂等(重复执行不报错、不叠加)。
- 不要依赖全局变量缓存状态,所有状态从
res.data和当前$trs实时计算 - 如果合并列涉及格式化(如时间戳转 YYYY-MM-DD),务必在比对前统一处理,否则
'2026-04-21'和1745222820000会被判为不同 - 导出 Excel 时,
table.cache['your-id']返回的是当前页数据,若需全量合并,得提前存好原始数据或调用服务端接口重新拉取
最常被忽略的是:合并后没清掉旧的 rowspan 就直接设新值,导致某些单元格 rowspan 堆叠错乱。每次执行前建议先清理:$trs.find('td[rowspan]').removeAttr('rowspan')。


















