公用代码,解决因为不一致导致的嵌套+固定列用法的样式错乱问题

This commit is contained in:
2betop 2020-12-07 17:02:06 +08:00
parent 164b2d7840
commit a7d2bbc920
3 changed files with 266 additions and 228 deletions

View File

@ -0,0 +1,196 @@
import React from 'react';
import {ClassNamesFn} from '../../theme';
import {IColumn, IRow} from '../../store/table';
import {SchemaNode, Action} from '../../types';
import {TableRow} from './TableRow';
import {filter} from '../../utils/tpl';
import {observer} from 'mobx-react';
import {trace, reaction} from 'mobx';
import {flattenTree} from '../../utils/helper';
export interface TableBodyProps {
className?: string;
rowsProps?: any;
tableClassName?: string;
classnames: ClassNamesFn;
columns: Array<IColumn>;
rows: Array<IRow>;
placeholder?: string;
render: (region: string, node: SchemaNode, props?: any) => JSX.Element;
renderCell: (
region: string,
column: IColumn,
item: IRow,
props: any
) => React.ReactNode;
onCheck: (item: IRow) => void;
onQuickChange?: (
item: IRow,
values: object,
saveImmediately?: boolean | any,
savePristine?: boolean
) => void;
footable?: boolean;
footableColumns: Array<IColumn>;
checkOnItemClick?: boolean;
buildItemProps?: (item: IRow, index: number) => any;
onAction?: (e: React.UIEvent<any>, action: Action, ctx: object) => void;
rowClassNameExpr?: string;
rowClassName?: string;
}
export class TableBody extends React.Component<TableBodyProps> {
reaction?: () => void;
constructor(props: TableBodyProps) {
super(props);
const rows = props.rows;
this.reaction = reaction(
() =>
`${flattenTree(rows)
.map(item => `${item.id}`)
.join(',')}${rows
.filter(item => item.checked)
.map(item => item.id)
.join(',')}`,
() => this.forceUpdate(),
{
onError: () => this.reaction!()
}
);
}
shouldComponentUpdate(nextProps: TableBodyProps) {
const props = this.props;
if (
props.columns !== nextProps.columns ||
props.buildItemProps !== nextProps.buildItemProps
) {
return true;
}
return false;
}
componentwillUnmount() {
this.reaction?.();
}
renderRows(
rows: Array<any>,
columns = this.props.columns,
rowProps: any = {}
): any {
const {
rowClassName,
rowClassNameExpr,
onAction,
buildItemProps,
checkOnItemClick,
classnames: cx,
render,
renderCell,
onCheck,
onQuickChange,
footable,
footableColumns
} = this.props;
return rows.map((item: IRow, rowIndex: number) => {
const itemProps = buildItemProps ? buildItemProps(item, rowIndex) : null;
const doms = [
<TableRow
{...itemProps}
classnames={cx}
checkOnItemClick={checkOnItemClick}
key={item.id}
itemIndex={rowIndex}
item={item}
itemClassName={cx(
rowClassNameExpr
? filter(rowClassNameExpr, item.data)
: rowClassName,
{
'is-last': item.depth > 1 && rowIndex === rows.length - 1
}
)}
columns={columns}
renderCell={renderCell}
render={render}
onAction={onAction}
onCheck={onCheck}
// todo 先注释 quickEditEnabled={item.depth === 1}
onQuickChange={onQuickChange}
{...rowProps}
/>
];
if (footable && footableColumns.length) {
if (item.depth === 1) {
doms.push(
<TableRow
{...itemProps}
classnames={cx}
checkOnItemClick={checkOnItemClick}
key={`foot-${item.id}`}
itemIndex={rowIndex}
item={item}
itemClassName={cx(
rowClassNameExpr
? filter(rowClassNameExpr, item.data)
: rowClassName
)}
columns={footableColumns}
renderCell={renderCell}
render={render}
onAction={onAction}
onCheck={onCheck}
footableMode
footableColSpan={columns.length}
onQuickChange={onQuickChange}
{...rowProps}
/>
);
}
} else if (item.children.length) {
// 嵌套表格
doms.push(
...this.renderRows(item.children, columns, {
...rowProps,
parent: item
})
);
}
return doms;
});
}
render() {
const {
placeholder,
classnames: cx,
className,
render,
rows,
columns,
rowsProps
} = this.props;
return (
<tbody className={className}>
{rows.length ? (
this.renderRows(rows, columns, rowsProps)
) : (
<tr className={cx('Table-placeholder')}>
<td colSpan={columns.length}>
{render('placeholder', placeholder || '暂无数据')}
</td>
</tr>
)}
</tbody>
);
}
}

View File

@ -7,6 +7,7 @@ import {filter} from '../../utils/tpl';
import {observer} from 'mobx-react'; import {observer} from 'mobx-react';
import {trace, reaction} from 'mobx'; import {trace, reaction} from 'mobx';
import {flattenTree} from '../../utils/helper'; import {flattenTree} from '../../utils/helper';
import {TableBody} from './TableBody';
export interface TableContentProps { export interface TableContentProps {
className?: string; className?: string;
@ -52,22 +53,6 @@ export class TableContent extends React.Component<TableContentProps> {
reaction?: () => void; reaction?: () => void;
constructor(props: TableContentProps) { constructor(props: TableContentProps) {
super(props); super(props);
const rows = props.rows;
this.reaction = reaction(
() =>
`${flattenTree(rows)
.map(item => `${item.id}`)
.join(',')}${rows
.filter(item => item.checked)
.map(item => item.id)
.join(',')}`,
() => this.forceUpdate(),
{
onError: () => this.reaction!()
}
);
} }
shouldComponentUpdate(nextProps: TableContentProps) { shouldComponentUpdate(nextProps: TableContentProps) {
@ -83,100 +68,6 @@ export class TableContent extends React.Component<TableContentProps> {
return false; return false;
} }
componentwillUnmount() {
this.reaction?.();
}
renderRows(
rows: Array<any>,
columns = this.props.columns,
rowProps: any = {}
): any {
const {
rowClassName,
rowClassNameExpr,
onAction,
buildItemProps,
checkOnItemClick,
classnames: cx,
render,
renderCell,
onCheck,
onQuickChange,
footable,
footableColumns
} = this.props;
return rows.map((item: IRow, rowIndex: number) => {
const itemProps = buildItemProps ? buildItemProps(item, rowIndex) : null;
const doms = [
<TableRow
{...itemProps}
classnames={cx}
checkOnItemClick={checkOnItemClick}
key={item.id}
itemIndex={rowIndex}
item={item}
itemClassName={cx(
rowClassNameExpr
? filter(rowClassNameExpr, item.data)
: rowClassName,
{
'is-last': item.depth > 1 && rowIndex === rows.length - 1
}
)}
columns={columns}
renderCell={renderCell}
render={render}
onAction={onAction}
onCheck={onCheck}
// todo 先注释 quickEditEnabled={item.depth === 1}
onQuickChange={onQuickChange}
{...rowProps}
/>
];
if (footable && footableColumns.length) {
if (item.depth === 1) {
doms.push(
<TableRow
{...itemProps}
classnames={cx}
checkOnItemClick={checkOnItemClick}
key={`foot-${item.id}`}
itemIndex={rowIndex}
item={item}
itemClassName={cx(
rowClassNameExpr
? filter(rowClassNameExpr, item.data)
: rowClassName
)}
columns={footableColumns}
renderCell={renderCell}
render={render}
onAction={onAction}
onCheck={onCheck}
footableMode
footableColSpan={columns.length}
onQuickChange={onQuickChange}
{...rowProps}
/>
);
}
} else if (item.children.length) {
// 嵌套表格
doms.push(
...this.renderRows(item.children, columns, {
...rowProps,
parent: item
})
);
}
return doms;
});
}
render() { render() {
const { const {
placeholder, placeholder,
@ -189,7 +80,17 @@ export class TableContent extends React.Component<TableContentProps> {
onScroll, onScroll,
tableRef, tableRef,
rows, rows,
renderHeadCell renderHeadCell,
renderCell,
onCheck,
rowClassName,
onQuickChange,
footable,
footableColumns,
checkOnItemClick,
buildItemProps,
onAction,
rowClassNameExpr
} = this.props; } = this.props;
const tableClassName = cx('Table-table', this.props.tableClassName); const tableClassName = cx('Table-table', this.props.tableClassName);
@ -225,17 +126,23 @@ export class TableContent extends React.Component<TableContentProps> {
)} )}
</tr> </tr>
</thead> </thead>
<tbody> <TableBody
{rows.length ? ( classnames={cx}
this.renderRows(rows, columns) placeholder={placeholder}
) : ( render={render}
<tr className={cx('Table-placeholder')}> renderCell={renderCell}
<td colSpan={columns.length}> onCheck={onCheck}
{render('placeholder', placeholder || '暂无数据')} onQuickChange={onQuickChange}
</td> footable={footable}
</tr> footableColumns={footableColumns}
)} checkOnItemClick={checkOnItemClick}
</tbody> buildItemProps={buildItemProps}
onAction={onAction}
rowClassNameExpr={rowClassNameExpr}
rowClassName={rowClassName}
rows={rows}
columns={columns}
></TableBody>
</table> </table>
</div> </div>
); );

View File

@ -40,6 +40,7 @@ import {SchemaQuickEdit} from '../QuickEdit';
import {SchemaCopyable} from '../Copyable'; import {SchemaCopyable} from '../Copyable';
import {SchemaRemark} from '../Remark'; import {SchemaRemark} from '../Remark';
import {toDataURL, getImageDimensions} from '../../utils/image'; import {toDataURL, getImageDimensions} from '../../utils/image';
import {TableBody} from './TableBody';
/** /**
* *
@ -1572,7 +1573,17 @@ export default class Table extends React.Component<TableProps, object> {
headerOnly: boolean = false, headerOnly: boolean = false,
tableClassName: string = '' tableClassName: string = ''
) { ) {
const {placeholder, store, classnames: cx, render, data} = this.props; const {
placeholder,
store,
classnames: cx,
render,
data,
checkOnItemClick,
buildItemProps,
rowClassNameExpr,
rowClassName
} = this.props;
const hideHeader = store.filteredColumns.every(column => !column.label); const hideHeader = store.filteredColumns.every(column => !column.label);
return ( return (
@ -1612,9 +1623,27 @@ export default class Table extends React.Component<TableProps, object> {
</thead> </thead>
{headerOnly ? null : ( {headerOnly ? null : (
<tbody> <TableBody
{rows.length ? ( tableClassName={cx(
this.renderRows(rows, columns, { store.combineNum > 0 ? 'Table-table--withCombine' : '',
tableClassName
)}
classnames={cx}
placeholder={placeholder}
render={render}
renderCell={this.renderCell}
onCheck={this.handleCheck}
onQuickChange={store.dragging ? undefined : this.handleQuickChange}
footable={store.footable}
footableColumns={store.footableColumns}
checkOnItemClick={checkOnItemClick}
buildItemProps={buildItemProps}
onAction={this.handleAction}
rowClassNameExpr={rowClassNameExpr}
rowClassName={rowClassName}
columns={columns}
rows={rows}
rowsProps={{
regionPrefix: 'fixed/', regionPrefix: 'fixed/',
renderCell: ( renderCell: (
region: string, region: string,
@ -1622,15 +1651,8 @@ export default class Table extends React.Component<TableProps, object> {
item: IRow, item: IRow,
props: any props: any
) => this.renderCell(region, column, item, props, true) ) => this.renderCell(region, column, item, props, true)
}) }}
) : ( />
<tr className={cx('Table-placeholder')}>
<td colSpan={columns.length}>
{render('placeholder', placeholder, {data})}
</td>
</tr>
)}
</tbody>
)} )}
</table> </table>
); );
@ -2085,93 +2107,6 @@ export default class Table extends React.Component<TableProps, object> {
: footerNode || toolbarNode || null; : footerNode || toolbarNode || null;
} }
renderRows(
rows: Array<any>,
columns = this.props.store.filteredColumns,
rowProps: any = {}
): any {
const {
store,
rowClassName,
rowClassNameExpr,
onAction,
buildItemProps,
checkOnItemClick,
classPrefix: ns,
classnames: cx,
render
} = this.props;
return rows.map((item: IRow, rowIndex: number) => {
const itemProps = buildItemProps ? buildItemProps(item, rowIndex) : null;
const doms = [
<TableRow
{...itemProps}
classPrefix={ns}
classnames={cx}
checkOnItemClick={checkOnItemClick}
key={item.id}
itemIndex={rowIndex}
item={item}
itemClassName={cx(
rowClassNameExpr
? filter(rowClassNameExpr, item.data)
: rowClassName,
{
'is-last': item.depth > 1 && rowIndex === rows.length - 1,
'is-expanded': item.expanded,
'is-expandable': item.expandable
}
)}
columns={columns}
renderCell={this.renderCell}
render={render}
onAction={onAction}
onCheck={this.handleCheck}
// todo 先注释 quickEditEnabled={item.depth === 1}
onQuickChange={store.dragging ? null : this.handleQuickChange}
{...rowProps}
/>
];
if (store.footable && store.footableColumns.length) {
if (item.depth === 1) {
doms.push(
<TableRow
{...itemProps}
classPrefix={ns}
classnames={cx}
checkOnItemClick={checkOnItemClick}
key={`foot-${item.id}`}
itemIndex={rowIndex}
item={item}
itemClassName={cx(
rowClassNameExpr
? filter(rowClassNameExpr, item.data)
: rowClassName
)}
columns={store.footableColumns}
renderCell={this.renderCell}
render={render}
onAction={onAction}
onCheck={this.handleCheck}
footableMode
footableColSpan={store.filteredColumns.length}
onQuickChange={store.dragging ? null : this.handleQuickChange}
{...rowProps}
/>
);
}
} else if (Array.isArray(item.data.children)) {
// 嵌套表格
doms.push(...this.renderRows(item.children, columns, rowProps));
}
return doms;
});
}
renderItemActions() { renderItemActions() {
const {itemActions, render, store, classnames: cx} = this.props; const {itemActions, render, store, classnames: cx} = this.props;
const finalActions = Array.isArray(itemActions) const finalActions = Array.isArray(itemActions)