jquery 具有“colspan”和“rowspan”属性的转置表

wkftcu5l  于 2023-08-04  发布在  jQuery
关注(0)|答案(1)|浏览(94)

我正在尝试转置一个包含rowspancellspan属性的单元格的表。我试过转置表的例子(herehere),但它们没有考虑单元格的大小--因此行和列最终会太长或太短。
我怎样才能调换我的表,并确保它仍然是矩形。
这是我的表的HTML。

table tr:first-child {
  color: #FFFFFF;
  background-color: #639187;
}

table tr td:first-child {
  color: #FFFFFF;
  background-color: #639187;
}

个字符

bjp0bcyl

bjp0bcyl1#

我发现这是一个很好的挑战,使用普通的旧JavaScript。它与a previous question that I don't think it's a duplicate有很大的不同。请注意,下面的代码仅适用于原始表中的rowspan s;然而,该逻辑应当适用于colspans。
它也不考虑页眉(thead s或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>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td style="background-color: rgb(204, 204, 204);" colspan="4" rowspan="1"></td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
    </tr>
    <tr>
      <td rowspan="1">London</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td style="background-color: rgb(204, 204, 204);" colspan="4" rowspan="1"></td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td style="background-color: rgb(204, 204, 204);" colspan="4" rowspan="1"></td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td style="background-color: rgb(204, 204, 204);" colspan="4" rowspan="1"></td>
      <td>&nbsp;</td>
    </tr>
    <tr>
      <td rowspan="1">Paris</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</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>&nbsp;</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>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td style="background-color: rgb(204, 204, 204);" colspan="4" rowspan="1"></td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
    </tr>
    <tr>
      <td rowspan="1">London</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td style="background-color: rgb(204, 204, 204);" colspan="4" rowspan="1"></td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td style="background-color: rgb(204, 204, 204);" colspan="4" rowspan="1"></td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td style="background-color: rgb(204, 204, 204);" colspan="4" rowspan="1"></td>
      <td>&nbsp;</td>
    </tr>
    <tr>
      <td rowspan="1">Paris</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</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>&nbsp;</td>
    </tr>
  </tbody>
</table>

注意:transpose来自this answerTransposing a 2D-array in JavaScriptMahdi Jadaliha

相关问题