必须在 done 回调中操作 DOM 才能安全合并单元格,因 Layui 表格异步渲染且内部使用虚拟 DOM 重绘,提前操作或配置 rowspan 均无效;需用 data-field 定位列、textContent 比对值、显式处理 null/undefined,并每次清除旧 rowspan 和隐藏状态。

必须在 done 回调里手动操作 DOM,其他任何位置写合并逻辑都会失效——Layui 表格是异步渲染的,table.render() 调用完 DOM 还没生成,$('#demo').find('td') 一定为空。
为什么不能在 cols 配置或 render 函数里设 rowspan?
Layui 会忽略你硬写的 rowspan 属性,也不支持通过 templet 返回带 rowspan 的 HTML 字符串。它内部用虚拟 DOM 重绘表格,每次分页、排序、重载都会清空你手动加的属性。所有“配置即生效”的尝试,上线后遇到翻页就崩。
-
cols: [{ field: 'deptName', rowspan: 2 }]—— 完全无效 -
templet: () => '<td rowspan="2">xxx</td>'—— 渲染后被覆盖,且破坏表格结构 - 在
render()调用后立即遍历$('td')—— 找不到元素,length === 0
怎么安全定位目标列并比对值?
别硬写 colIndex = 0,Layui 渲染后 td 顺序 ≠ cols 数组下标。前面有复选框、序号、fixed: 'left' 列,都会导致偏移。固定列还单独渲染在另一个 table 里,混算必错。
- 用浏览器 inspect 看目标
td是tr的第几个子节点(从 0 开始) - 或用
$('th[data-field="deptName"]').index()查表头列序,通常与数据行一致 - 比对必须用
td.textContent.trim(),不是innerHTML—— 否则带图标、空格、换行的字段永远不相等 - 若字段可能为
null或undefined,要显式判断:!currVal && !prevVal才算相等,避免null === undefined的语义错误
合并时最容易踩的三个坑
哪怕算法写对,漏掉任一状态清理,翻页后就会错位、重复合并、跨页粘连。
- 每次执行前必须清除旧的
rowspan和display: none:$('td[rowspan]').removeAttr('rowspan'); $('td:hidden').show(); - 遍历时要跳过已设
rowspan > 1的td,否则会把已合并单元格当新起点,导致 rowspan 叠加 - 多列合并必须独立维护状态:按
deptName合并 3 行、category合并 2 行,不能共用一个startRow变量——强行耦合会导致某列跨行错位 - 开启
height或scroll时禁用合并:虚拟滚动复用tr元素,rowspan会被挂到错误行上;如必须滚动,改用table.setRowData()+ 自定义模板输出空字符串(仅适用于单列、不依赖 DOM 顺序的场景)
最易被忽略的是空字段、跨页边界、固定列分离这三类情况。测试数据往往不触发它们,但真实数据一上来,合并就突然断开或错位——问题不在代码逻辑,而在 DOM 状态没管干净。


















