我有一个像下面的JSON对象,我正在使用下面的包装函数将JSON转换为HTML
从JSON检索的部分:
var data = { "Column Headers" : [ // Hierarchy is not limited to two levels, it is n level
[ "Column1" , ["Column1's SubColumn 1", "Column1's SubColumn 2"] ],
[ "Column2" , ["Column2's SubColumn 1", "Column1's SubColumn 2"] ],
[ "Column3" , ["Column3's SubColumn 1", "Column1's SubColumn 2"] ]
],
"Columns under subColumns" : ["I am column 1", "I am column 2"],
"Data for Table" :[
{ "name": ["Group 1","Sub Group 1"], "data" : [[0,1],[1,2],[45,20],[0,1],[1,2],[45,20]]},
{ "name": ["Group 1","Sub Group 2"], "data" : [[0,1],[1,2],[45,20],[0,1],[1,2],[45,20]]},
{ "name": ["Group 2","Sub Group 1"], "data" : [[0,1],[1,2],[45,20],[0,1],[1,2],[45,20]]},
{ "name": ["Group 2","Sub Group 2"], "data" : [[0,1],[1,2],[45,20],[0,1],[1,2],[45,20]]}
], // here the hierarchy is not limited to two sub groups.. it could be any number..
"row group headers" : ["Group 1 Header", "Sub group Header"]
}
Run Code Online (Sandbox Code Playgroud)
它应该编译成HTML,就像在这个小提琴http://jsfiddle.net/RwdWq/
这是我写的代码
var render = function(data){
var formattedData = {};
function returnRowsData( obj ) {
return obj["Data for Table"];
}
function returnColsData(obj) {
return obj["Column Headers"];
}
function rowLabels(obj) {
return obj["row group headers"];
}
function bottomColLabels(obj) {
return obj["Columns under subColumns"];
}
function simplifyCols(obj) {
var reform = {
table : {}
}, bottomLabs = bottomColLabels(data);
var y = 0;
for(var i = 0, l = obj.length; i < l; i++){
var key = obj[i];
key.push(bottomLabs);
for (var j = 0, m = key.length; j < m; j++) {
var colspan = 1;
for (var k = j + 1; k < m; k++) {
colspan *= key[k].length;
}
reform.table[j] = reform.table[j] || [];
if (j == 0) {
y += colspan;
}
reform.table[j].push({
span : colspan,
data : key[j]
});
}
}
reform.count = y;
return reform;
}
var formatted = simplifyCols( returnColsData( data[0]) ) || {};
var cols = formatted.table;
//console.log(cols);
formattedData.cols = cols;
var keys = Object.keys(cols).sort(function(a, b){
return a - b;
});
var table = document.createElement('table');
for (var i = 0, l = keys.length - 1; i < l; i++) {
var keyData = cols[keys[i]], tr = document.createElement('tr');
if (i == 0) {
var rLs = rowLabels(data[0]);
for (var rL = 0; rL < rLs.length; rL++) {
var td = document.createElement('th');
td.innerHTML = rLs[rL];
td.rowSpan = keys.length;
td.className = "rowLabel";
tr.appendChild(td);
}
}
table.appendChild(tr);
for (var j = 0, m = keyData.length; j < m; j++) {
var eleData = keyData[j].data;
if(eleData instanceof Array){
for (var k = 0, n = eleData.length; k < n; k++) {
var td = document.createElement('td');
td.innerHTML = eleData[k];
td.colSpan = keyData[j].span;
td.className = "colHeaders";
tr.appendChild(td);
}
}else{
var td = document.createElement('td');
td.innerHTML = keyData[j].data;
td.colSpan = keyData[j].span;
td.className = "colHeaders";
tr.appendChild(td);
}
}
table.appendChild(tr);
}
var tr = document.createElement('tr');
var noOfbottomLabs = formatted.count ? formatted.count / bottomLabs.length : bottomLabs.length;
for (var i = 1; i <= noOfbottomLabs; i++) {
for (var j = 0; j < bottomLabs.length; j++) {
var td = document.createElement('td');
td.innerHTML = bottomLabs[j];
td.className = "bottomLabs";
tr.appendChild(td);
}
}
table.appendChild(tr);
function setToValue(obj, value, path) {
var parent = obj;
for (var i = 0; i < path.length - 1; i += 1) {
parent[path[i]] = parent[path[i]] || {}
parent = parent[path[i]];
}
parent[path[path.length-1]] = value;
}
var rowsData = returnRowsData(data), tempRows = {}, tempArr = {};
for (var i = 0, l = rowsData.length; i < l ; i++) {
var names = rowsData[i].name, _data = rowsData[i].data;
setToValue(tempRows, _data, names);
}
var similiar = {};
for (var ele = 0, lent = rowsData.length; ele < lent; ele++) {
var curD = rowsData[ele], tr = document.createElement('tr');
for (var i = 0; i < curD.name.length; i++) {
var td = document.createElement('td');
td.innerHTML = curD.name[i] || "-";
td.setAttribute('val', curD.name[i]);
td.className = "rowHeader";
similiar[curD.name[i]] = 0;
tr.appendChild(td);
}
var merg = [];
merg = [].concat.apply( merg, curD.data);
for (var i = 0; i < merg.length; i++) {
var td = document.createElement('td');
td.innerHTML = merg[i] || "-";
td.className = "tdData";
tr.appendChild(td);
}
table.appendChild(tr);
console.log(merg);
}
document.body.appendChild(table);
for (var text in similiar) {
var elements = document.querySelectorAll('[val="' + text + '"]');
elements[0].rowSpan = elements.length;
for (var j = 1; j < elements.length; j++) {
var v = elements[j];
v.parentNode.removeChild(v);
}
}
}
Run Code Online (Sandbox Code Playgroud)
目前它正在像这样工作http://jsfiddle.net/RwdWq/3/
如果数据很大,我怎样才能解决这个问题,并且页面有时会死掉.帮助我提高性能,我想检查没有表格的可能性.
Ent*_*ack 15
我知道如何解决你的问题.还有一个解决方案.你的代码很长,我的所有解决方案都要求重写你写的几乎所有东西,所以我会把这里最重要的部分放在这里.首先是第一个.
你的json结构很糟糕.我建议你改一点.这是我的:
编辑:正如Bergi所说,我的结构没有精确定义标题中单元格的顺序.你的这种方式更好.
var data = {
"Column Headers" : {
"Column1" : {
"Column1's SubColumn 1" : ["I am column 1", "I am column 2"],
"Column1's SubColumn 2" : ["I am column 1", "I am column 2"]
},
"Column2" : {
"Column2's SubColumn 1": ["I am column 1", "I am column 2"],
"Column2's SubColumn 2" : ["I am column 1", "I am column 2"]
},
"Column3" : {
"Column3's SubColumn 1": ["I am column 1", "I am column 2"],
"Column3's SubColumn 2": ["I am column 1", "I am column 2"]
}
},
"Row Headers" : {
"Column1" : ["Column1's SubColumn 1", "Column1's SubColumn 2"],
"Column2" : ["Column2's SubColumn 1", "Column1's SubColumn 2"],
"Column3" : ["Column3's SubColumn 1", "Column1's SubColumn 2"]
},
"Data for Table" : [
[0, 1, 1, 2, 45, 20, 0, 1, 1, 2, 45, 20],
[0, 1, 1, 2, 45, 20, 0, 1, 1, 2, 45, 20],
[0, 1, 1, 2, 45, 20, 0, 1, 1, 2, 45, 20],
[0, 1, 1, 2, 45, 20, 0, 1, 1, 2, 45, 20]
]
}
Run Code Online (Sandbox Code Playgroud)
它仍然不完美,但至少它是人类可读的.
2. Json解析算法
你开始使用一些函数渲染,它可能是imho命名空间或构造函数.然后你创建了很多小函数,然后将它们放在算法的各个部分之后.
尝试将算法拆分为更多函数,并将每个函数设置为一些主要点:
function parseJson() { ... }
function parseHeader() { ... }
function parseRows() { ... }
function renderColumnsHeaders() { ... }
function renderRow() { ... }
Run Code Online (Sandbox Code Playgroud)
你也可以把它作为一个对象.然后,您可以轻松添加各种功能,如排序,过滤或其他东西.
var MyDataTable = (function () { // this is namespace
var MyDataTable = function(json) { // this is object constructor, it will probably just loads data
this.data = json;
}
// these functions are visible only inside namespace
function parseJson() { ... }
function parseHeader() { ... }
function parseRows() { ... }
function renderColumnsHeaders() { ... }
function renderRow() { ... }
MyDataTable.prototype.renderTable = function (where) { ... } // this will render whole table
MyDataTable.prototype.filterTableBy = function () { ... } // filter that you can implement later
return MyDataTable; // returns constructor
})();
var data = { ... } // some data
var firstTable = new MyDataTable(data);
firstTable.renderTable(someDivOrAnyElementYouWant);
Run Code Online (Sandbox Code Playgroud)
这样的代码是almoast profi;)易于维护,易于扩展,易于从中插件;)
3.提高表呈现性能
为什么表格渲染这么慢?嗯,这可能是不是因为表的,但因为大的HTML,您正试图在包括一次.如果你使用javascript来制作DOM元素,或者你将DOM元素直接写入html,这无关紧要.如果有很多元素,渲染它总是需要一段时间.
不幸的是,html渲染是同步的.这意味着一切都被冻结,直到你的功能没有完成.它不像动画或ajax那样工作(它被称为'异步JavaScript和XML'用于共振).
您拥有的第一个选项是逐步使用ajax和load table.设置一次可以加载的行数限制.然后:*调用ajax*从ajax获取json*解析它*获取行并渲染它们*重复然后你的浏览器不会冻结.渲染仍然是同步的,但两个渲染调用之间会有"窗口",所以这里会完成各种事件和其他事情.简单地说,很多短尖峰不会像一个长尖峰一样冻结你的浏览器.
另一种选择是根据用户位置加载数据.用户无法一次查看所有数据.这与第一个选项非常相似,它被称为"无限滚动".你可能已经在facebook上看到了谷歌图片...这里有jquery插件.
最后一个选项是使用setInterval或setTimeout本机javascript函数.除了你不使用ajax之外,这种技术也适用于许多较短的尖峰.您首先在JavaScript中加载所有数据.然后使用这些函数逐步渲染它们.由于这些函数是异步的,因此效果很好.但它需要更深入的了解.我有异步调用的例子.有些div会像彩虹那样改变颜色,但它不是动画:http:
//windkiller.g6.cz/async/async-html-render.html
编辑:
可靠性使它没有桌子
可以使用div元素或者某些列表而不是表格.我不推荐它.这里有大数据表,浏览器开发人员正在尽最大努力提高表的性能.也许你听过或读过一些表格很慢的猜测.它们很慢,但这些时间都消失了.所以在这种情况下坚持使用表格.
小智 3
这是我的基于 jQuery 的解决方案:
<!DOCTYPE html>
<html>
<head>
<title>json2html</title>
<style>
#target { display: none }
td { text-align: center; border: 1px solid gray; }
.colHeaders { }
.rowLabel { }
.bottomLabs { }
.rowHeader { }
.tdData { }
</style>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<script type="text/javascript">
var json2html = (function () {
var json2html = function(json) {
this.data = json;
this.rgh = json["row group headers"];
this.ch = json["Column Headers"];
this.dft = json["Data for Table"];
this.cus = json["Columns under subColumns"];
this.sc = this.cus.length;
var depth = 0;
for (var i in this.ch) {
depth = Math.max(depth, this.ch[i].length);
}
this.depth = depth;
}
function repeat(pattern, count) {
var result = pattern;
while (--count > 0) {
result += pattern;
}
return result;
}
function join(data, td) {
try {
return td + data.join('</td>' + td) + '</td>';
} catch (e) {
return td + data + '</td>';
}
}
function renderSubHeader(data, index, sc) {
var html = '';
$.each(data, function() {
var cs = sc;
for (var i = index + 1; i < this.length; i++) {
cs *= this[i].length;
}
var value = (typeof this[index] != 'undefined') ? this[index] : '';
var cell = join(value, '<td class="colHeaders"' + ((cs > 1) ? ' colspan="'+cs+'">' : '>'));
if (index > 1) {
for (var i = index - 1; i > 0; i--) {
html += repeat(cell, this[i].length);
}
} else {
html += cell;
}
});
return(html);
}
function renderHeader(data) {
var html = '<tr>';
html += join(data.rgh, '<th rowspan="'+(data.depth + 1)+'" class="rowLabel">');
html += renderSubHeader(data.ch, 0, data.sc);
html += '</tr>';
for (var index = 1; index < data.depth; index++) {
html += '<tr>';
html += renderSubHeader(data.ch, index, data.sc);
html += '</tr>';
};
return html;
}
function renderColHeader(data) {
var html = '<tr>';
$.each(data.dft[0].data, function(index) {
html += join(data.cus, '<td class="bottomLabs">');
});
return html+'</tr>';
}
function renderData(data) {
var html = '';
$.each(data.dft, function(nr) {
html += '<tr>';
html += join(this.name, '<td class="rowHeader">');
$.each(this.data, function() {
html += join(this, '<td class="tdData">');
});
html += '</tr>';
});
return html;
}
function mergeCells(cells, attr) {
var rs = 1;
var old = null;
cells.each(function() {
if (old == null) {
old = $(this);
rs = 1;
} else {
if ($(this).text() == old.text()) {
rs++;
$(this).remove();
} else {
if (rs > 1) {
old.attr(attr, rs);
rs = 1;
}
old = $(this);
}
}
});
if (rs > 1) {
old.attr(attr, rs);
}
}
json2html.prototype.renderTable = function(thead, tbody) {
var startTime = new Date();
thead.html(
renderHeader(this) +
renderColHeader(this)
);
tbody.html(renderData(this));
for (var i = this.rgh.length; i > 0; i--) {
mergeCells($('td:nth-child('+i+')', tbody), 'rowspan');
};
var endTime = new Date();
console.log('renderTable('+this.dft.length+' rows): ' + (endTime - startTime) + 'ms');
}
return json2html;
})();
//==================================================================================================
var data1 = {
"Column Headers": [
["Column1", ["Column1's SubColumn 1", "Column1's SubColumn 2"] ],
["Column2", ["Column2's SubColumn 1", "Column1's SubColumn 2"] ],
["Column3", ["Column3's SubColumn 1", "Column1's SubColumn 2"] ]
],
"Columns under subColumns": [
"I am column 1",
"I am column 2"
],
"Data for Table": [
{ "name": ["Group 1","Sub Group 1"], "data": [[0,1],[1,2],[45,20],[0,1],[1,2],[45,20]] },
{ "name": ["Group 1","Sub Group 2"], "data": [[0,1],[1,2],[45,20],[0,1],[1,2],[45,20]] },
{ "name": ["Group 1","Sub Group 2"], "data": [[0,1],[1,2],[45,20],[0,1],[1,2],[45,20]] },
{ "name": ["Group 1","Sub Group 2"], "data": [[0,1],[1,2],[45,20],[0,1],[1,2],[45,20]] },
{ "name": ["Group 2","Sub Group 1"], "data": [[0,1],[1,2],[45,20],[0,1],[1,2],[45,20]] },
{ "name": ["Group 2","Sub Group 2"], "data": [[0,1],[1,2],[45,20],[0,1],[1,2],[45,20]] }
],
"row group headers": [
"Group 1 Header",
"Sub group Header"
]
};
var data2 = {
"Column Headers" : [
[ "Column1", ["Column1's SubColumn 1", "Column1's SubColumn 2", "Column1's SubColumn 3"], ["abc", "Hello1"] ],
[ "Column2", ["Column2's SubColumn 1", "Column2's SubColumn 2", "Column2's SubColumn 3"], ["def", "Hello2"] ],
[ "Column3", ["Column3's SubColumn 1", "Column3's SubColumn 2", "Column3's SubColumn 3"], ["ghi", "Hello3"] ]
],
"Columns under subColumns": [
"I am column 1",
"I am column 2"
],
"Data for Table": [
{ "name": ["Group 1","Sub Group 1", "abc"], "data": [[0,1],[1,2],[45,20],[0, 1],[1,2],[45,20],[0,1],[1,2],[45,20],[0, 1],[1,2],[45,20],[0,1],[1,2],[45,20],[0, 1],[1,2],[45,20]] },
{ "name": ["Group 1","Sub Group 1", "def"], "data": [[0,1],[1,2],[45,20],[0, 1],[1,2],[45,20],[0,1],[1,2],[45,20],[0, 1],[1,2],[45,20],[0,1],[1,2],[45,20],[0, 1],[1,2],[45,20]] },
{ "name": ["Group 2","Sub Group 1", "ghi"], "data": [[0,1],[1,2],[45,20],[0, 1],[1,2],[45,20],[0,1],[1,2],[45,20],[0, 1],[1,2],[45,20],[0,1],[1,2],[45,20],[0, 1],[1,2],[45,20]] },
{ "name": ["Group 2","Sub Group 2", "jkl"], "data": [[0,1],[1,2],[45,20],[0,86],[1,2],[45,20],[0,1],[1,2],[45,20],[0,86],[1,2],[45,20],[0,1],[1,2],[45,20],[0,86],[1,2],[45,20]] }
],
"row group headers": [
"Group 1 Header",
"Sub group Header",
"abc"
]
};
var data3 = {
"Column Headers" : [
[ "Column1", ["Column1's SubColumn 1", "Column1's SubColumn 2", "Column1's SubColumn 3"], ["abc", "Hello1"] ],
[ "Column2", ["Column2's SubColumn 1", "Column2's SubColumn 2", "Column2's SubColumn 3"] ],
[ "Column3", ["Column3's SubColumn 1", "Column3's SubColumn 2", "Column3's SubColumn 3"], ["ghi"] ]
],
"Columns under subColumns": [
"I am column 1",
"I am column 2"
],
"Data for Table": [
{ "name": ["Group 1"], "data": [[0,1],[1,2],[45,20],[0, 1],[1,2],[45,20],[0,1],[1,2],[45,20],[0, 1],[1,2],[45,20]] },
{ "name": ["Group 1"], "data": [[0,1],[1,2],[45,20],[0, 1],[1,2],[45,20],[0,1],[1,2],[45,20],[0, 1],[1,2],[45,20]] },
{ "name": ["Group 2"], "data": [[0,1],[1,2],[45,20],[0, 1],[1,2],[45,20],[0,1],[1,2],[45,20],[0, 1],[1,2],[45,20]] },
{ "name": ["Group 2"], "data": [[0,1],[1,2],[45,20],[0,86],[1,2],[45,20],[0,1],[1,2],[45,20],[0,86],[1,2],[45,20]] }
],
"row group headers": [
"Group 1 Header",
]
};
$(function () {
var data = [data1, data2, data3];
$('#dataset').change(function() {
$('#target').hide();
if (this.value != '') {
$('#target thead').empty();
$('#target tbody').empty();
var html = new json2html(data[this.value]);
html.renderTable($('#target thead'), $('#target tbody'));
$('#target').fadeIn('slow');
}
});
});
</script>
</head>
<body>
<label for="dataset">Choose a dataset</label>
<select id="dataset">
<option value=""></option>
<option value="0">Data 1</option>
<option value="1">Data 2</option>
<option value="2">Data 3</option>
</select>
<table id="target">
<thead>
</thead>
<tbody>
</tbody>
</table>
</body>
Run Code Online (Sandbox Code Playgroud)
JS在这里摆弄。