Giter VIP home page Giter VIP logo

Comments (5)

Fansaly avatar Fansaly commented on August 28, 2024 2
  • 复杂分组表头
  • 复杂分组表头下 colStart 与 colEnd 不正确的问题
  • 复杂分组表头下,且数据为空时 body colspan 不正确的问题
  • 测试

(匿了

from table.

Fansaly avatar Fansaly commented on August 28, 2024

实现复杂分组表头最小侵入方案:

已有单元测试测试通过

新增 src/utils/convertUtil.ts
interface Column {
  [key: string | symbol]: any;
};

interface Options {
  children: string;
  colSpan: string;
  rowSpan: string;
  hidden: string;
}

export function convertColumns<Columns extends readonly any[] = Column[]>(
  columns: Columns,
  options: Partial<Options> = {},
) {
  if (!Array.isArray(columns) || columns.length === 0) {
    return [] as unknown as Columns;
  }

  const defaultOptions = {
    children: 'children',
    colSpan: 'colSpan',
    rowSpan: 'rowSpan',
    hidden: 'hidden',
  };
  const {
    children: childrenProp,
    colSpan: colSpanProp,
    rowSpan: rowSpanProp,
    hidden: hiddenProp,
  } = Object.assign({}, defaultOptions, options);

  let specified = false;
  let tree = columns.map((item) => ({ ...item } as Column));

  let depthCurr = 0;
  let depthNext = 0;
  const nodePos: {
    index: number;
    total: number;
  } = [{
    index: tree.length,
    total: tree.length,
  }];
  const rowSpans: number[] = [];
  const columnsMap = new Map<number, Column[]>();
  const treeMap = new Map<Column, Column[]>();
  const branchLastSet = new Set<Column>();

  while (tree.length > 0) {
    depthCurr = depthNext;

    nodePos.splice(depthCurr + 1);
    rowSpans.splice(depthCurr);

    nodePos[depthCurr].index--;

    if (nodePos[depthCurr].index <= 0) {
      depthNext = 0;

      for (let i = nodePos.length - 1; i >= 0; i--) {
        if (nodePos[i].index > 0) {
          depthNext = i;
          break;
        }
      }
    }

    const node = tree.shift();

    if (!node || typeof node !== 'object' || node[hiddenProp]) {
      continue;
    }

    // const pathKey = nodePos.reduce((acc, { index, total }) => {
    //   return `${acc}-${total - 1 - index}`;
    // }, 'key');

    const colSpanSpecified = node[colSpanProp];
    const rowSpanSpecified = node[rowSpanProp];
    const colSpan = node[colSpanProp] ?? 1;
    const rowSpan = node[rowSpanProp] ?? 1;
    node[colSpanProp] = colSpan;
    node[rowSpanProp] = rowSpan;

    if (!specified && (colSpan > 1 || rowSpan > 1)) {
      specified = true;
    }

    const parentsRowCount = rowSpans.reduce((acc, num) => acc + num, 0);
    if (!columnsMap.has(parentsRowCount)) {
      columnsMap.set(parentsRowCount, []);
    }
    columnsMap.get(parentsRowCount).push(node);

    let leaf = node[childrenProp];
    delete node[childrenProp];

    if (Array.isArray(leaf) && leaf.length > 0) {
      depthNext = depthCurr + 1;
      nodePos[depthNext] = { index: leaf.length, total: leaf.length };
      rowSpans[depthCurr] = rowSpan;

      leaf = leaf.map((item) => ({ ...item } as Column));
      node.colSpanSpecified = colSpanSpecified;
      if (!treeMap.has(node)) {
        treeMap.set(node, []);
      }
      treeMap.get(node).push(...leaf);
      tree = [...leaf, ...tree];
    } else {
      node.rowSpanSpecified = rowSpanSpecified;
      node.parentsRowCount = parentsRowCount;
      branchLastSet.add(node);
    }
  }

  if (!specified) {
    return columns;
  }

  // correct colSpan of parent column in default state
  [...treeMap.keys()].reverse().forEach((column) => {
    const { colSpanSpecified } = column;
    delete column.colSpanSpecified;

    if (column[hiddenProp] || Number.isInteger(colSpanSpecified)) {
      return;
    }

    const children = treeMap.get(column);
    column[colSpanProp] = children.reduce((acc, item) => {
      return item[hiddenProp] ? acc : acc + item[colSpanProp];
    }, 0);
  });

  let rowCountMax = 0;
  branchLastSet.forEach((column) => {
    const rowCount = column[rowSpanProp] + column.parentsRowCount;
    if (rowCount > rowCountMax) {
      rowCountMax = rowCount;
    }
  });

  // correct rowSpan of column in default state
  branchLastSet.forEach((column) => {
    const { rowSpanSpecified, parentsRowCount } = column;

    if (!Number.isInteger(rowSpanSpecified)) {
      column[rowSpanProp] = rowCountMax - parentsRowCount;
    }

    delete column.rowSpanSpecified;
    delete column.parentsRowCount;
  });

  const keys = [...columnsMap.keys()].sort();
  for (let i = keys.length - 1; i >= 1; i--) {
    const parent = columnsMap.get(keys[i - 1]);
    parent[0][childrenProp] = columnsMap.get(keys[i]);
  }

  return columnsMap.get(0) as unknown as Columns;
}

src/Header/Header.tsxfillRowCells 之前转换 rootColumns

diff --git a/src/Header/Header.tsx b/src/Header/Header.tsx
index f21b817b..07162562 100644
--- a/src/Header/Header.tsx
+++ b/src/Header/Header.tsx
@@ -2,6 +2,7 @@ import { useContext } from '@rc-component/context';
 import * as React from 'react';
 import TableContext, { responseImmutable } from '../context/TableContext';
 import devRenderTimes from '../hooks/useRenderTimes';
+import { convertColumns } from '../utils/convertUtil';
 import type {
   CellType,
   ColumnGroupType,
@@ -67,7 +68,7 @@ function parseHeaderRows<RecordType>(
   }

   // Generate `rows` cell data
-  fillRowCells(rootColumns, 0);
+  fillRowCells(convertColumns<ColumnsType<RecordType>>(rootColumns), 0);

   // Handle `rowSpan`
   const rowCount = rows.length;

from table.

afc163 avatar afc163 commented on August 28, 2024

来个 PR?

from table.

Fansaly avatar Fansaly commented on August 28, 2024

@afc163 #1118 PR 已提交

from table.

Fansaly avatar Fansaly commented on August 28, 2024

新增复杂分组表头后会造成以下影响

  • 复杂分组表头下的 colStart colEnd 计算不正确

    在显式指定的 colSpanrowSpan 大于或者等于 2 时

  • table 数据为空时 .rc-table-placeholder .rc-table-cellcolspan 值不正确

    flattenColumns.length实际表头列数 不一致时

改动的文件可能较多,继续在 #1118 追加完善,还是等待 merge 后再提交新的 PR 呢

from table.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.