javascript - 如何通过 JavaScript/jQuery 以编程方式创建不规则表格?
问题描述
有一个合并了一些行的excel,我们需要创建一个与它在excel中显示的布局相同的表,并用数据库中的数据填充。
布局如下所示:
我尝试使用以下代码:
for (let group of group_list) {
var table = document.createElement("table")
table.setAttribute("id","summaryTbl");
$('#main').append(table);
var row = table.insertRow(0);
row.insertCell(0).outerHTML = "<th>Column 1</th>";
row.insertCell(1).outerHTML = "<th>Column 2</th>";
row.insertCell(2).outerHTML = "<th>Column 3</th>";
row.insertCell(3).outerHTML = "<th>Column 4</th>";
$('#main').append('</thead>');
但不知何故,它总是显示“tbody”而不是“thead”:
除了以下代码:
var table = document.createElement("table")
table.setAttribute("id","summaryTbl");
var row = table.insertRow(0);
row.insertCell(0).outerHTML = "<th>Column 1</th>";
...
$('#summaryTbl tr:last').after('<tr><td>'+"Test 1"+'</td>');
...
$('#summaryTbl').append('<tr><td>'+ "Test 2"+'</td>');
有没有更好的方法来生成这样一个不规则的表格?使用一些 JavaScript 库还是仅仅通过 for-loop 和 if-else 条件?
解决方案
我已经看过您的帖子并尝试将其作为自己的练习,我不妨分享一下结果。不完全相同,因为在您的图片中,“1.1.1.1.x”填充到左侧,“2.3.x.1”比其他行小,我没有做这些棘手的案例。
const values = ["1.1.1.1.1", "1.1.1.1.2", "1.1.1.1.3", "1.1.1.1.4", "1.1.1.1.5", "1.2.1.1.1", "2.1.1.1.1", "2.2.1.1.1", "2.2.2.1.1", "2.2.3.1.1", "2.3.1.1", "2.3.2.1", "2.3.3.1", "2.3.4.1"]
// create a nested object from values
// 1.2.3 becomes {1:{2:{3:}}}
const transformedValues = (() => {
const output = {}
values.forEach(el => {
let tmp = output
el.split(".").forEach(val => {
if (!tmp[val]) {
tmp[val] = {}
}
tmp = tmp[val]
})
})
return output
})()
// find the object max depth, for the column count
const maxDepth = (function rec(obj, depth = 0){
return Math.max(depth, ...Object.values(obj).map(val => rec(val, depth + 1)))
})(transformedValues)
// header name generator (more than 26 and you'll go into non alphanumeric)
let headerASCII = "A".charCodeAt(0)
const getNextHeader = () => String.fromCharCode(headerASCII++)
// create the table
const table = document.createElement("table")
/*
@param {string} val the text of the created cell
@param {Object} next the childs of the object
@param {HTMLRowElement | null} row the last created
@param {boolean} newRow if we need to create a new row
@param {boolean} newHeader if we need to create a new thead
*/
function createTable(val, next, row, newRow = false, newHeader = false) {
// create new header
if (newHeader) {
const head = document.createElement("thead")
// with depth - 1 cells (first one takes 2 columns)
for (let i = 0; i < maxDepth - 1; i++) {
let th = document.createElement("th")
th.textContent = getNextHeader()
if(i === 0) {th.colSpan = 2}
head.appendChild(th)
}
table.appendChild(head)
}
// create new row
if (newRow) {
row = document.createElement("tr")
table.appendChild(row)
}
// new cell
const cell = document.createElement("td")
cell.textContent = val
// span on enought rows to align with every child
cell.rowSpan = (function childCount(obj) {return Object.values(obj).reduce((acc, el) => acc + childCount(el), 0) || 1})(next)
row.appendChild(cell)
// recurcive call
Object.entries(next).forEach(([key, value], i) => {
createTable(`${val}.${key}`, value, row, i !== 0)
})
}
// first call
Object.entries(transformedValues).forEach(([key, value]) => {
createTable(key, value, null, true, true)
})
document.body.append(table)
table {
border-collapse: collapse;
}
table th, table td {
border: 2px solid black;
}
table th {
background-color: cyan;
}
推荐阅读
- laravel - Spatie、Laravel 和 VueJs 的角色和权限
- windows - Windows 上的 Sonar Scanner 一直在引用 UserAppdata/temp 的 jars
- npm - 找不到模块“watchpack”
- c# - /langversion 的选项“7.3”无效;必须是 ISO-1、ISO-2、默认值或 1 到 6 范围内的整数
- google-developers-console - console.developers.google.com 与 console.cloud.google.com 有何不同?
- objective-c - 将 NSString 转换为目标 C 中的无符号字符类型数组
- python - Graphviz Networkx - 可视化两组不同的节点
- google-cloud-build - 无法为 Cloud Build 配置 SMTP
- google-apps-script - 在迭代之间添加暂停
- django - 按模式将多个 Django url 前缀统一到同一页面