必须在 done 回调里操作 DOM,否则找不到元素;Layui 表格异步渲染,done 回调确保 tbody 已挂载、数据已写入;合并需基于原始数据比对、清除旧属性、正确设置 rowspan 并隐藏后续单元格。
必须在 done 回调里操作 DOM,否则找不到元素
layui 表格是异步渲染的,table.render() 调用后 dom 还没生成,此时查 $('td') 或 $('#demo').find('table') 会返回空集合。唯一可靠时机是 done 回调——它保证 tbody 已挂载、数据已写入、真实表格结构就位。
常见错误包括:
- 把合并逻辑写在
render()调用之后、done之外——几乎必失效 - 用
$('#your-table-id')直接选中,实际匹配到的是外层容器(带layui-table-box的 div),不是真正的数据表格 - 在
init阶段或cols配置里加rowspan: 2——Layui 会忽略该字段
正确做法是限定父容器范围,再找内层表格:
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');
}合并哪一列?先确认真实 colIndex,别硬编码
Layui 渲染后,<td> 的顺序不等于 cols 数组索引。比如你配置了 {field: 'name', title: '姓名'},但它前面有复选框列、序号列、固定列,那它在 DOM 中可能位于第 3 个 <td>(索引 2),而非 0。
安全获取方式:
- 用浏览器开发者工具 inspect 目标
<td>,看它是<tr>下第几个子节点(从 0 开始) - 用
$('th[data-field="name"]').index()查表头列位置(th和td索引一致) - 如果该列设了
fixed: 'left',它会被渲染到独立的<table>中,不能和主表混算索引
注意:合并逻辑必须基于原始数据比对,而不是 td.textContent——后者含图标、HTML 标签时会误判。应和 res.data[i][field] 对齐。
手动合并三步:清旧、比对、设 rowspan + display: none
核心不是“视觉连在一起”,而是按数据连续性计算跨行数,并显式设置 rowspan、隐藏后续单元格。漏掉任一环节都会出错:
- 不先清除旧的
rowspan和display: none,翻页或重载后会叠加失效 - 遍历时没跳过已设
rowspan > 1的<td>,会导致重复合并、错位 - 用
visibility: hidden替代display: none——打印/导出时仍占位,表格错乱
示例(合并第 2 列,字段为 'category'):
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');
}
mark = 1;
mergeStart = i;
}
}
// 处理最后一组
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');
}
}
}排序、分页、搜索后必须重执行,不能只 run 一次
Layui 所有交互操作(点击表头排序、切换分页、触发搜索)都会销毁并重建 tbody,之前写的 rowspan 和 display: none 全部丢失。这意味着合并逻辑不是“初始化一次就行”,而是每次 done 触发都得完整跑一遍。
容易被忽略的点:
- 如果你把合并函数抽成独立方法但没在每次
done里调用,只有首次加载生效 - 用
table.reload()刷新数据时,done仍会触发,合并逻辑必须包含在内 - 合并涉及多列时(如先按 A 列合并,再按 B 列合并),要确保顺序合理,避免第二轮覆盖第一轮的
rowspan
真正麻烦的不是算法本身,而是时机、索引、状态清理这三件事必须同步到位——少一个,表格就裂开。


















