我正在尝试转置包含具有rowspan
和cellspan
属性的单元格的表。我已经尝试过对表进行转置的示例(here和here),但是它们没有考虑单元格的大小-因此,行和列最终会变得太长或太短。
如何摆放桌子并确保它保持矩形。
这是我的html表。
table tr:first-child {
color: #FFFFFF;
background-color: #639187;
}
table tr td:first-child {
color: #FFFFFF;
background-color: #639187;
}
<table cellspacing="0" border="1">
<tbody>
<tr>
<td></td>
<td colspan="1">9:00</td>
<td colspan="1">9:15</td>
<td colspan="1">9:30</td>
<td colspan="1">9:45</td>
<td colspan="1">10:00</td>
<td colspan="1">10:15</td>
<td colspan="1">10:30</td>
<td colspan="1">10:45</td>
<td colspan="1">11:00</td>
<td colspan="1">11:15</td>
<td colspan="1">11:30</td>
<td colspan="1">11:45</td>
<td colspan="1">12:00</td>
<td colspan="1">12:15</td>
<td colspan="1">12:30</td>
<td colspan="1">12:45</td>
<td colspan="1">13:00</td>
<td colspan="1">13:15</td>
<td colspan="1">13:30</td>
<td colspan="1">13:45</td>
<td colspan="1">14:00</td>
<td colspan="1">14:15</td>
<td colspan="1">14:30</td>
<td colspan="1">14:45</td>
<td colspan="1">15:00</td>
<td colspan="1">15:15</td>
<td colspan="1">15:30</td>
<td colspan="1">15:45</td>
<td colspan="1">16:00</td>
<td colspan="1">16:15</td>
<td colspan="1">16:30</td>
<td colspan="1">16:45</td>
<td colspan="1">17:00</td>
<td colspan="1">17:15</td>
<td colspan="1">17:30</td>
<td colspan="1">17:45</td>
<td colspan="1">18:00</td>
</tr>
<tr>
<td rowspan="1">Madrid</td>
<td style="background-color: rgb(204, 204, 204);" colspan="4" rowspan="1"></td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td style="background-color: rgb(204, 204, 204);" colspan="4" rowspan="1"></td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td rowspan="1">London</td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td style="background-color: rgb(204, 204, 204);" colspan="4" rowspan="1"></td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td style="background-color: rgb(204, 204, 204);" colspan="4" rowspan="1"></td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td style="background-color: rgb(204, 204, 204);" colspan="4" rowspan="1"></td>
<td> </td>
</tr>
<tr>
<td rowspan="1">Paris</td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td colspan="12" rowspan="1" style="background-color: rgb(204, 204, 204);"></td>
<td colspan="4" rowspan="1" style="background-color: rgb(204, 204, 204);"></td>
<td> </td>
</tr>
</tbody>
</table>
最佳答案
我发现使用普通的旧JavaScript要做这是一个不错的挑战。它与a previous question that I don't think it's a duplicate足够不同。请注意,以下代码仅适用于原始表中的rowspan
。但是,该逻辑应适用于colspan
。
它还不考虑页眉(thead
或th
s)或页脚(tfooter
s)。我认为解决这些问题并不困难。
我已经在下面的代码中添加了注释,以寻求指导,但是请务必提出任何问题。
console.time();
const transpose = m => m[0].map((x, i) => m.map(x => x[i]));
const table = document.getElementById("transposed");
const rows = Array.from(table.querySelectorAll("tr"));
const totalRowCount = rows.length;
// First, create an array of the rows and within each element,
// an array of the cells; easier to deal with than NodeLists.
// This could be done more cleverly with map or reduce, but
// I like good old fashioned for loops.
const m = new Array(totalRowCount);
for (let r = 0; r < rows.length; r++) {
const row = rows[r];
const cells = Array.from(row.querySelectorAll("td"));
m[r] = [];
for (let c = 0; c < cells.length; c++) {
const cell = cells[c];
let rowspan = cell.getAttribute("rowspan");
let colspan = cell.getAttribute("colspan");
rowspan = rowspan && parseInt(rowspan, 10);
colspan = colspan && parseInt(colspan, 10);
// Note that I'm swapping colspan and rowspan here in the
// cells of my array. I could do this after transposition,
// but felt like doing it here.
// Note also that unlike in the duplicate question, I
// default the attribute to 1 rather than 0. I found that
// some browsers get messed up with spanning 0 rows/columns.
cell.setAttribute("colspan", rowspan || 1);
cell.setAttribute("rowspan", colspan || 1);
// I'm using a temporary object here to make it easier to
// access information about the cell later on, without adding
// that information to the DOM.
m[r].push({
element: cell,
index: c,
rowspan: rowspan || 0,
colspan: colspan || 0
});
}
}
// Now m contains an array of arrays. Each of the 4 elements
// in the topmost array contains a different number of elements.
// The elements are objects containing the <td>, its index in
// the row and the rowspan and colspan for that cell.
// So, we'll build another array of arrays, this time with
// objects to represent the cells that are spanned.
let rowsToSpan = 0;
let colsToSpan = 0;
let cellsToInject = new Array(m.length);
for (let r = 0; r < m.length; r++) {
let colSpannedCells = m[r].filter(c => c.colspan && c.colspan > 1);
cellsToInject[r] = new Array(colSpannedCells.length);
for (let c = 0; c < colSpannedCells.length; c++) {
let cell = colSpannedCells[c];
cellsToInject[r].push({
index: cell.index,
cells: new Array(cell.colspan - 1)
});
}
}
// Now we have an array of arrays of the cells we want to inject, so we iterate
// over them, splicing the "empty" cells into the array.
var r = 0;
// One might wonder why I'm using for..of here, where I didn't previously; good
// question. :) I was playing around with performance (hence the console.time() and
// console.timeEnd()) and wanted to see the effect. This would work just as well
// with a normal for loop.
for (let row of cellsToInject) {
if (row && row.length) {
var injectIndex = 0;
var injectCount = 0;
for (let col of row) {
if (col && col.cells.length) {
col.cells.fill({
element: null,
rowspan: null,
colspan: null
});
// The trick here is to ensure we're taking account of previously
// injected cells to ensure the new set of cells are injected in
// the correct place.
injectIndex = col.index + injectCount + 1;
Array.prototype.splice.apply(m[r], [injectIndex, 0, ...col.cells])
// Keeping a running tally of the number of cells injected helps.
injectCount += col.cells.length;
}
}
}
r++;
}
// Now m is an array of arrays, with each element in the topmost
// array having an equal number of elements. This makes the transposition
// work better.
const transposed = transpose(m);
// Now we remove the tbody and inject our own.
table.removeChild(table.querySelector("tbody"));
let tbody = document.createElement("tbody");
// Just iterate over the transposed array, creating a row for each
// element, and iterate over the nested array, adding the element
// for each (where present) back in.
for (let rw of transposed) {
const row = document.createElement("tr");
for (let ce of rw) {
if (ce && ce.element) {
row.appendChild(ce.element);
}
}
tbody.appendChild(row);
}
table.appendChild(tbody);
console.timeEnd();
table tr:first-child {
color: #FFFFFF;
background-color: #639187;
}
table tr td:first-child {
color: #FFFFFF;
background-color: #639187;
}
<table cellspacing="0" border="1" id="not-transposed">
<tbody>
<tr>
<td></td>
<td colspan="1">9:00</td>
<td colspan="1">9:15</td>
<td colspan="1">9:30</td>
<td colspan="1">9:45</td>
<td colspan="1">10:00</td>
<td colspan="1">10:15</td>
<td colspan="1">10:30</td>
<td colspan="1">10:45</td>
<td colspan="1">11:00</td>
<td colspan="1">11:15</td>
<td colspan="1">11:30</td>
<td colspan="1">11:45</td>
<td colspan="1">12:00</td>
<td colspan="1">12:15</td>
<td colspan="1">12:30</td>
<td colspan="1">12:45</td>
<td colspan="1">13:00</td>
<td colspan="1">13:15</td>
<td colspan="1">13:30</td>
<td colspan="1">13:45</td>
<td colspan="1">14:00</td>
<td colspan="1">14:15</td>
<td colspan="1">14:30</td>
<td colspan="1">14:45</td>
<td colspan="1">15:00</td>
<td colspan="1">15:15</td>
<td colspan="1">15:30</td>
<td colspan="1">15:45</td>
<td colspan="1">16:00</td>
<td colspan="1">16:15</td>
<td colspan="1">16:30</td>
<td colspan="1">16:45</td>
<td colspan="1">17:00</td>
<td colspan="1">17:15</td>
<td colspan="1">17:30</td>
<td colspan="1">17:45</td>
<td colspan="1">18:00</td>
</tr>
<tr>
<td rowspan="1">Madrid</td>
<td style="background-color: rgb(204, 204, 204);" colspan="4" rowspan="1"></td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td style="background-color: rgb(204, 204, 204);" colspan="4" rowspan="1"></td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td rowspan="1">London</td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td style="background-color: rgb(204, 204, 204);" colspan="4" rowspan="1"></td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td style="background-color: rgb(204, 204, 204);" colspan="4" rowspan="1"></td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td style="background-color: rgb(204, 204, 204);" colspan="4" rowspan="1"></td>
<td> </td>
</tr>
<tr>
<td rowspan="1">Paris</td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td colspan="12" rowspan="1" style="background-color: rgb(204, 204, 204);"></td>
<td colspan="4" rowspan="1" style="background-color: rgb(204, 204, 204);"></td>
<td> </td>
</tr>
</tbody>
</table>
<table cellspacing="0" border="1" id="transposed">
<tbody>
<tr>
<td></td>
<td colspan="1">9:00</td>
<td colspan="1">9:15</td>
<td colspan="1">9:30</td>
<td colspan="1">9:45</td>
<td colspan="1">10:00</td>
<td colspan="1">10:15</td>
<td colspan="1">10:30</td>
<td colspan="1">10:45</td>
<td colspan="1">11:00</td>
<td colspan="1">11:15</td>
<td colspan="1">11:30</td>
<td colspan="1">11:45</td>
<td colspan="1">12:00</td>
<td colspan="1">12:15</td>
<td colspan="1">12:30</td>
<td colspan="1">12:45</td>
<td colspan="1">13:00</td>
<td colspan="1">13:15</td>
<td colspan="1">13:30</td>
<td colspan="1">13:45</td>
<td colspan="1">14:00</td>
<td colspan="1">14:15</td>
<td colspan="1">14:30</td>
<td colspan="1">14:45</td>
<td colspan="1">15:00</td>
<td colspan="1">15:15</td>
<td colspan="1">15:30</td>
<td colspan="1">15:45</td>
<td colspan="1">16:00</td>
<td colspan="1">16:15</td>
<td colspan="1">16:30</td>
<td colspan="1">16:45</td>
<td colspan="1">17:00</td>
<td colspan="1">17:15</td>
<td colspan="1">17:30</td>
<td colspan="1">17:45</td>
<td colspan="1">18:00</td>
</tr>
<tr>
<td rowspan="1">Madrid</td>
<td style="background-color: rgb(204, 204, 204);" colspan="4" rowspan="1"></td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td style="background-color: rgb(204, 204, 204);" colspan="4" rowspan="1"></td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td rowspan="1">London</td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td style="background-color: rgb(204, 204, 204);" colspan="4" rowspan="1"></td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td style="background-color: rgb(204, 204, 204);" colspan="4" rowspan="1"></td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td style="background-color: rgb(204, 204, 204);" colspan="4" rowspan="1"></td>
<td> </td>
</tr>
<tr>
<td rowspan="1">Paris</td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td colspan="12" rowspan="1" style="background-color: rgb(204, 204, 204);"></td>
<td colspan="4" rowspan="1" style="background-color: rgb(204, 204, 204);"></td>
<td> </td>
</tr>
</tbody>
</table>
注意:
transpose
通过this answer从Transposing a 2D-array in JavaScript到Mahdi Jadaliha。关于javascript - 具有'colspan'和'rowspan'属性的转置表,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52189230/