AngularJS动态表头(含colspan/rowspan)关联表体实现求助
解决动态合并表头与关联tbody的问题
我明白你的困扰了——你现在的代码能完美生成带colspan和rowspan的表头,但tbody部分完全没法和表头对应,因为你复用了表头的结构数组,而tbody需要的是横向排列的每一行数据,不是表头的层级结构。咱们来一步步搞定这个问题:
问题根源
finalArrayHTML是为表头的层级结构设计的(比如"Multi 1"占一行,下面是它的两个子列),但tbody需要的是把所有叶子列(没有子列的最终列)的第n个数据项组合成一行,比如第一行是所有列的第0个值,第二行是第1个,以此类推。
解决方案步骤
1. 扁平化获取所有叶子列
先写一个递归函数,把所有最底层的、没有子列的列收集起来——这些列就是tbody每个单元格对应的数据来源:
var getLeafColumns = function(data) { var columns = []; data.forEach(function(item) { if (item.SubColumns.length > 0) { // 有子列就递归进去收集 columns = columns.concat(getLeafColumns(item.SubColumns)); } else { // 没有子列,直接加入叶子列数组 columns.push(item); } }); return columns; };
2. 生成tbody的行数据
基于叶子列数组,循环生成每一行数据:
// 获取所有叶子列 var leafColumns = getLeafColumns(jsonDATA); // 生成tbody数据:每一行是所有叶子列对应索引的值 $scope.tbodyData = []; // 假设所有列的数据长度一致,取第一列的长度作为总行数 var totalRows = leafColumns[0].valor.length; for (var i = 0; i < totalRows; i++) { var currentRow = []; leafColumns.forEach(function(col) { // 把每个叶子列的第i个值加入当前行 currentRow.push(col.valor[i]); }); $scope.tbodyData.push(currentRow); }
3. 修改HTML中的tbody部分
把原来绑定finalArrayHTML的tbody改成绑定新生成的tbodyData:
<tbody> <tr data-ng-repeat="row in tbodyData"> <td data-ng-repeat="cell in row">{{cell}}</td> </tr> </tbody>
完整修改后的代码
控制器部分
angular.module('myapp', []).controller('tableColSpanRowSpan', ['$scope', function ($scope) { $scope.finalArrayHTML = []; var jsonDATA = [ { "rotulo":"Simple 1", "SubColumns":[ ], "valor":[ "simples 0", "simples 1", "simples 2", "simples 3", "simples 4", "simples 5", "simples 6", "simples 7", "simples 8", "simples 9" ] }, { "rotulo":"Simple 2", "SubColumns":[ ], "valor":[ "simples 0", "simples 1", "simples 2", "simples 3", "simples 4", "simples 5", "simples 6", "simples 7", "simples 8", "simples 9" ] }, { "rotulo":"Multi 1", "SubColumns":[ { "rotulo":"Sub 1", "SubColumns":[ ], "valor":[ "sub 0", "sub 1", "sub 2", "sub 3", "sub 4", "sub 5", "sub 6", "sub 7", "sub 8", "sub 9" ] }, { "rotulo":"Sub 2", "SubColumns":[ ], "valor":[ "sub 0", "sub 1", "sub 2", "sub 3", "sub 4", "sub 5", "sub 6", "sub 7", "sub 8", "sub 9" ] } ] } ]; // 原有的表头生成逻辑,保留不变 var getColSpan = function (data, count) { if (data.length > 0) { for (var c = 0; c < data.length; c++) { if (data[c].SubColumns.length > 0) { count = getColSpan(data[c].SubColumns, count); } else { ++count; } } } return count; }; var getDepth = function (obj) { var depth = 0; if (obj.SubColumns) { obj.SubColumns.forEach(function (d) { var tmpDepth = getDepth(d) if (tmpDepth > depth) { depth = tmpDepth } }) } return 1 + depth }; var getRowSpan = function (allData, index, count) { if (allData[index].SubColumns.length > 0) { } else { var depth = 0; for (var j = 0; j < allData.length; j++) { var depthTmp = getDepth(allData[j]); if (depthTmp > depth) { depth = depthTmp; } } return depth; } return count; }; var rowIndex = 0; var RecursiveFunction = function (data, currentRow) { for (var i = 0; i < data.length; i++) { var tmp = { title: data[i].rotulo, conteudo: data[i].valor, colSpan: getColSpan(data[i].SubColumns, 0), rowSpan: getRowSpan(data, i, 0) }; if (typeof $scope.finalArrayHTML[rowIndex] == 'undefined') { $scope.finalArrayHTML[rowIndex] = []; } $scope.finalArrayHTML[rowIndex].push(tmp); if (data[i].SubColumns.length > 0) { ++rowIndex; RecursiveFunction(data[i].SubColumns, data[i]); --rowIndex; } } }; RecursiveFunction(jsonDATA, 0); // 新增的tbody数据生成逻辑 var getLeafColumns = function(data) { var columns = []; data.forEach(function(item) { if (item.SubColumns.length > 0) { columns = columns.concat(getLeafColumns(item.SubColumns)); } else { columns.push(item); } }); return columns; }; var leafColumns = getLeafColumns(jsonDATA); $scope.tbodyData = []; var totalRows = leafColumns[0].valor.length; for (var i = 0; i < totalRows; i++) { var currentRow = []; leafColumns.forEach(function(col) { currentRow.push(col.valor[i]); }); $scope.tbodyData.push(currentRow); } }]);
HTML部分
<!doctype html> <html ng-app="myapp"> <head> <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.js"></script> </head> <body> <div ng-controller="tableColSpanRowSpan"> <table border="1" cellspacing="2" cellpadding="3"> <thead> <tr data-ng-repeat="t in finalArrayHTML"> <th colspan="{{h.colSpan}}" rowspan="{{h.rowSpan}}" data-ng-repeat="h in t">{{h.title}}</th> </tr> </thead> <tbody> <tr data-ng-repeat="row in tbodyData"> <td data-ng-repeat="cell in row">{{cell}}</td> </tr> </tbody> </table> </div> </body> </html>
这样修改后,表头的合并单元格正常显示,tbody的每一行数据也会和表头的列一一对应,完美解决你的问题。
内容的提问来源于stack exchange,提问作者Douglas Teles
相关产品推荐
相关产品推荐

