支持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 objectsconst list = [{ name: 'Brian Vaughn', description: 'Software engineer' }];function VirtualTable() {return (<Tablewidth={300}height={300}headerHeight={20}rowHeight={30}rowCount={list.length}rowGetter={({ index }) => list[index]}><Columnlabel='Name'dataKey='name'width={100}/><Columnwidth={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 (<MultiGridcellRenderer={cellRenderer} // 渲染的表格内容columnWidth={240} // 每列的宽度columnCount={182} // 多少列,如果有固定列,需要加上固定列fixedRowCount={1} // 固定的表头行fixedColumnCount={2} // 左侧固定的的列width={1200} // Table的宽度height={254} // Table的高度 + 滚动条的高度 14pxstyleTopLeftGrid={{ 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%" }} /><VirtualTablecolumns={columns}dataSource={list}rowKey="id"pagination={false}scroll={{ x: 300, y: 400 }}rowSelection={rowSelection}bordered/><Paginationsize="small"total={list.length}current={this.state.pageNumber}pageSize={this.state.objectsPerPage}showSizeChangerpageSizeOptions={["10", "20", "50", "1000"]}onShowSizeChange={this.onShowSizeChange.bind(this)}onChange={this.onPageChange.bind(this)}showTotal={() => `共 ${list.length} 条`}/></Fragment>);}}export default App;
