Skip to content

记一个 Table 跨行转换算法

源数据格式

javascript
[
  [{ value: "一级" }, { value: "二级1" }, { value: "三级1" }],
  [{ value: "一级" }, { value: "二级1" }, { value: "三级2" }],
  [{ value: "一级" }, { value: "二级2" }, { value: "三级3" }],
];
[
  [{ value: "一级" }, { value: "二级1" }, { value: "三级1" }],
  [{ value: "一级" }, { value: "二级1" }, { value: "三级2" }],
  [{ value: "一级" }, { value: "二级2" }, { value: "三级3" }],
];

HTML 模板

html
<table>
  <tr v-for="(row, rowIndex) in computedData" :key="rowIndex">
    <td v-for="(col, colIndex) in row" :rowspan="col.rowspan" :key="colIndex">{{ col.value }}</td>
  </tr>
</table>
<table>
  <tr v-for="(row, rowIndex) in computedData" :key="rowIndex">
    <td v-for="(col, colIndex) in row" :rowspan="col.rowspan" :key="colIndex">{{ col.value }}</td>
  </tr>
</table>

目标格式

javascript
// computedData
[
  [
    { rowspan: 3, value: "一级" },
    { rowspan: 2, value: "二级1" },
    { rowspan: 1, value: "三级1" },
  ],
  [{ rowspan: 1, value: "三级2" }],
  [
    { rowspan: 1, value: "二级2" },
    { rowspan: 1, value: "三级3" },
  ],
];
// computedData
[
  [
    { rowspan: 3, value: "一级" },
    { rowspan: 2, value: "二级1" },
    { rowspan: 1, value: "三级1" },
  ],
  [{ rowspan: 1, value: "三级2" }],
  [
    { rowspan: 1, value: "二级2" },
    { rowspan: 1, value: "三级3" },
  ],
];

难点解析

由于 table 跨行,会导致下一行的 td 不需要遍历,比如第一行的列跨到了第二行,那么第二行的列就不需要遍历。

所以 computedData 的 length 为 3、1、2

暂时没有特别好的办法,我所用的方式是生成 result 的时候,查找 result 中是否出现过相同值的单元格,如果出现,就 rowspan++,如果没有出现,则 push 进数组。

转换算法

javascript
function getRowSpan(inputData, rowIndex, colIndex, valueKeyName) {
  let n = 1;
  while (
    inputData[rowIndex + n] &&
    inputData[rowIndex + n][colIndex][valueKeyName] === inputData[rowIndex][colIndex][valueKeyName]
  ) {
    n++;
  }
  return n;
}

function isNeedShow(inputData, rowIndex, colIndex, valueKeyName) {
  const prev = inputData[rowIndex - 1];
  const current = inputData[rowIndex];
  if (prev && current && prev[colIndex][valueKeyName] === current[colIndex][valueKeyName]) {
    return false;
  } else {
    return true;
  }
}

export function transformRowSpan(inputData, valueKeyName) {
  const result = [];
  inputData.forEach((row, rowIndex) => {
    const computedRow = [];
    row.forEach((col, colIndex) => {
      if (isNeedShow(inputData, rowIndex, colIndex, valueKeyName)) {
        const computedCol = { ...col };
        computedCol.rowspan = getRowSpan(inputData, rowIndex, colIndex, valueKeyName) || 1;
        computedRow.push(computedCol);
      }
    });
    result.push(computedRow);
  });
  return result;
}
function getRowSpan(inputData, rowIndex, colIndex, valueKeyName) {
  let n = 1;
  while (
    inputData[rowIndex + n] &&
    inputData[rowIndex + n][colIndex][valueKeyName] === inputData[rowIndex][colIndex][valueKeyName]
  ) {
    n++;
  }
  return n;
}

function isNeedShow(inputData, rowIndex, colIndex, valueKeyName) {
  const prev = inputData[rowIndex - 1];
  const current = inputData[rowIndex];
  if (prev && current && prev[colIndex][valueKeyName] === current[colIndex][valueKeyName]) {
    return false;
  } else {
    return true;
  }
}

export function transformRowSpan(inputData, valueKeyName) {
  const result = [];
  inputData.forEach((row, rowIndex) => {
    const computedRow = [];
    row.forEach((col, colIndex) => {
      if (isNeedShow(inputData, rowIndex, colIndex, valueKeyName)) {
        const computedCol = { ...col };
        computedCol.rowspan = getRowSpan(inputData, rowIndex, colIndex, valueKeyName) || 1;
        computedRow.push(computedCol);
      }
    });
    result.push(computedRow);
  });
  return result;
}

最终效果

UTOOLS1587100295064.png

最后编辑时间:

Version 4.0 (framework-1.0.0-rc.20)