JS+HTML创建跨单元格矩阵表格:解决溢出与Pareto列显示问题
问题修正:带跨单元格的矩阵表格内容溢出与Pareto列分行显示
问题1:表格右侧内容溢出
通过CSS设置单元格文本自动换行,配合固定表格布局,确保内容自适应容器宽度,避免超出边界。
问题2:Pareto列数据分行显示
原代码将同一Process+DATE下的Pareto值合并为逗号分隔字符串,现改为根据实际数据条目数动态生成行,同时调整跨单元格(rowspan)的数量,让每个Pareto值单独占一行。
修正后的完整代码
HTML/JavaScript
var data = [{ Process: 'PCAL', DATE: '29 Nov 2023', FPY: '0.0', QTY: '1', RTY: '0.0', Pareto: 'Client BER META 1 Serdes 142', Fail: '1' }, { Process: 'CAL', DATE: '28 Nov 2023', FPY: '100.0', QTY: '2', RTY: '100.0', Pareto: 'None', Fail: 'None' }, { Process: 'FVT', DATE: '28 Nov 2023', FPY: '50.0', QTY: '2', RTY: '50.0', Pareto: 'Client BER Lane 12', Fail: '3' }, { Process: 'FVT', DATE: '28 Nov 2023', FPY: '50.0', QTY: '2', RTY: '50.0', Pareto: 'Client BER', Fail: '1' }, { Process: 'ESS', DATE: '28 Nov 2023', FPY: '100.0', QTY: '1', RTY: '100.0', Pareto: 'None', Fail: 'None' }, { Process: 'ESS', DATE: '29 Nov 2023', FPY: '0.0', QTY: '1', RTY: '0.0', Pareto: 'Module Power', Fail: '4' }, { Process: 'ESS', DATE: '29 Nov 2023', FPY: '0.0', QTY: '1', RTY: '0.0', Pareto: 'Module A Power', Fail: '14' }, { Process: 'EXS', DATE: '30 Nov 2023', FPY: '100.0', QTY: '3', RTY: '100.0', Pareto: 'None', Fail: 'None' } ]; // 提取并排序唯一日期 var uniqueDates = [...new Set(data.map(item => item.DATE))].sort(); // 预计算每个Process对应的最大行数(各日期下的条目数最大值) var processRowCounts = {}; var uniqueProcesses = [...new Set(data.map(item => item.Process))]; uniqueProcesses.forEach(process => { var maxRows = 0; uniqueDates.forEach(date => { var count = data.filter(item => item.Process === process && item.DATE === date).length; if (count > maxRows) maxRows = count; }); processRowCounts[process] = maxRows || 1; // 至少保留1行 }); // 创建表格 document.write('<table>'); document.write('<tr><th rowspan="2">Process</th>'); // 日期表头 uniqueDates.forEach(date => { document.write(`<th colspan="5">${date}</th>`); }); document.write('</tr>'); // 子列表头 document.write('<tr>'); uniqueDates.forEach(() => { document.write('<th>Qty</th><th>FPY</th><th>RTY</th><th>Pareto</th><th>Fail</th>'); }); document.write('</tr>'); // 填充数据 uniqueProcesses.forEach(process => { const totalRows = processRowCounts[process]; // 第一行:Process跨totalRows行,各日期的基础数据跨对应行数 document.write(`<tr><td rowspan="${totalRows}">${process}</td>`); // 存储每个日期下的数据,方便后续行填充 const dateDataMap = {}; uniqueDates.forEach(date => { const rowData = data.filter(item => item.Process === process && item.DATE === date); dateDataMap[date] = rowData; const rowCount = rowData.length; if (rowCount > 0) { // QTY/FPY/RTY跨当前日期的条目数 document.write(` <td rowspan="${rowCount}">${rowData[0].QTY}</td> <td rowspan="${rowCount}">${rowData[0].FPY}</td> <td rowspan="${rowCount}">${rowData[0].RTY}</td> <td>${rowData[0].Pareto}</td> <td>${rowData[0].Fail}</td> `); } else { // 无数据时跨Process的总行数 document.write(` <td rowspan="${totalRows}"></td> <td rowspan="${totalRows}"></td> <td rowspan="${totalRows}"></td> <td></td> <td></td> `); } }); document.write('</tr>'); // 后续行:填充剩余的Pareto和Fail值 for (let rowIdx = 1; rowIdx < totalRows; rowIdx++) { document.write('<tr>'); uniqueDates.forEach(date => { const rowData = dateDataMap[date]; if (rowData && rowData[rowIdx]) { document.write('<td></td><td></td><td></td>'); // QTY/FPY/RTY已跨行,留空 document.write(`<td>${rowData[rowIdx].Pareto}</td>`); document.write(`<td>${rowData[rowIdx].Fail}</td>`); } else { // 无数据或超出当前日期条目数,填充空单元格 document.write('<td></td><td></td><td></td><td></td><td></td>'); } }); document.write('</tr>'); } }); document.write('</table>');
CSS
table { border-collapse: collapse; width: 100%; table-layout: fixed; /* 固定布局,防止列宽失衡 */ } table, th, td { border: 1px solid black; } th, td { padding: 10px; text-align: left; word-break: break-word; /* 长文本自动换行 */ overflow-wrap: break-word; } th { background-color: #f0f0f0; /* 表头背景色,可选优化 */ }
关键修改说明
- 修复表头错误:原代码第一列表头误写为
DATE,修正为Process,匹配数据逻辑。 - 动态跨行计算:不再固定设置
rowspan=5,而是根据每个Process下各日期的实际数据量,动态计算跨行行数,确保内容完全显示。 - Pareto分行处理:遍历Process的后续行,逐个填充剩余的Pareto和Fail值,避免合并为逗号分隔字符串。
- 解决内容溢出:通过
word-break: break-word实现长文本自动换行,table-layout: fixed保证表格布局稳定,防止超出容器宽度。
内容的提问来源于stack exchange,提问作者EAF
相关产品推荐
相关产品推荐

