react-window 固定列参考
https://codesandbox.io/s/0mk3qwpl4l?file=/src/index.js:0-1735
antd Table3x https://github.com/ctq123/ant-virtual-table
antd Table4x https://ant.design/components/table/#components-table-demo-virtual-list
https://github.com/wubostc/virtualized-table-for-antd
缺点:
- 点击排序会自动刷新表格
- innerElementType就是 sticky的列;固定列要和滚动的列分开 ```jsx import React, {memo, useState, createContext, forwardRef} from ‘react’; import PropTypes from ‘prop-types’; import {VariableSizeList as List} from ‘react-window’; import AutoSizer from ‘react-virtualized-auto-sizer’; import {Icon} from ‘antd’; import classNames from ‘classnames’;
const Context = createContext();
VirtualTable.propTypes = { dataSource: PropTypes.array.isRequired, };
function VirtualTable({dataSource}) { const [sortIcon, setSortIcon] = useState(‘caret-up’); const children = childrenColumns([{label: ‘综合’, value: 0}, {label: ‘评价’, value: 1}]); const {length} = dataSource
// 数组第一个 values遍历生成表头 const {values} = dataSource[0] || {}; const columns = getColumns({values, children, onClick}); if (dataSource.length) { columns.unshift(…mapColumns([‘学科’, ‘成绩’])); }
function onClick(value) { console.log(‘click’, value) }
function onSort({index, colIndex}) { setSortIcon(prev => { return prev === ‘caret-up’ ? ‘caret-down’ : ‘caret-up’; });
setTimeout(() => {
dataSource.sort((a, b) => {
const item = a.values[colIndex][index]
const bitem = b.values[colIndex][index]
return (sortIcon === 'caret-up') ? bitem - item : item - bitem;
})
}, 0)
}
function RenderThead({item, index}) { if (!item.children) { const style = {height: 81, lineHeight: ‘80px’, padding: 8} return (
function onClick({e, ...value}) {
onSort(value)
e.currentTarget.classList.add('on')
}
return (
<div className='tr'>
<div className='tr-first'>{item.name}</div>
<div className="flex">
{
item.children.map((child, i) => {
if (!child.name) return null
return (
<div className='th flex-1' key={`${index}-${i}-thead`}>
{child.name}
<Icon
type={sortIcon}
className='sort-icon'
onClick={(e) => onClick({e, index: i, child, colIndex: index})}
/>
</div>
)
})
}
</div>
</div>
)
}
function RenderTbody({index}) { return dataSource.map((item, i) => { const {keys, values} = item; const {length = 0} = keys;
const oddClass = classNames({
tr: true,
flex: true,
odd: i % 2 === 0
});
if (index < length) {
return (
<div className={oddClass}>
<div className='flex-1'>{keys[index]}</div>
</div>
)
}
const colItem = values[index - length]
if (!colItem) return (
<div className={oddClass}>
<div className='flex-1' />
</div>
);
const [time, a, b, c, ...args] = colItem;
return (
<div className={oddClass}>
{args.map((item, i) => {
return (
<div
key={`${index}-${i}`}
className='flex-1'
onClick={() => onClick({index: i, time})}
>
{item === null ? '' : item}
</div>
)
})}
</div>
);
})
}
function Column(value) { const {index, style} = value; const item = columns[index]; if (!item) return null;
return (
<div style={style}>
<RenderThead index={index} item={item}/>
<RenderTbody index={index}/>
</div>
)
}
const ItemWrapper = ({data, index, style}) => {
const {ItemRenderer, stickyIndices} = data;
// 过滤掉固定的行
if (stickyIndices && stickyIndices.includes(index)) {
return null;
}
return
function StickyList(props) {
const {children, stickyIndices, …rest} = props;
return (
{ItemWrapper}
// 固定的行 const StickyRow = ({index}) => { console.log(12, index) const item = columns[index]; if (!item) return null;
const _style = {height: 81, lineHeight: '80px', padding: 8}
return (
<div style={{float: 'left', width: '50%'}}>
<div className='tr' style={_style}>
{item.name}
</div>
<RenderTbody index={index}/>
</div>
)
};
const innerElementType = forwardRef(({children, …rest}, ref) => {
return (
return (
export default memo(VirtualTable);
// 固定左侧表头 function mapColumns(dataSource) { return dataSource.map((key, i) => ({ name: key, key: ‘keys’, })); }
// children 表头 function childrenColumns(dataSource) { return dataSource.map(({label}, i) => ({ name: label, index: i, key: ‘values’, })); }
// 遍历数组第一个values生成表头 function getColumns({values, children}) { return values.map(([time], i) => { return { name: toHours(time), children, }; }); }
RenderCell
```jsx
function RenderCell({ className, value = '' }) {
return (
<div className={className}>
<div className='flex-1'>{value}</div>
</div>
);
}
数据格式
[
{
keys: ['标题', '描述'],
values: [{time: 1628148180000, title: '', desc: '', value: 100}]
},
{
keys: ['标题', '描述'],
values: [{time: 1628148190000, title: '', desc: '', value: 100}]
},
]