js
复制代码
/**
* 动态生成多层表头表格
* @param {Object} options - 表格配置
* @param {Array} options.headers - 表头配置数组
* @param {Array} options.data - 表格数据数组
* @param {string} options.containerId - 容器ID
*/
function generateMultiHeaderTable(options) {
const { headers, data, containerId } = options;
const container = document.getElementById(containerId);
if (!container) return;
// 1. 计算表头层级和每个单元格的合并属性
const headerLevels = calculateHeaderLevels(headers);
const processedHeaders = processHeaders(headers, headerLevels);
// 2. 生成表头HTML
const theadHtml = generateThead(processedHeaders, headerLevels);
// 3. 生成表格内容HTML
const tbodyHtml = generateTbody(data, processedHeaders);
// 4. 组合成完整表格并渲染
const tableHtml = `
<table border="1" cellpadding="8" cellspacing="0">
${theadHtml}
${tbodyHtml}
</table>
`;
container.innerHTML = tableHtml;
}
/**
* 计算表头的最大层级
*/
function calculateHeaderLevels(headers) {
let maxLevel = 1;
function traverse(header, currentLevel) {
if (currentLevel > maxLevel) {
maxLevel = currentLevel;
}
if (header.children && header.children.length) {
header.children.forEach(child => traverse(child, currentLevel + 1));
}
}
headers.forEach(header => traverse(header, 1));
return maxLevel;
}
/**
* 处理表头,计算每个单元格的rowspan和colspan
*/
function processHeaders(headers, totalLevels) {
const result = [];
function traverse(headers, currentLevel, parent) {
headers.forEach(header => {
// 标记当前层级
header.level = currentLevel;
// 没有子项的单元格需要跨越多行
if (!header.children || !header.children.length) {
header.rowspan = totalLevels - currentLevel + 1;
header.colspan = 1;
result.push(header);
} else {
// 有子项的单元格只占当前行
header.rowspan = 1;
// 计算需要横跨的列数(子项总数量)
header.colspan = countLeafNodes(header.children);
result.push(header);
// 递归处理子项
traverse(header.children, currentLevel + 1, header);
}
});
}
traverse(headers, 1, null);
return result;
}
/**
* 计算叶子节点数量(用于确定colspan)
*/
function countLeafNodes(headers) {
let count = 0;
function traverse(headers) {
headers.forEach(header => {
if (!header.children || !header.children.length) {
count++;
} else {
traverse(header.children);
}
});
}
traverse(headers);
return count;
}
/**
* 生成表头HTML
*/
function generateThead(headers, totalLevels) {
let thead = '<thead>';
// 为每个层级生成一行
for (let level = 1; level <= totalLevels; level++) {
const levelHeaders = headers.filter(header => header.level === level);
thead += '<tr>';
levelHeaders.forEach(header => {
thead += `<th rowspan="${header.rowspan}" colspan="${header.colspan}">${header.name}</th>`;
});
thead += '</tr>';
}
thead += '</thead>';
return thead;
}
/**
* 生成表格内容HTML
*/
function generateTbody(data, headers) {
// 获取所有叶子节点(最终列)
const leafHeaders = headers.filter(header => !header.children || !header.children.length);
let tbody = '<tbody>';
data.forEach(row => {
tbody += '<tr>';
leafHeaders.forEach(header => {
tbody += `<td>${row[header.key] !== undefined ? row[header.key] : ''}</td>`;
});
tbody += '</tr>';
});
tbody += '</tbody>';
return tbody;
}
// ------------------------------
// 使用示例
// ------------------------------
// 1. 定义表头结构
const headers = [
{
name: '日期',
key: 'date',
// 没有children表示这是叶子节点
},
{
name: '产品A',
children: [
{ name: '销量', key: 'a_sales' },
{ name: '销售额', key: 'a_revenue' }
]
},
{
name: '产品B',
children: [
{ name: '销量', key: 'b_sales' },
{ name: '销售额', key: 'b_revenue' },
{
name: '增长率',
children: [
{ name: '周环比', key: 'b_week_growth' },
{ name: '月环比', key: 'b_month_growth' }
]
}
]
},
{
name: '总计',
key: 'total'
}
];
// 2. 定义表格数据
const tableData = [
{
date: '2023-01-01',
a_sales: 120,
a_revenue: 6000,
b_sales: 80,
b_revenue: 4000,
b_week_growth: '12%',
b_month_growth: '8%',
total: 10000
},
{
date: '2023-01-02',
a_sales: 150,
a_revenue: 7500,
b_sales: 95,
b_revenue: 4750,
b_week_growth: '8%',
b_month_growth: '5%',
total: 12250
}
];
// 3. 生成表格
window.onload = () => {
generateMultiHeaderTable({
headers: headers,
data: tableData,
containerId: 'tableContainer'
});
};