diff --git a/docs/demo/expandedSticky.md b/docs/demo/expandedSticky.md new file mode 100644 index 000000000..df58f5783 --- /dev/null +++ b/docs/demo/expandedSticky.md @@ -0,0 +1,8 @@ +--- +title: expandedSticky +nav: + title: Demo + path: /demo +--- + + diff --git a/docs/examples/expandedSticky.tsx b/docs/examples/expandedSticky.tsx new file mode 100644 index 000000000..c55aa7534 --- /dev/null +++ b/docs/examples/expandedSticky.tsx @@ -0,0 +1,82 @@ +import React, { useState } from 'react'; +import type { ColumnType } from 'rc-table'; +import Table from 'rc-table'; +import '../../assets/index.less'; + +// 合并单元格 +export const getRowSpan = (source: (string | number | undefined)[] = []) => { + const list: { rowSpan?: number }[] = []; + let span = 0; + source.reverse().forEach((key, index) => { + span = span + 1; + if (key !== source[index + 1]) { + list.push({ rowSpan: span }); + span = 0; + } else { + list.push({ rowSpan: 0 }); + } + }); + return list.reverse(); +}; + +const Demo = () => { + const [expandedRowKeys, setExpandedRowKeys] = useState([]); + + const data = [ + { key: 'a', a: '小二', d: '文零西路' }, + { key: 'b', a: '张三', d: '文一西路' }, + { key: 'c', a: '张三', d: '文二西路' }, + ]; + const rowKeys = data.map(item => item.key); + + const rowSpanList = getRowSpan(data.map(item => item.a)); + + const columns: ColumnType>[] = [ + { + title: '手机号', + dataIndex: 'a', + width: 100, + fixed: 'left', + onCell: (_, index) => { + const { rowSpan = 1 } = rowSpanList[index]; + const props: React.TdHTMLAttributes = {}; + props.rowSpan = rowSpan; + if (rowSpan >= 1) { + let currentRowSpan = rowSpan; + for (let i = index; i < index + rowSpan; i += 1) { + const rowKey = rowKeys[i]; + if (expandedRowKeys.includes(rowKey)) { + currentRowSpan += 1; + } + } + props.rowSpan = currentRowSpan; + } + return props; + }, + }, + Table.EXPAND_COLUMN, + { title: 'Address', fixed: 'right', dataIndex: 'd', width: 200 }, + ]; + + return ( +
+

expanded & sticky

+ > + rowKey="key" + sticky + scroll={{ x: 800 }} + columns={columns} + data={data} + expandable={{ + expandedRowOffset: 1, + expandedRowKeys, + onExpandedRowsChange: keys => setExpandedRowKeys(keys), + expandedRowRender: record =>

{record.key}

, + }} + className="table" + /> +
+ ); +}; + +export default Demo; diff --git a/src/Body/BodyRow.tsx b/src/Body/BodyRow.tsx index 7e320eaa6..5fd13a35e 100644 --- a/src/Body/BodyRow.tsx +++ b/src/Body/BodyRow.tsx @@ -4,7 +4,7 @@ import Cell from '../Cell'; import { responseImmutable } from '../context/TableContext'; import devRenderTimes from '../hooks/useRenderTimes'; import useRowInfo from '../hooks/useRowInfo'; -import type { ColumnType, CustomizeComponent } from '../interface'; +import type { ColumnType, CustomizeComponent, ExpandableConfig } from '../interface'; import ExpandedRow from './ExpandedRow'; import { computedExpandedClassName } from '../utils/expandUtil'; import { TableProps } from '..'; @@ -22,6 +22,7 @@ export interface BodyRowProps { scopeCellComponent: CustomizeComponent; indent?: number; rowKey: React.Key; + expandedRowOffset?: ExpandableConfig['expandedRowOffset']; } // ================================================================================== @@ -107,6 +108,7 @@ function BodyRow( rowComponent: RowComponent, cellComponent, scopeCellComponent, + expandedRowOffset = 0, } = props; const rowInfo = useRowInfo(record, rowKey, index, indent); @@ -196,6 +198,14 @@ function BodyRow( if (rowSupportExpand && (expandedRef.current || expanded)) { const expandContent = expandedRowRender(record, index, indent + 1, expanded); + const offsetColumns = flattenColumns.filter((_, idx) => idx < expandedRowOffset); + let offsetWidth = 0; + offsetColumns.forEach(item => { + if (typeof item.width === 'number') { + offsetWidth = offsetWidth + (item.width ?? 0); + } + }); + expandRowNode = ( ( prefixCls={prefixCls} component={RowComponent} cellComponent={cellComponent} - colSpan={flattenColumns.length} + offsetWidth={offsetWidth} + colSpan={flattenColumns.length - expandedRowOffset} isEmpty={false} > {expandContent} diff --git a/src/Body/ExpandedRow.tsx b/src/Body/ExpandedRow.tsx index b4009601c..aee83c6aa 100644 --- a/src/Body/ExpandedRow.tsx +++ b/src/Body/ExpandedRow.tsx @@ -14,6 +14,7 @@ export interface ExpandedRowProps { children: React.ReactNode; colSpan: number; isEmpty: boolean; + offsetWidth?: number; } function ExpandedRow(props: ExpandedRowProps) { @@ -30,6 +31,7 @@ function ExpandedRow(props: ExpandedRowProps) { expanded, colSpan, isEmpty, + offsetWidth = 0, } = props; const { scrollbarSize, fixHeader, fixColumn, componentWidth, horizonScroll } = useContext( @@ -39,12 +41,11 @@ function ExpandedRow(props: ExpandedRowProps) { // Cache render node let contentNode = children; - if (isEmpty ? horizonScroll && componentWidth : fixColumn) { contentNode = (
(props: BodyProps) { emptyNode, classNames, styles, + expandedRowOffset, } = useContext(TableContext, [ 'prefixCls', 'getComponent', @@ -45,6 +46,7 @@ function Body(props: BodyProps) { 'emptyNode', 'classNames', 'styles', + 'expandedRowOffset', ]); const { body: bodyCls = {} } = classNames || {}; const { body: bodyStyles = {} } = styles || {}; @@ -83,6 +85,7 @@ function Body(props: BodyProps) { cellComponent={tdComponent} scopeCellComponent={thComponent} indent={indent} + expandedRowOffset={expandedRowOffset} /> ); }); diff --git a/src/Table.tsx b/src/Table.tsx index d5a8b196c..58a626731 100644 --- a/src/Table.tsx +++ b/src/Table.tsx @@ -872,6 +872,7 @@ function Table( expandedRowRender: expandableConfig.expandedRowRender, onTriggerExpand, expandIconColumnIndex: expandableConfig.expandIconColumnIndex, + expandedRowOffset: expandableConfig.expandedRowOffset, indentSize: expandableConfig.indentSize, allColumnsFixedLeft: flattenColumns.every(col => col.fixed === 'start'), emptyNode, @@ -922,6 +923,7 @@ function Table( expandableConfig.expandedRowRender, onTriggerExpand, expandableConfig.expandIconColumnIndex, + expandableConfig.expandedRowOffset, expandableConfig.indentSize, emptyNode, diff --git a/src/context/TableContext.tsx b/src/context/TableContext.tsx index b9cae4ddc..381cf68b2 100644 --- a/src/context/TableContext.tsx +++ b/src/context/TableContext.tsx @@ -3,6 +3,7 @@ import type { ColumnsType, ColumnType, Direction, + ExpandableConfig, ExpandableType, ExpandedRowRender, GetComponent, @@ -55,6 +56,7 @@ export interface TableContextProps { expandIcon: RenderExpandIcon; onTriggerExpand: TriggerEventHandler; expandIconColumnIndex: number; + expandedRowOffset: ExpandableConfig['expandedRowOffset']; allColumnsFixedLeft: boolean; // Column diff --git a/src/interface.ts b/src/interface.ts index 54ebfcd97..dcdfb4f9b 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -256,6 +256,7 @@ export interface ExpandableConfig { rowExpandable?: (record: RecordType) => boolean; columnWidth?: number | string; fixed?: FixedType; + expandedRowOffset?: number; } // =================== Render ===================