
1. 为什么需要动态表格合并单元格最近在做一个后台管理系统时遇到了一个典型需求展示接口分组数据时相同分组的接口需要合并单元格显示。比如一个支付接口组下有微信支付、支付宝支付等多个接口这时候就需要把支付接口组这个单元格合并起来显示。使用layui的table组件渲染动态数据时官方并没有提供现成的合并单元格方案。网上能找到的解决方案大多存在几个问题只适用于静态表格动态渲染后无法正确合并合并逻辑不够健壮遇到空数据会报错没有考虑layui自动生成的DOM结构特点我花了三天时间踩了各种坑最终摸索出一个稳定的解决方案。下面就把这个实战经验完整分享给大家包含你可能遇到的所有细节问题。2. 理解layui表格的DOM结构2.1 关键点表格的真实DOM位置很多开发者第一次尝试合并单元格时都会直接通过$(#tableId)来获取表格DOM这会导致代码失效。因为layui在渲染时会自动包裹多层容器实际结构是这样的div idyourContainer !-- layui自动添加的容器 -- div classlayui-table-box div classlayui-table-header table.../table !-- 这是表头 -- /div div classlayui-table-body table.../table !-- 这才是我们要操作的数据表格 -- /div /div /div正确的选择器写法应该是$(#yourContainer .layui-table-body table).find(tr)2.2 动态渲染的时机把握合并操作必须在表格渲染完成后执行这就是为什么代码要放在done回调里。但要注意一个细节当分页切换时done会再次触发所以合并逻辑需要能重复执行而不出错。3. 完整解决方案代码解析3.1 基础合并逻辑实现先看完整的代码实现后面我会逐行解释关键点table.render({ elem: #demo, // 其他配置... done: function(res, curr, count){ // 需要合并的列配置 var mergeConfig [ { field: group, index: 0 }, // 第1列按group字段合并 { field: type, index: 2 } // 第3列按type字段合并 ]; // 从第2行开始跳过表头 var startRow 1; var $rows $(#demo .layui-table-body table).find(tr); mergeConfig.forEach(function(config){ var colIndex config.index; var mergeCount 0; var mergeCells []; for(var istartRow; i$rows.length; i){ var $current $rows.eq(i).find(td).eq(colIndex); var $next $rows.eq(i1).find(td).eq(colIndex); var currentText $current.text(); var nextText $next.length ? $next.text() : null; if(currentText nextText){ mergeCells.push($current); mergeCount; }else{ if(mergeCount 0){ // 设置第一个单元格的rowspan mergeCells[0].attr(rowspan, mergeCount 1); // 隐藏其他重复单元格 mergeCells.slice(1).concat($current).forEach(function($td){ $td.addClass(layui-hide); }); } mergeCount 0; mergeCells []; } } }); } });3.2 关键代码解读mergeConfig配置项field仅作为注释说明实际未使用index要合并的列索引从0开始边界处理技巧var nextText $next.length ? $next.text() : null;这里处理了最后一行没有下一行的情况避免报错。合并实现原理找到连续相同值的单元格给第一个单元格设置rowspan给后续重复单元格添加layui-hide类隐藏性能优化点使用forEach替代for...of提升IE兼容性缓存$rows.length避免重复计算4. 实际开发中的坑与解决方案4.1 分页数据合并问题当表格开启分页时合并操作只对当前页有效。如果需要跨页合并有两种解决方案前端方案table.render({ limit: 9999 // 设置足够大的每页条数 });简单但数据量大时影响性能。后端方案 让接口返回已合并的数据结构并在前端做对应渲染。4.2 动态排序后的合并如果表格支持排序重新排序后需要重新合并。可以通过监听排序事件实现table.on(sort(demo), function(obj){ table.reload(demo, { initSort: obj, done: function(res, curr, count){ // 重新执行合并逻辑 } }); });4.3 自适应高度问题合并单元格后行高可能发生变化。需要手动调整// 在合并完成后执行 $(.layui-table-body).css(height, auto); layer.resize();5. 进阶支持多列同时合并原始方案每次只能处理一列的合并。改进后的版本可以支持多列独立合并function mergeCells($table, colIndexes, startRow){ colIndexes.forEach(function(index){ var $rows $table.find(tr); // ...合并逻辑... }); } // 使用方式 mergeCells($(#demo table), [0, 2], 1);这个封装后的函数可以复用支持任意多列合并。6. 最佳实践建议CSS优化 添加以下样式使合并后的单元格更美观.layui-table td[rowspan] { text-align: center; vertical-align: middle; }性能监控 大数据量时监控合并耗时console.time(merge); // 合并操作... console.timeEnd(merge);单元测试建议 测试用例应该覆盖空表格情况所有数据都不相同的情况连续多行相同的情况最后一行的特殊情况这个方案已经在我们的生产环境稳定运行半年多处理过各种边界情况。关键在于正确理解layui的DOM生成规则以及在合并时做好各种异常情况的防御处理。