支持5中滚动类型
- Table 基于Grid来实现,表格具有固定的头部,并且可以在垂直方向上滚动
- Grid 构建任意网状的结构,传入一个二维的数组,渲染出类似棋盘的结构
- List 列表,一个维的列表,横向滚动,X轴 & 竖向滚动,Y轴
- Masonry 卡片效果
- 可以在水平方向,也可以在垂直方向滚动
- 不同于Grid的是可以自定义每个元素的大小,或者子元素的大小也可以是动态变化的
- Collection 瀑布流
- 类似于瀑布流的形式,同样可以水平和垂直方向滚动
https://github.com/bvaughn/react-virtualized
虚拟滚动demo https://codesandbox.io/examples/package/react-virtualized
https://css-tricks.com/rendering-lists-using-react-virtualized/
https://segmentfault.com/a/1190000017233625
npm install react-virtualized
- 缺点:不支持子元素的动态高度或者宽度,只支持固定的宽高
Table
Table案例 https://bvaughn.github.io/react-virtualized/#/components/Table
Table文档 https://github.com/bvaughn/react-virtualized/blob/master/docs/Table.md
import React from 'react';
import { Column, Table } from 'react-virtualized';
import 'react-virtualized/styles.css'; // only needs to be imported once
// Table data as an array of objects
const list = [
{ name: 'Brian Vaughn', description: 'Software engineer' }
];
function VirtualTable() {
return (
<Table
width={300}
height={300}
headerHeight={20}
rowHeight={30}
rowCount={list.length}
rowGetter={({ index }) => list[index]}
>
<Column
label='Name'
dataKey='name'
width={100}
/>
<Column
width={200}
label='Description'
dataKey='description'
/>
</Table>
);
};
export default VirtualTable
Grid
https://bvaughn.github.io/react-virtualized/#/components/Grid
MultiGrid
多列固定虚拟滚动
import React from 'react';
import PropTypes from 'prop-types';
import moment from 'moment';
import { MultiGrid } from 'react-virtualized';
import styles from "./style.less";
const subChild = () => {
const arr = ['成绩', '科目'];
return arr.map(item => <div key={item} className='flex-1'>{item}</div>);
};
App.propTypes = {
data: PropTypes.array.isrequired,
}
function App({ data }) {
// 固定表头
function getThead(columnIndex) {
const { values } = data[0] || {};
if (columnIndex < 2) {
const arr = ['INFO', '机刷'];
return arr[columnIndex];
};
if (values) {
const thead = values.map((item, i) => {
const [time] = item;
return moment(time).format('HH:mm');
});
return (
<>
<div style={{ borderBottom: '1px solid #ddd' }}>{thead[columnIndex]}</div>
<div className="flex">{subChild()}</div>
</>
);
}
}
// 固定左侧的列
function getColumns(columnIndex, rowIndex) {
const { keys } = data[rowIndex - 1];
if (columnIndex > 1) return;
return keys[columnIndex];
}
// 表格的内容
function getTbody(columnIndex, rowIndex) {
const { values } = data[rowIndex - 1];
const columns = values[columnIndex - 2];
return columns.map((item, i) => {
if (i < 3) return null;
return <div className='flex-1'>{item ? item : '-'}</div>;
});
}
function cellRenderer({ columnIndex, key, rowIndex, style }) {
// 渲染表头
if (rowIndex === 0) {
return (
<div className={styles.Cell} key={key} style={{ ...style, height: 80 }}>
{getThead(columnIndex)}
</div>
);
}
// 固定左侧2列
if (columnIndex < 2) {
return (
<div className={styles.Cell} key={key} style={style}>
{getColumns(columnIndex, rowIndex)}, {rowIndex}
</div>
);
}
return (
<div className={styles.Cell} key={key} style={style}>
<div className="flex">{getTbody(columnIndex, rowIndex)}</div>
</div>
);
}
return (
<MultiGrid
cellRenderer={cellRenderer} // 渲染的表格内容
columnWidth={240} // 每列的宽度
columnCount={182} // 多少列,如果有固定列,需要加上固定列
fixedRowCount={1} // 固定的表头行
fixedColumnCount={2} // 左侧固定的的列
width={1200} // Table的宽度
height={254} // Table的高度 + 滚动条的高度 14px
styleTopLeftGrid={{ height: 80 }}
styleTopRightGrid={{ height: 80 }}
rowHeight={40} // 一行的高度
rowCount={5} // 多少行
hideTopRightGridScrollbar={true}
/>
);
}
export default App;
List
https://bvaughn.github.io/react-virtualized/#/components/List
列表滚动demo https://codesandbox.io/s/sckvn
Collection
https://bvaughn.github.io/react-virtualized/#/components/Collection
antd-table-virtual
https://github.com/ctq123/ant-virtual-table
https://judes.me/frontend/2019/09/17/infinite-table.html
https://www.daimajiaoliu.com/daima/4723be904900405
import React, { PureComponent, Fragment } from "react";
import { VirtualTable } from "ant-virtual-table";
import { Pagination } from "antd";
import "antd/dist/antd.css";
const columns = [
{
title: "序号",
dataIndex: "id",
// fixed: 'left',
width: 100
},
{
title: "姓名",
dataIndex: "name",
width: 150
},
{
title: "年龄",
dataIndex: "age",
width: 100,
sorter: (a, b) => a.age - b.age,
},
{
title: "性别",
dataIndex: "sex",
width: 100,
render: text => {
return text === "male" ? "男" : "女";
}
}
];
function generateData(count) {
const res = [];
const names = ["Tom", "Marry", "Jack", "Lorry", "Tanken", "Salla"];
const sexs = ["male", "female"];
for (let i = 0; i < count; i++) {
let obj = {
id: i,
name: names[i % names.length] + i,
sex: sexs[i % sexs.length],
age: 15 + Math.round(10 * Math.random())
};
res.push(obj);
}
return res;
}
const dataSource = generateData(10000);
class App extends PureComponent {
constructor(props) {
super(props);
this.state = {
pageNumber: 1,
objectsPerPage: 10,
list: dataSource
};
}
// 改变页面数字第几页发起的请求
onPageChange(pageNumber) {
this.setState({
pageNumber
});
}
// 改变页面显示条数发起的请求
onShowSizeChange(current, objectsPerPage) {
const list = dataSource.slice(
(current - 1) * objectsPerPage,
objectsPerPage
);
this.setState({
list,
pageNumber: current,
objectsPerPage
});
}
onChange = (selectedRowKeys, selectedRows) => {
console.log(
`onChange selectedRowKeys: ${selectedRowKeys}`,
"selectedRows: ",
selectedRows
);
};
onSelect = (record, selected, selectedRows, nativeEvent) => {
console.log(
`onSelect record: ${record} selected: ${selected}`,
"selectedRows: ",
selectedRows
);
};
onSelectAll = (selected, selectedRows) => {
console.log(
`onSelectAll selected: ${selected}`,
"selectedRows: ",
selectedRows
);
};
render() {
const { list = [] } = this.state;
const rowSelection = {
onChange: this.onChange,
onSelect: this.onSelect,
onSelectAll: this.onSelectAll
};
return (
<Fragment>
<div style={{ height: 30, width: "100%" }} />
<VirtualTable
columns={columns}
dataSource={list}
rowKey="id"
pagination={false}
scroll={{ x: 300, y: 400 }}
rowSelection={rowSelection}
bordered
/>
<Pagination
size="small"
total={list.length}
current={this.state.pageNumber}
pageSize={this.state.objectsPerPage}
showSizeChanger
pageSizeOptions={["10", "20", "50", "1000"]}
onShowSizeChange={this.onShowSizeChange.bind(this)}
onChange={this.onPageChange.bind(this)}
showTotal={() => `共 ${list.length} 条`}
/>
</Fragment>
);
}
}
export default App;