refactor: table

pull/4639/head
tangjinzhou 2021-09-04 17:11:18 +08:00
parent 60ea53ce91
commit a948e663a9
13 changed files with 199 additions and 128 deletions

View File

@ -142,26 +142,6 @@ export default defineComponent<BodyRowProps<unknown>>({
const key = columnsKey[colIndex];
const fixedInfo = fixedInfoList[colIndex];
// ============= Used for nest expandable =============
let appendCellNode;
if (colIndex === (expandIconColumnIndex || 0) && nestExpandable.value) {
appendCellNode = (
<>
<span
style={{ paddingLeft: `${indentSize * indent}px` }}
class={`${prefixCls}-row-indent indent-level-${indent}`}
/>
{expandIcon({
prefixCls,
expanded: expanded.value,
expandable: hasNestChildren.value,
record,
onExpand: onInternalTriggerExpand,
})}
</>
);
}
let additionalCellProps;
if (column.customCell) {
additionalCellProps = column.customCell(record, index);
@ -180,8 +160,30 @@ export default defineComponent<BodyRowProps<unknown>>({
dataIndex={dataIndex}
customRender={customRender}
{...fixedInfo}
appendNode={appendCellNode}
additionalProps={additionalCellProps}
v-slots={{
// ============= Used for nest expandable =============
appendNode: () => {
if (colIndex === (expandIconColumnIndex || 0) && nestExpandable.value) {
return (
<>
<span
style={{ paddingLeft: `${indentSize * indent}px` }}
class={`${prefixCls}-row-indent indent-level-${indent}`}
/>
{expandIcon({
prefixCls,
expanded: expanded.value,
expandable: hasNestChildren.value,
record,
onExpand: onInternalTriggerExpand,
})}
</>
);
}
return null;
},
}}
/>
);
})}

View File

@ -43,24 +43,6 @@ export default defineComponent<ExpandedRowProps>({
colSpan,
} = props;
let contentNode: any = slots.default?.();
if (fixColumn) {
contentNode = (
<div
style={{
width: componentWidth - (fixHeader ? tableContext.scrollbarSize : 0),
position: 'sticky',
left: 0,
overflow: 'hidden',
}}
class={`${prefixCls}-expanded-row-fixed`}
>
{contentNode}
</div>
);
}
return (
<Component
class={attrs.class}
@ -68,9 +50,33 @@ export default defineComponent<ExpandedRowProps>({
display: expanded ? null : 'none',
}}
>
<Cell component={cellComponent} prefixCls={prefixCls} colSpan={colSpan}>
{contentNode}
</Cell>
<Cell
component={cellComponent}
prefixCls={prefixCls}
colSpan={colSpan}
v-slots={{
default: () => {
let contentNode: any = slots.default?.();
if (fixColumn) {
contentNode = (
<div
style={{
width: componentWidth - (fixHeader ? tableContext.scrollbarSize : 0),
position: 'sticky',
left: 0,
overflow: 'hidden',
}}
class={`${prefixCls}-expanded-row-fixed`}
>
{contentNode}
</div>
);
}
return contentNode;
},
}}
></Cell>
</Component>
);
};

View File

@ -16,7 +16,6 @@ export interface BodyProps<RecordType> {
expandedKeys: Set<Key>;
customRow: GetComponentProps<RecordType>;
rowExpandable: (record: RecordType) => boolean;
// emptyNode: React.ReactNode;
childrenColumnName: string;
}

View File

@ -22,14 +22,12 @@ function isRenderCell<RecordType = DefaultRecordType>(
export interface CellProps<RecordType = DefaultRecordType> {
prefixCls?: string;
className?: string;
record?: RecordType;
/** `record` index. Not `column` index. */
index?: number;
dataIndex?: DataIndex;
customRender?: ColumnType<RecordType>['customRender'];
component?: CustomizeComponent;
children?: any;
colSpan?: number;
rowSpan?: number;
ellipsis?: CellEllipsisType;
@ -46,6 +44,7 @@ export interface CellProps<RecordType = DefaultRecordType> {
// Additional
/** @private Used for `expandable` with nest tree */
appendNode?: any;
additionalProps?: HTMLAttributes;
rowType?: 'header' | 'body' | 'footer';
@ -56,18 +55,39 @@ export interface CellProps<RecordType = DefaultRecordType> {
}
export default defineComponent<CellProps>({
name: 'Cell',
props: [] as any,
props: [
'prefixCls',
'record',
'index',
'dataIndex',
'customRender',
'children',
'component',
'colSpan',
'rowSpan',
'fixLeft',
'fixRight',
'firstFixLeft',
'lastFixLeft',
'firstFixRight',
'lastFixRight',
'appendNode',
'additionalProps',
'ellipsis',
'align',
'rowType',
'isSticky',
'column',
] as any,
slots: ['appendNode'],
setup(props) {
setup(props, { slots }) {
return () => {
const {
prefixCls,
className,
record,
index,
dataIndex,
customRender,
children,
component: Component = 'td',
colSpan,
rowSpan,
@ -77,7 +97,7 @@ export default defineComponent<CellProps>({
lastFixLeft,
firstFixRight,
lastFixRight,
appendNode,
appendNode = slots.appendNode?.(),
additionalProps = {},
ellipsis,
align,
@ -90,7 +110,7 @@ export default defineComponent<CellProps>({
// ==================== Child Node ====================
let cellProps: CellType;
let childNode;
const children = slots.default?.();
if (validateValue(children)) {
childNode = children;
} else {
@ -127,8 +147,7 @@ export default defineComponent<CellProps>({
colSpan: cellColSpan,
rowSpan: cellRowSpan,
style: cellStyle,
className: cellClassName,
class: cellClass,
class: cellClassName,
...restCellProps
} = cellProps || {};
const mergedColSpan = cellColSpan !== undefined ? cellColSpan : colSpan;
@ -179,7 +198,6 @@ export default defineComponent<CellProps>({
rowSpan: mergedRowSpan && mergedRowSpan !== 1 ? mergedRowSpan : null,
class: classNames(
cellPrefixCls,
className,
{
[`${cellPrefixCls}-fix-left`]: isFixLeft,
[`${cellPrefixCls}-fix-left-first`]: firstFixLeft,
@ -193,7 +211,6 @@ export default defineComponent<CellProps>({
},
additionalProps.class,
cellClassName,
cellClass,
),
style: {
...parseStyleText(additionalProps.style as any),

View File

@ -6,8 +6,6 @@ import type { AlignType } from '../interface';
import { getCellFixedInfo } from '../utils/fixUtil';
export interface SummaryCellProps {
className?: string;
children?: any;
index: number;
colSpan?: number;
rowSpan?: number;
@ -38,7 +36,7 @@ export default defineComponent<SummaryCellProps>({
return (
<Cell
className={attrs.class as string}
class={attrs.class as string}
index={index}
component="td"
prefixCls={prefixCls}

View File

@ -1,3 +1,8 @@
export default function FooterRow(props, { slots }) {
return <tr {...props}>{slots.default?.()}</tr>;
}
import { defineComponent } from 'vue';
export default defineComponent({
name: 'FooterRow',
setup(_props, { slots }) {
return () => <tr>{slots.default?.()}</tr>;
},
});

View File

@ -1,4 +1,5 @@
import { FunctionalComponent } from 'vue';
import { computed, defineComponent, FunctionalComponent, onBeforeUnmount, watchEffect } from 'vue';
import { useInjectTable } from '../context/TableContext';
import Cell from './Cell';
import Row from './Row';
@ -11,16 +12,22 @@ export interface SummaryFC extends FunctionalComponent<SummaryProps> {
Cell: typeof Cell;
}
/**
* Syntactic sugar. Do not support HOC.
*/
const Summary: SummaryFC = (_props, { slots }) => {
return slots.default?.();
};
Summary.Row = Row;
Summary.Cell = Cell;
Summary.displayName = 'Summary';
let indexGuid = 0;
const Summary = defineComponent<SummaryProps>({
props: ['fixed'] as any,
name: 'Summary',
setup(props, { slots }) {
const tableContext = useInjectTable();
const uniKey = `table-summary-uni-key-${++indexGuid}`;
const fixed = computed(() => (props.fixed as string) === '' || props.fixed);
watchEffect(() => {
tableContext.summaryCollect(uniKey, fixed.value);
});
onBeforeUnmount(() => {
tableContext.summaryCollect(uniKey, false);
});
return () => slots.default?.();
},
});
export default Summary;

View File

@ -29,8 +29,8 @@ function parseHeaderRows<RecordType>(
const colSpans: number[] = columns.filter(Boolean).map(column => {
const cell: CellType<RecordType> = {
key: column.key,
className: classNames(column.className, column.class),
children: column.title,
class: classNames(column.className, column.class),
// children: column.title,
column,
colStart: currentColIndex,
};

View File

@ -86,6 +86,7 @@ export default defineComponent<RowProps>({
additionalProps={additionalProps}
rowType="header"
column={column}
v-slots={{ default: () => column.title }}
/>
);
})}

View File

@ -1,26 +1,20 @@
import ColumnGroup from './sugar/ColumnGroup';
import Column from './sugar/Column';
import Header from './Header/Header';
import type {
GetRowKey,
ColumnsType,
TableComponents,
Key,
DefaultRecordType,
TriggerEventHandler,
GetComponentProps,
ExpandableConfig,
LegacyExpandableProps,
GetComponent,
PanelRender,
TableLayout,
ExpandableType,
RowClassName,
CustomizeComponent,
ColumnType,
CustomizeScrollBody,
TableSticky,
FixedType,
} from './interface';
import Body from './Body';
import useColumns from './hooks/useColumns';
@ -28,16 +22,13 @@ import { useLayoutState, useTimeoutLock } from './hooks/useFrame';
import { getPathValue, mergeObject, validateValue, getColumnsKey } from './utils/valueUtil';
import useStickyOffsets from './hooks/useStickyOffsets';
import ColGroup from './ColGroup';
import { getExpandableProps, getDataAndAriaProps } from './utils/legacyUtil';
import Panel from './Panel';
import Footer, { FooterComponents } from './Footer';
import Footer from './Footer';
import { findAllChildrenKeys, renderExpandIcon } from './utils/expandUtil';
import { getCellFixedInfo } from './utils/fixUtil';
import StickyScrollBar from './stickyScrollBar';
import useSticky from './hooks/useSticky';
import FixedHolder from './FixedHolder';
import type { SummaryProps } from './Footer/Summary';
import Summary from './Footer/Summary';
import {
computed,
CSSProperties,
@ -59,6 +50,10 @@ import isVisible from '../vc-util/Dom/isVisible';
import { getTargetScrollBarSize } from '../_util/getScrollBarSize';
import classNames from '../_util/classNames';
import { EventHandler } from '../_util/EventInterface';
import VCResizeObserver from '../vc-resize-observer';
import { useProvideTable } from './context/TableContext';
import { useProvideBody } from './context/BodyContext';
import { useProvideResize } from './context/ResizeContext';
// Used for conditions cache
const EMPTY_DATA = [];
@ -85,8 +80,8 @@ export interface TableProps<RecordType = unknown> extends LegacyExpandableProps<
rowClassName?: string | RowClassName<RecordType>;
// Additional Part
// title?: PanelRender<RecordType>;
// footer?: PanelRender<RecordType>;
title?: PanelRender<RecordType>;
footer?: PanelRender<RecordType>;
// summary?: (data: readonly RecordType[]) => any;
// Customize
@ -103,40 +98,14 @@ export interface TableProps<RecordType = unknown> extends LegacyExpandableProps<
expandColumnWidth?: number;
expandIconColumnIndex?: number;
// // =================================== Internal ===================================
// /**
// * @private Internal usage, may remove by refactor. Should always use `columns` instead.
// *
// * !!! DO NOT USE IN PRODUCTION ENVIRONMENT !!!
// */
// internalHooks?: string;
// /**
// * @private Internal usage, may remove by refactor. Should always use `columns` instead.
// *
// * !!! DO NOT USE IN PRODUCTION ENVIRONMENT !!!
// */
// // Used for antd table transform column with additional column
// transformColumns?: (columns: ColumnsType<RecordType>) => ColumnsType<RecordType>;
// /**
// * @private Internal usage, may remove by refactor.
// *
// * !!! DO NOT USE IN PRODUCTION ENVIRONMENT !!!
// */
// internalRefs?: {
// body: React.MutableRefObject<HTMLDivElement>;
// };
sticky?: boolean | TableSticky;
}
export default defineComponent<TableProps>({
name: 'Table',
slots: ['title', 'footer', 'summary', 'emptyText'],
inheritAttrs: false,
emits: ['expand', 'expandedRowsChange'],
setup(props, { slots, attrs, emit }) {
setup(props, { slots, emit }) {
const mergedData = computed(() => props.data || EMPTY_DATA);
const hasData = computed(() => !!mergedData.value.length);
@ -432,13 +401,58 @@ export default defineComponent<TableProps>({
const emptyNode = () => {
return hasData.value ? null : slots.emptyText?.() || 'No Data';
};
useProvideTable(
reactive({
...reactivePick(props, 'prefixCls', 'direction'),
getComponent,
scrollbarSize,
fixedInfoList: computed(() =>
flattenColumns.value.map((_, colIndex) =>
getCellFixedInfo(
colIndex,
colIndex,
flattenColumns.value,
stickyOffsets.value,
props.direction,
),
),
),
isSticky: computed(() => stickyState.value.isSticky),
summaryCollect,
}),
);
useProvideBody(
reactive({
...reactivePick(
props,
'rowClassName',
'expandedRowClassName',
'expandRowByClick',
'expandedRowRender',
'expandIconColumnIndex',
'indentSize',
),
columns,
flattenColumns,
tableLayout: mergedTableLayout,
componentWidth,
fixHeader,
fixColumn,
horizonScroll,
expandIcon: mergedExpandIcon,
expandableType,
onTriggerExpand,
}),
);
useProvideResize({
onColumnResize,
});
return () => {
const {
prefixCls,
rowClassName,
data,
rowKey,
scroll,
tableLayout,
direction,
@ -450,10 +464,8 @@ export default defineComponent<TableProps>({
// Customize
id,
showHeader,
components,
customHeaderRow,
rowExpandable,
sticky,
customRow,
} = props;
@ -648,7 +660,36 @@ export default defineComponent<TableProps>({
</div>
);
}
return null;
let fullTable = (
<div
class={classNames(prefixCls, {
[`${prefixCls}-rtl`]: direction === 'rtl',
[`${prefixCls}-ping-left`]: pingedLeft.value,
[`${prefixCls}-ping-right`]: pingedRight.value,
[`${prefixCls}-layout-fixed`]: tableLayout === 'fixed',
[`${prefixCls}-fixed-header`]: fixHeader.value,
/** No used but for compatible */
[`${prefixCls}-fixed-column`]: fixColumn.value,
[`${prefixCls}-scroll-horizontal`]: horizonScroll.value,
[`${prefixCls}-has-fix-left`]: flattenColumns.value[0] && flattenColumns.value[0].fixed,
[`${prefixCls}-has-fix-right`]:
flattenColumns.value[columnCount.value - 1] &&
flattenColumns.value[columnCount.value - 1].fixed === 'right',
})}
id={id}
ref={fullTableRef}
>
{title && <Panel class={`${prefixCls}-title`}>{title(mergedData.value)}</Panel>}
<div class={`${prefixCls}-container`}>{groupTableNode}</div>
{footer && <Panel class={`${prefixCls}-footer`}>{footer(mergedData.value)}</Panel>}
</div>
);
if (horizonScroll.value) {
fullTable = <VCResizeObserver onResize={onFullTableResize}>{fullTable}</VCResizeObserver>;
}
return fullTable;
};
},
});

View File

@ -15,6 +15,8 @@ export interface TableContextProps {
fixedInfoList: readonly FixedInfo[];
isSticky: boolean;
summaryCollect: (uniKey: string, fixed: boolean | string) => void;
}
export const BodyContextKey: InjectionKey<TableContextProps> = Symbol('TableContextProps');

View File

@ -120,7 +120,6 @@ function useColumns<RecordType>({
}: {
prefixCls?: Ref<string>;
columns?: Ref<ColumnsType<RecordType>>;
// children?: React.ReactNode;
expandable: Ref<boolean>;
expandedKeys: Ref<Set<Key>>;
getRowKey: Ref<GetRowKey<RecordType>>;
@ -134,11 +133,6 @@ function useColumns<RecordType>({
expandFixed?: Ref<FixedType>;
}): // transformColumns: (columns: ColumnsType<RecordType>) => ColumnsType<RecordType>,
[ComputedRef<ColumnsType<RecordType>>, ComputedRef<readonly ColumnType<RecordType>[]>] {
// const baseColumns = React.useMemo<ColumnsType<RecordType>>(
// () => columns || convertChildrenToColumns(children),
// [columns, children],
// );
// Add expand column
const withExpandColumns = computed<ColumnsType<RecordType>>(() => {
if (expandable.value) {

View File

@ -36,9 +36,8 @@ export type RowClassName<RecordType> = (
export interface CellType<RecordType = DefaultRecordType> {
key?: Key;
class?: string;
className?: string;
style?: CSSProperties;
children?: any;
// children?: any;
column?: ColumnsType<RecordType>[number];
colSpan?: number;
rowSpan?: number;