layui table 的 cols 配置不支持动态合并单元格,必须在 done 回调中通过原生 JS 遍历 tbody 行,依据字段值连续相同手动设置 rowspan/colspan 属性实现合并。
layui table 的 cols 配置不支持动态合并单元格
layui 原生 table 组件的列配置(cols)只接受静态结构,rowspan 和 colspan 必须在初始化时写死,无法根据后端数据自动计算合并逻辑。这是最常被误解的起点——很多人以为加个 cellminwidth 或改个 align 就能触发合并,其实完全无关。
真正起作用的是渲染后的 DOM 操作,不是配置项。
- 所有“合并”效果都得靠
done回调里手动操作<td>的rowspan/colspan属性 -
initSort、defaultToolbar等配置对合并无影响 - 开启
height或使用scroll时,合并容易错位——因为虚拟滚动会复用<tr>,必须重算
在 done 回调里遍历 tbody tr 手动合并行
这是目前最稳定、兼容性最好的做法:等表格渲染完,用原生 JS 遍历 <tbody> 的行,按字段值是否连续相同来决定是否合并。关键点是「连续」——非连续重复值不能合并,否则会跨数据块出错。
示例场景:后端返回用户列表,按 deptName 合并第一列
table.render({
elem: '#demo',
url: '/api/users',
cols: [[
{field: 'deptName', title: '部门'},
{field: 'name', title: '姓名'},
{field: 'role', title: '角色'}
]],
done: function(res, curr, count) {
mergeRows('deptName', 0); // 合并第0列(deptName),按值连续相同
}
});
<p>function mergeRows(field, colIndex) {
const tbody = document.querySelector('#demo + .layui-table-box .layui-table-body tbody');
const rows = tbody.querySelectorAll('tr');
let rowspan = 1;
let currentVal = null;</p><p>for (let i = 0; i < rows.length; i++) {
const td = rows[i].cells[colIndex];
const data = JSON.parse(td.getAttribute('data-content') || '{}');
const val = data[field] || td.innerText.trim();</p><pre class='brush:php;toolbar:false;'>if (val === currentVal && i > 0) {
rowspan++;
td.style.display = 'none'; // 隐藏后续单元格
} else {
if (rowspan > 1) {
rows[i - rowspan].cells[colIndex].setAttribute('rowspan', rowspan);
}
currentVal = val;
rowspan = 1;
}} // 处理最后一组 if (rowspan > 1) { rows[rows.length - rowspan].cells[colIndex].setAttribute('rowspan', rowspan); } }
- 必须用
data-content取原始字段值,避免被格式化/过滤干扰(比如用了templet) - 不能直接用
innerText判断,因为可能含空格、换行或 HTML 标签 - 合并后记得调用
table.resize(),否则表头和内容可能错位
列合并(colspan)要小心表头与内容对齐
列合并本质是让一个 <td> 横跨多列,但 layui 表格的列宽由 width 或自动计算决定,colspan 不会自动拉伸该单元格宽度,容易导致文字溢出或遮挡相邻列。
- 优先考虑用
templet渲染组合字段(如把「城市+区域」拼成一列),比强行colspan更可控 - 若真要
colspan,需同步设置td.style.width,且注意响应式下宽度失效问题 - 表头(
thead)不支持colspan动态变化;如果内容行合并了 2 列,表头也得提前写死colspan="2",否则视觉断裂
分页、排序、搜索后合并失效怎么办
每次重载数据(table.reload())、切换页码、点击排序都会触发新渲染,之前手动加的 rowspan 全部丢失。这不是 bug,是预期行为——DOM 被替换了。
- 必须把合并逻辑封装成函数,并在所有可能触发重绘的地方调用:
done、page回调、sort回调、以及手动reload后的done - 不要在
render外部直接操作tbody,因为异步加载时 DOM 可能还没生成 - 如果用了服务端分页,确保后端返回的数据已按合并字段预排序,否则前端合并逻辑会断开
合并的本质是视觉聚类,不是数据建模。别指望它替代 groupBy 或后端聚合——字段值稍有差异(比如空格、大小写、null/undefined)就会让合并中断,这点最容易被忽略。









