Javascript 从 json 创建复杂的表头

Javascript Create complex table header from json

本文关键字:表头 复杂 创建 json Javascript      更新时间:2023-09-26

我想用colspan创建一个html表头,但我迷路了;我有这个 JSON:

var metadata = [{
"colIndex": 0,
    "colType": "String",
    "colName": "PM"
}, {
"colIndex": 1,
    "colType": "String",
    "colName": "PROD"
}, {
"colIndex": 2,
    "colType": "Numeric",
    "colName": "NR/M1"
}, {
"colIndex": 3,
    "colType": "Numeric",
    "colName": "NR/M2"
}, {
"colIndex": 4,
    "colType": "Numeric",
    "colName": "NR/M3"
}, {
"colIndex": 5,
    "colType": "Numeric",
    "colName": "NR/M4"
}, {
"colIndex": 6,
    "colType": "Numeric",
    "colName": "NR/M5"
}, {
"colIndex": 7,
    "colType": "Numeric",
    "colName": "NR ART/M6"
}, {
"colIndex": 8,
    "colType": "Numeric",
    "colName": "NR ART/M1"
}, {
"colIndex": 9,
    "colType": "Numeric",
    "colName": "NR ART/M2"
}, {
"colIndex": 10,
    "colType": "Numeric",
    "colName": "NR ART/M3"
}, {
"colIndex": 11,
    "colType": "Numeric",
    "colName": "NR ART/MX"
}];

表头将主要基于拆分"colType":"Numeric"

+------+-------+-----+--------+-----+-----+-----+-----+------+----+----+----+
|      |       |               NR               |           NR ART          |
+ PAM  | PROD  +-----+--------+-----+-----+-----+-----+------+----+----+----+
|              | M1   | M2    | M3  | M4  | M5  | M6  | M1  | M2  | M3 | MX |
+------+-------+-----+--------+-----+-----+-----+-----+------+----+----+----+

首先,我尝试拆分 colName,其中 colType 是数字

var arr = [], a;
$.each(metadata, function (i, v) {
  arr.push(v.colName.split("/"));
  a = v.colName.split("/").length;
});

接下来,我得到了独特的父母(?),但我能用这个做什么?我想我必须在层次结构中遍历这个数组(父级 - 子级,然后构造 HTML 标头)。

数组是动态的。

有什么建议吗?请,谢谢。

下面的代码应该可以完成工作请检查

var arr = {}, a;
$.each(metadata, function (i, v) {
     arr[v.colName.split("/")[0]] = arr[v.colName.split("/")[0]].push(v.colName.split("/")[1]) || [] ;       
});

为了显示它

for(t1 in arr){
    if(t1.length > 0){
          //has children element
    }
    else{
        //has only 1 element
    }
}

使这复杂化的一件事是,您的表格需要colspanrowspan。因此,您需要根据 colName 属性对对象进行组计数。

这是一个粗略的例子,说明你如何做到这一点。解释在代码注释中。(此示例对colspan使用组计数,但rowspan是硬编码的。您也可以对rowspan进行组计数)。

在这个例子中,我只使用jQuery来创建和添加表。核心逻辑是普通的Javascript

片段

var metadata = [{"colIndex": 0, "colType": "String", "colName": "PM"}, {"colIndex": 1, "colType": "String", "colName": "PROD"}, {"colIndex": 2, "colType": "Numeric", "colName": "NR/M1"}, {"colIndex": 3, "colType": "Numeric", "colName": "NR/M2"}, {"colIndex": 4, "colType": "Numeric", "colName": "NR/M3"}, {"colIndex": 5, "colType": "Numeric", "colName": "NR/M4"}, {"colIndex": 6, "colType": "Numeric", "colName": "NR/M5"}, {"colIndex": 7, "colType": "Numeric",    "colName": "NR ART/M6"}, {"colIndex": 8, "colType": "Numeric", "colName": "NR ART/M1"}, {"colIndex": 9, "colType": "Numeric", "colName": "NR ART/M2"}, {"colIndex": 10, "colType": "Numeric", "colName": "NR ART/M3"}, {"colIndex": 11, "colType": "Numeric", "colName": "NR ART/MX"}];
// First filtering objects which will form the headers
var rowHeaders = metadata.filter(function(obj) { return obj.colType == "String"; });
var colHeaders = metadata.filter(function(obj) { return obj.colType == "Numeric"; });
// Now we need the grouping on colName with value before slash.
// These will form the group header. Count will determine the colspan.
var colHeadersMain = {};
metadata.forEach(function(obj) { 
    if (obj.colType == "String") { return } // Only for Numeric colType
    // Check if the key has been stored in the colHeadersMain
    if (obj.colName.split('/')[0] in colHeadersMain) {
        // If yes, then increment the value of the key for object colHeadersMain
        colHeadersMain[obj.colName.split('/')[0]]++;
    } else {
        // If not, reset the value
        colHeadersMain[obj.colName.split('/')[0]] = 1;
    }
});
// Variables to hold jQuery elements
var $table = $("<table>"), $thead = $("<thead>"), 
    $row1 = $("<tr>"), $row2 = $("<tr>");
// Iterate row headers and form the first row
// Hard-coding the rowspan. 
// ToDo: Maintain count, similar to column headers.
rowHeaders.forEach(function(obj, idx) {
    var $th = $("<th rowspan='2'>");
    $th.text(obj.colName);
    $row1.append($th);
});
// Iterate col grouping headers and continue the row
// colpsan is the group count that we created earlier
for (var key in colHeadersMain) {
    var $th = $("<th colspan='" + colHeadersMain[key] + "'>");
    $th.text(key);
    $row1.append($th);    
}
// Add the first header row to thead
$thead.append($row1); 
// Iterate next line of col headers 
colHeaders.forEach(function(obj, idx) {
    var $th = $("<th>");
    $th.text(obj.colName.split('/')[1]);
    $row2.append($th);    
});
// Add to the thead
$thead.append($row2); 
// Add to the table
$table.append($thead);
// Add to the page / element
$("#wrap").append($table);
// Done.
table, td, th { border: 1px solid gray; border-collapse: collapse; }
th, td { padding: 4px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="wrap"></div>

由于您没有在帖子中标记jQuery,因此这里有一个普通的JavaScript解决方案(尽管您确实在帖子的代码中使用了$,这可能表示jQuery)。

下面的代码在应用于metadata时会将其解析为更有利于您想要执行的操作的格式:

var columns = [];
metadata.forEach(function(column, index, array) { // parse into a more friendly format for making columns
    var col = {}, // will be the column
        parts = column.colName.split('/'), // you're splitting on the column name in your post
        match = null, // for lookup, leaving null for falsy test later
        i = 0; // iterator / index
    col.name = parts[0]; // store the name
    col.type = column.colType; // and type
    col.index = column.colIndex; // and index, if you want to use it later
    col.subColumns = []; // make an empty array for any subcolumns that may exist so we can concat later
    if (parts.length > 1) {
        col.subColumns.push({ // subcolumn, push it into the array
            "name": parts[1],
            "index": col.index
        });
    }
    for (i = 0; i < columns.length; i += 1) {
        if (columns[i].name === col.name) { // [parent] column already exists
            match = i; // store the index
            break; // exit the loop
        }
    }
    if (match) { // index found
        columns[i].subColumns = columns[i].subColumns.concat(col.subColumns); // concat the subcolumns
    } else {
        columns.push(col); // did not exist, add it to the array
    }
});

完成此操作后,遍历columns变量两次以创建两行(假设 theadtrth 元素的变量)。

columns.forEach(function(column, index, array) { // loop through once to make "parent" headers
    th = document.createElement('th'); // create th element
    th.colSpan = column.subColumns.length; // set a colSpan as necessary
    if (!column.subColumns.length) { //  if there are no subcolumns, make the header span two rows
        th.rowSpan = 2;
    }
    th.innerText = column.name; // set the header text
    tr.appendChild(th); // add to row
});
columns.forEach(function(column, index, array) { // loop through a second time to get the child headers
    column.subColumns.forEach(function(subColumn, index, array) { // loop through the child headers
        th = document.createElement('th'); // create th
        th.innerText = subColumn.name; // set the header text
        tr.appendChild(th); // add to row
    });
});

这是在行动:

var metadata = [{
        "colIndex": 0,
        "colType": "String",
        "colName": "PM"
    }, {
        "colIndex": 1,
        "colType": "String",
        "colName": "PROD"
    }, {
        "colIndex": 2,
        "colType": "Numeric",
        "colName": "NR/M1"
    }, {
        "colIndex": 3,
        "colType": "Numeric",
        "colName": "NR/M2"
    }, {
        "colIndex": 4,
        "colType": "Numeric",
        "colName": "NR/M3"
    }, {
        "colIndex": 5,
        "colType": "Numeric",
        "colName": "NR/M4"
    }, {
        "colIndex": 6,
        "colType": "Numeric",
        "colName": "NR/M5"
    }, {
        "colIndex": 7,
        "colType": "Numeric",
        "colName": "NR ART/M6"
    }, {
        "colIndex": 8,
        "colType": "Numeric",
        "colName": "NR ART/M1"
    }, {
        "colIndex": 9,
        "colType": "Numeric",
        "colName": "NR ART/M2"
    }, {
        "colIndex": 10,
        "colType": "Numeric",
        "colName": "NR ART/M3"
    }, {
        "colIndex": 11,
        "colType": "Numeric",
        "colName": "NR ART/MX"
    }],
    columns = [],
    thead = document.getElementById('dynamic'), // cache this DOM lookup
    tr = document.createElement('tr'),
    th; // placeholder for th elements that will be created
metadata.forEach(function(column, index, array) { // parse into a more friendly format for making columns
    var col = {}, // will be the column
        parts = column.colName.split('/'), // you're splitting on the column name in your post
        match = null, // for lookup, leaving null for falsy test later
        i = 0; // iterator / index
    col.name = parts[0]; // store the name
    col.type = column.colType; // and type
    col.index = column.colIndex; // and index, if you want to use it later
    col.subColumns = []; // make an empty array for any subcolumns that may exist so we can concat later
    if (parts.length > 1) {
        col.subColumns.push({ // subcolumn, push it into the array
            "name": parts[1],
            "index": col.index
        });
    }
    for (i = 0; i < columns.length; i += 1) {
        if (columns[i].name === col.name) { // [parent] column already exists
            match = i; // store the index
            break; // exit the loop
        }
    }
    if (match) { // index found
        columns[i].subColumns = columns[i].subColumns.concat(col.subColumns); // concat the subcolumns
    } else {
        columns.push(col); // did not exist, add it to the array
    }
});
columns.forEach(function(column, index, array) { // loop through once to make "parent" headers
    th = document.createElement('th'); // create th element
    th.colSpan = column.subColumns.length; // set a colSpan as necessary
    if (!column.subColumns.length) { //  if there are no subcolumns, make the header span two rows
        th.rowSpan = 2;
    }
    th.innerText = column.name; // set the header text
    tr.appendChild(th); // add to row
});
thead.appendChild(tr); // add row to thead
tr = document.createElement('tr'); // reset row
columns.forEach(function(column, index, array) { // loop through a second time to get the child headers
    column.subColumns.forEach(function(subColumn, index, array) { // loop through the child headers
        th = document.createElement('th'); // create th
        th.innerText = subColumn.name; // set the header text
        tr.appendChild(th); // add to row
    });
});
thead.appendChild(tr); // add row to thead
th {border: 1px solid black;}
<table>
    <thead id="dynamic"></thead>
</table>

jQuery,如果你使用它,可以使这个语法更"含糖"(主要是在制作行和标题单元格时,见下文),但原理是相同的。

columns.forEach(function(column, index, array) { // loop through once to make "parent" headers
    th.clone().attr({
        "colSpan": column.subColumns.length,
        "rowSpan": column.subColumns.length === 0 ? 2 : 1
    }).text(column.name).appendTo(tr);
});
tr.appendTo(thead);
tr = $('<tr />');
columns.forEach(function(column, index, array) { // loop through a second time to get the child headers
    column.subColumns.forEach(function(subColumn, index, array) { // loop through the child headers
        th.clone().text(subColumn.name).appendTo(tr);
    });
});
tr.appendTo(thead);

几个小时后,我找到了问题的答案。在第一部分中,我创建了 tr 和 th(th non Unique)

var a = [], l = 0;
for (var i = 0; i < metadata.length; i++) {
   var d = {
    "colName": metadata[i].colName.split("/"),
        "colType": metadata[i].colType
   };
   a.push(d);
   if (metadata[i].colType == "Numeric") {
      trl = metadata[i].colName.split("/").length;
   }
}
for (var l = 0; l < trl; l++) {
   var tr = $("<tr/>").appendTo("thead");
}
for (var j = 0; j < a.length; j++) {
   if (a[j].colType == "String") {
     $("<th/>").addClass("string").attr("rowspan", l).html(a[j].colName).appendTo("thead tr:nth(0)");
   } else {
      for (var k = 0; k < a[j].colName.length; k++) {
          $("<th/>").addClass("numeric").html(a[j].colName[k]).appendTo("thead tr:nth(" + k + ")");
      }
  }
}

这部分改编自这里。现在我清理桌子头,生活只是独特的th。

$('table tr').each(function () {
  var tr = this;
  var counter = 0;
  var strLookupText = '';
  $('th.numeric', tr).each(function (index, value) {
    var td = $(this);
    if ((td.text() == strLookupText) || (td.text() == "")) {
        counter++;
        td.prev().attr('colspan', '' + parseInt(counter + 1, 10) + '').css({
            textAlign: 'center'
        });
        td.remove();
    } else {
        counter = 0;
    }
    strLookupText = td.text();
   });
});

代码有点乱,但已经晚了。