Javascript 从 json 创建复杂的表头
Javascript Create complex table header from json
我想用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
}
}
使这复杂化的一件事是,您的表格需要colspan
和rowspan
。因此,您需要根据 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
变量两次以创建两行(假设 thead
、tr
和 th
元素的变量)。
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();
});
});
代码有点乱,但已经晚了。
- 在Redux中,我应该在哪里编写复杂的异步流
- 将复杂对象从angular js传递到web api,它总是返回404
- dropdown.js中的复杂事件处理
- 您有更好的动态方式来缩短复杂的代码jquery吗
- 相当复杂的Regex
- 用Javascript重新格式化复杂文本日期字符串的更好方法
- ui网格:在自定义表头模板中触发排序
- 加速我的复杂函数绘图仪(canvas+javascript)
- JQuery Mobile Javascript复杂方程式
- 修复了使用Jquery的列(表头问题)
- 如何使用javascript过滤复杂的json对象
- 复杂量角器选择器
- "改变“;列表头,然后继续处理列表
- JavaScript中的复杂字符串匹配
- 有关PouchDB的复杂startkey/endkey查询未返回预期结果
- 复杂的javascript函数,我该如何使用它
- 在给定 javascript 中的表头的情况下生成 TSV 文件
- TinyMCE:添加复杂格式
- 如何使用原型继承编写一个整洁灵活的复杂javascript应用程序
- Javascript 从 json 创建复杂的表头