Sobald Sie das Prinzip verstanden haben, wird es einfacher, Code zu schreiben.
components/ScrollableTable/interface.tsx
import * as React from 'react';
export declare type AlignType = 'left' | 'center' | 'right';
export interface ColumnType {
align?: AlignType;
className?: string;
dataKey?: string;
fixed?: boolean;
title?: React.ReactNode;
width?: number;
render?: (value: any, record: any, index: number) => React.ReactNode;
}
export interface TableProps {
className?: string;
style?: React.CSSProperties;
columns?: ColumnType[];
dataSource?: any[];
width?: number;
height?: number;
}
components/ScrollableTable/index.tsx
import React, { FunctionComponent, useRef } from 'react';
import { TableProps, ColumnType } from './interface';
import './index.less';
const ScrollableTable: FunctionComponent<any> = (props: TableProps) => {
const style: React.CSSProperties = props.style || {};
const maxHeight: string = props.width ? (props.height + 'px') : 'unset';
const columns: ColumnType[] = props.columns || [];
const dataSource: any[] = props.dataSource || [];
let maxWidth: number = 0;
if (props.width) style.width = props.width;
if (columns.length === 0) {
columns.push({
dataKey: 'key'
});
}
columns.forEach((column: ColumnType) => {
const width: number = column.width || 50;
maxWidth += width;
});
const fixedColumns: number[][] = getFixedColumns(columns);
const leftFixedColumns: number[] = fixedColumns[0];
const rightFixedColumns: number[] = fixedColumns[1];
const tableBody: any = useRef();
const handleScroll = (target: any) => {
const scrollLeft: number = target.scrollLeft;
const tableHeaders: any = target.parentElement.getElementsByClassName('st-table-header');
if (tableHeaders.length > 0) {
tableHeaders[0].scrollLeft = scrollLeft;
}
};
return (
<div
className={classNames('st-table-container', props.className)}
style={style}
>
<div className="st-table-header">
<table>
<colgroup>
{
renderCols(columns)
}
</colgroup>
<thead className="st-table-thead">
<tr>
{
columns.map((column: ColumnType, index: number) => {
const align: any = column.align || undefined;
const title: React.ReactNode = column.title || '';
const fixed: string = leftFixedColumns.includes(index) ? 'left' : (rightFixedColumns.includes(index) ? 'right' : '');
const fixedClassName: string = fixed ? ('st-table-cell-fix-' + fixed) : '';
return (
<th
key={index}
className={classNames('st-table-cell', fixedClassName, column.className)}
style={{textAlign: align}}
>
{title}
</th>
);
})
}
</tr>
</thead>
</table>
</div>
<div
ref={tableBody}
className="st-table-body"
style={{maxHeight: maxHeight}}
onScroll={(e: any) => handleScroll(e.currentTarget)}
>
<table style={{width: maxWidth, minWidth: '100%'}}>
<colgroup>
{
renderCols(columns)
}
</colgroup>
<tbody className="st-table-tbody">
{
dataSource.map((record: any, index: number) => (
<tr key={index} className="st-table-row">
{
renderCells(columns, leftFixedColumns, rightFixedColumns, record, index)
}
</tr>
))
}
</tbody>
</table>
</div>
</div>
);
};
function classNames(...names: (string | undefined)[]) {
const currentNames: string[] = [];
names.forEach((name: (string | undefined)) => {
if (name) currentNames.push(name);
});
return currentNames.join(' ');
}
function getFixedColumns(columns: ColumnType[]) {
const total: number = columns.length;
const leftFixedColumns: number[] = [];
const rightFixedColumns: number[] = [];
if (columns[0].fixed) {
for (let i = 0; i < total; i++) {
if (columns[i].fixed) {
leftFixedColumns.push(i);
} else {
break;
}
}
}
if (columns[total - 1].fixed) {
for (let i = total - 1; i >= 0; i--) {
if (columns[i].fixed) {
if (!leftFixedColumns.includes(i)) rightFixedColumns.push(i);
} else {
break;
}
}
}
return [leftFixedColumns, rightFixedColumns];
}
function renderCols(columns: ColumnType[]) {
return columns.map((column: ColumnType, index: number) => {
const width: number = column.width || 50;
return (
<col
key={index}
style={{width: width, minWidth: width}}
/>
);
});
}
function renderCells(columns: ColumnType[], leftFixedColumns: number[], rightFixedColumns: number[], record: any, index: number) {
return columns.map((column: ColumnType, index: number) => {
const align: any = column.align || undefined;
const fixed: string = leftFixedColumns.includes(index) ? 'left' : (rightFixedColumns.includes(index) ? 'right' : '');
const className: string = classNames('st-table-cell', column.className, fixed ? ('st-table-cell-fix-' + fixed) : '');
const rawValue: any = (column.dataKey && column.dataKey in record) ? record[column.dataKey] : undefined;
let value: any = undefined;
if (column.render) {
value = column.render(rawValue, record, index);
} else {
value = (rawValue === undefined || rawValue === null) ? '' : String(rawValue);
}
return (
<td
key={index}
className={className}
style={{textAlign: align}}
>
{value}
</td>
);
});
}
export default ScrollableTable;
components/ScrollableTable/index.less
.st-table-container {
border: 1px solid #f0f0f0;
border-right: 0;
border-bottom: 0;
font-size: 14px;
.st-table-header {
border-right: 1px solid #f0f0f0;
overflow: hidden;
table {
border-collapse: separate;
border-spacing: 0;
table-layout: fixed;
width: 100%;
thead.st-table-thead {
tr {
th.st-table-cell {
background: #fafafa;
border-bottom: 1px solid #f0f0f0;
border-right: 1px solid #f0f0f0;
color: rgba(0, 0, 0, .85);
font-weight: 500;
padding: 8px;
text-align: left;
&:last-child {
border-right: 0;
}
}
}
}
}
}
.st-table-body {
overflow: auto scroll;
border-bottom: 1px solid #f0f0f0;
border-right: 1px solid #f0f0f0;
table {
border-collapse: separate;
border-spacing: 0;
table-layout: fixed;
tbody.st-table-tbody {
tr.st-table-row {
td.st-table-cell {
border-bottom: 1px solid #f0f0f0;
border-right: 1px solid #f0f0f0;
color: rgba(0, 0, 0, .65);
padding: 8px;
text-align: left;
&:last-child {
border-right: 0;
}
}
&:last-child {
td.st-table-cell {
border-bottom: 0;
}
}
}
}
}
}
table {
.st-table-cell {
&.st-table-cell-fix-left {
background: #fff;
position: sticky;
left: 0;
z-index: 2;
}
&.st-table-cell-fix-right {
background: #fff;
position: sticky;
right: 0;
z-index: 2;
}
}
}
}
Nach dem Login kopieren
views/Test/index.tsx
import React, { FunctionComponent } from 'react';
import Page from '../../components/Page';
import ScrollableTable from '../../components/ScrollableTable';
import StoreProvider from '../../stores/products/context';
import './index.less';
const Test: FunctionComponent<any> = (props: any) => {
let records: any[] = [{
id: 1,
productName: '淡泰',
amount1: 198,
amount2: 200,
amount3: 205.5,
currency: '人民币',
ca: 'Amy'
}, {
productName: '方润',
amount1: 105.5,
amount2: 100,
amount3: 108,
currency: '港元',
ca: 'Baby'
}, {
productName: '医疗基金-1',
amount1: 153,
amount2: 150,
amount3: 155,
currency: '人民币',
ca: 'Emily'
}, {
productName: '医疗基金-2',
amount1: 302,
amount2: 300,
amount3: 290,
currency: '美元',
ca: 'Baby'
}, {
productName: '医疗基金-3',
amount1: 108.8,
amount2: 100,
amount3: 130,
currency: '人民币',
ca: 'Amy'
}, {
productName: '医疗基金-4',
amount1: 205,
amount2: 200,
amount3: 208,
currency: '美元',
ca: '吴丹'
}, {
productName: '医疗基金-5',
amount1: 315.5,
amount2: 300,
amount3: 280,
currency: '人民币',
ca: 'Baby'
}, {
productName: '医疗基金-6',
amount1: 109,
amount2: 95,
amount3: 106,
currency: '人民币',
ca: 'Emily'
}, {
productName: '恒大私募债',
amount1: 213,
amount2: 200,
amount3: 208,
currency: '港元',
ca: '吴丹'
}];
const totalRecord: any = {
productName: '合计',
amount1: {},
amount2: {},
amount3: {}
};
records.forEach((record: any) => {
const currency: string = record.currency;
['amount1', 'amount2', 'amount3'].forEach((key: string) => {
const value: any = totalRecord[key];
if (!(currency in value)) value[currency] = 0;
value[currency] += record[key];
});
});
records.push(totalRecord);
const columns: any[] = [{
dataKey: 'productName',
title: '产品名称',
width: 90,
fixed: true
}, {
dataKey: 'amount1',
title: <React.Fragment>上周缴款金额<br/>(万)</React.Fragment>,
width: 140,
align: 'center',
className: 'amount',
render: calculateTotal
}, {
dataKey: 'amount2',
title: <React.Fragment>上周预约金额<br/>(万)</React.Fragment>,
width: 140,
align: 'center',
className: 'amount',
render: calculateTotal
}, {
dataKey: 'amount3',
title: <React.Fragment>待本周跟进金额<br/>(万)</React.Fragment>,
width: 140,
align: 'center',
className: 'amount',
render: calculateTotal
}, {
dataKey: 'currency',
title: '币种',
width: 80
}, {
dataKey: 'ca',
title: 'CA',
width: 80
}];
return (
<StoreProvider>
<Page
{...props}
title="销售统计"
className="test"
>
<div style={{padding: 15}}>
<ScrollableTable
width={window.innerWidth - 30}
height={196}
columns={columns}
dataSource={records}
/>
</div>
</Page>
</StoreProvider>
);
};
function calculateTotal(value: any) {
if (value instanceof Object) {
const keys: any[] = Object.keys(value);
return (
<React.Fragment>
{
keys.map((key: string, index: number) => (
<span key={index}>
{`${value[key].toFixed(2)}万${key}`}
</span>
))
}
</React.Fragment>
)
}
return value.toFixed(2);
}
export default Test;
views/Test/index.less
.st-table-container {
.st-table-body {
td.st-table-cell.amount {
padding-right: 20px !important;
text-align: right !important;
span {
display: block;
}
}
}
}
Nach dem Login kopieren
Das obige ist der detaillierte Inhalt vonSo erreichen Sie die Tabellenkopffixierung in React. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!