我有一个类似下面的对象:
var obj = {
a : {
x : 1,
y : 2,
z : 3
},
b : {
x : 1,
y : 2,
z : 3
}
}
有了它,我想生成下表。格式如下所示
我正在尝试从对象获取元素并尝试追加但与rowSpan值混淆
var tr = document.createElement('tr');
for(var i in obj){
var td = document.createElement('td');
td.rowSpan = ? // Here I am getting confused.
}
模板引擎可以解决我的问题吗? 做这个的最好方式是什么?
答案 0 :(得分:4)
这是使用纯js中的递归函数执行此操作的一种方法:
function addObjectToTable(table, obj, tr) {
var rows = 0;
for (key in obj) {
if (tr == null) {
tr = document.createElement('tr');
table.appendChild(tr);
}
var td = document.createElement('td');
td.textContent = key;
tr.appendChild(td);
var value = obj[key];
if (typeof value != 'object') {
var td = document.createElement('td');
td.textContent = value;
tr.appendChild(td);
rows += 1;
}
else {
var subrows = addObjectToTable(table, value, tr);
td.setAttribute('rowspan',subrows);
rows += subrows;
}
tr = null;
}
return rows;
}
这将被称为:
var table = document.createElement('table');
addObjectToTable(table,obj);
document.body.appendChild(table);
请注意,首次调用时, tr 参数为null,因为我们始终必须在顶层创建一个新行。当递归调用函数时, tr 参数从上层传入,因为较低级别最初会添加到其父对象的行中。
该函数返回添加的行数,因此当重新调用它时,调用者将知道将 rowspan 值设置为的内容。
答案 1 :(得分:3)
我找不到处理循环的答案,我也决定在没有任何不必要的DOM写入的情况下这样做。此外,我没有按照OP请求的确切标记,因为我觉得嵌套表对于像这样的递归操作更方便 - 并且提供接近相同的视觉目的。
所以,这是我创建的函数:
function dataToTable (data) {
var storage = [];
return (function buildTable (data) {
var table = '<table><tbody>';
var name, value;
// Add the object/array to storage for cirular detection.
storage.push(data);
for (name in data) {
value = data[name];
table += '<tr><td>' + name + '</td><td>';
// If the value is an object we've put in storage (circular)
if (storage.indexOf(value) !== -1) {
table += '<em>Circular</em>';
} else if (typeof value === 'object') {
table += buildTable(value);
} else {
table += value;
}
table += '</td></tr>';
}
return table + '</tbody></table>';
}(data));
}
以下是我用来测试的对象:
var obj = {
a : {
x : 1,
y : 2,
z : 3
},
b : {
x : 1,
y : 2,
z : {
test1: 0,
test2: {
test3: 1,
test4: ['a','b','c']
}
}
}
};
obj.c = obj;
obj.b.z.test2.test4.push(obj.a);
该函数将此对象转换为HTML表。你用桌子做什么取决于你。在我的小提琴上,我使用DOM将表添加到DIV(document.getElementById)。
我希望你能清楚地看到我的实施。
UPDATE ::
我决定在jQuery库上测试它,它工作正常!除了,函数打印为toString值没有良好的文本格式..这是有道理的,但不是很有帮助。所以,我认为这是一个很好的,简单的方法来查看框架/库的API和什么不是。因此,我为函数的语法高亮添加了美化,并在表生成器中添加了函数的类型检查,以及快速类来摆脱美化框周围的边框(因为表格单元格上已经有边框) 。如果有人对为源读/调试设计的版本感兴趣,那么这就是小提琴:
答案 2 :(得分:2)
更新:如果你不需要空单元格解决方案可以(查看小提琴http://jsfiddle.net/gD87t/11/)
示例对象:
var obj = {
a : {
x : 1,
y : 2,
z : {
c : 4,
d : 5
}
},
b : {
x : 1,
y : 2,
z : 3
}
}
构建表的例程:
function merge(rows , inner) {
inner.reduce(function (i, p) {
rows.push(i)
})
}
function getRows(o) {
var rows = []
if (typeof o == 'object') {
for (var k in o) {
var innerRows = getRows(o[k])
, firstCell = $('<td />')
.text(k)
.attr('rowspan',innerRows.length)
innerRows[0].prepend(firstCell)
rows = rows.concat(innerRows)
}
} else {
var tr = $('<tr />')
, td = $('<td />').text(o)
tr.append(td)
rows.push(tr)
}
return rows
}
function buildTable(o, $t) {
var rows = getRows(o)
$t.append(rows)
}
buildTable(obj, $('#table2'))
答案 3 :(得分:1)
rowspan
的值是内部对象中的属性数。您可以使用Object.keys
函数获取对象上的键列表,然后使用其length
属性来确定有多少属性:
for(var i in obj){
var td = document.createElement('td');
td.rowSpan = Object.keys(obj[i]).length;
}
答案 4 :(得分:1)
var table = document.createElement('table');
var i, j;
var row, cell;
for(i in obj) {
if(obj.hasOwnProperty(i)) {
var row = document.createElement('tr');
var cell = document.createElement('td');
cell.rowSpan = Object.keys(obj[i]).length;
cell.innerText = i;
row.appendChild(cell);
for(j in obj[i]) {
if(obj[i].hasOwnProperty(j)) {
cell = document.createElement('td');
cell.innerText = j;
row.appendChild(cell);
cell = document.createElement('td');
cell.innerText = obj[i][j];
row.appendChild(cell);
table.appendChild(row);
row = document.createElement('tr');
}
}
}
}
document.body.appendChild(table);
当然,它在jQuery中看起来不那么冗长。但看起来你想在普通的DOM中做到这一点。
答案 5 :(得分:0)
var obj = {
a : {
x : 1,
y : 2,
z : {c:1, d:3}
},
b : {
x : 1,
y : 2,
z : 3
}
}
var table = document.createElement('table');
function createTable (o, parentCells) {
for (var key in o) {
var row = document.createElement('tr');
var cell = document.createElement('td');
cell.rowSpan = 1;
cell.innerText = key;
if (typeof o[key] !== "object") {
var cellv = document.createElement('td');
cellv.innerText = o[key];
row.appendChild(cell);
row.appendChild(cellv);
table.appendChild(row);
}
else {
for (var i = 0; i < parentCells.length; i++) {
parentCells[i].rowSpan += Object.keys(o[key]).length;
}
cell.rowSpan += Object.keys(o[key]).length;
var newParentCells = new Array(parentCells);
newParentCells.push(cell);
row.appendChild(cell);
table.appendChild(row);
createTable(o[key], newParentCells);
}
}
}
createTable(obj, []);
document.body.appendChild(table);
答案 6 :(得分:0)
如果您希望像在问题中一样使用document.createElement
,最简单的方法可能是这样的:
function generateTable(o) {
var table, tr, td, i, j, l, keys;
table = document.createElement('table')
for(i in o){
tr = document.createElement('tr');
table.appendChild(tr);
td = document.createElement('td');
keys = Object.keys(o[i]);
td.rowSpan = keys.length;
td.textContent = i;
tr.appendChild(td);
x=0;
for(j=0;j<keys.length;j++) {
if(j) {
tr = document.createElement('tr');
table.appendChild(tr);
}
td = document.createElement('td');
td.textContent = keys[j];
tr.appendChild(td);
td = document.createElement('td');
td.textContent =o[i][keys[j]];
tr.appendChild(td);
}
}
return table;
}
CAVEAT:Object.keys
在旧浏览器中不可用,因此您需要这样的polyfill:
if (!Object.keys) {
Object.keys = (function () {
var hasOwnProperty = Object.prototype.hasOwnProperty,
hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
dontEnums = [
'toString',
'toLocaleString',
'valueOf',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'constructor'
],
dontEnumsLength = dontEnums.length;
return function (obj) {
if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) throw new TypeError('Object.keys called on non-object');
var result = [];
for (var prop in obj) {
if (hasOwnProperty.call(obj, prop)) result.push(prop);
}
if (hasDontEnumBug) {
for (var i=0; i < dontEnumsLength; i++) {
if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]);
}
}
return result;
};
})();
}
另外,有一个更简单的polyfill,可以很好地覆盖大多数情况:
(取自Token Posts)
if (!Object.keys) Object.keys = function(o) {
if (o !== Object(o))
throw new TypeError('Object.keys called on a non-object');
var k=[],p;
for (p in o) if (Object.prototype.hasOwnProperty.call(o,p)) k.push(p);
return k;
}
你可以在这里看到它的一个小提琴:http://jsfiddle.net/uyJv2/