transform: translate3d(x,y,z) 代替 position: absolute定位实现虚拟滚动
- 不能把 transform加到 height=40000的 div上面,会出现滚动条【无法滚动到低的Bug】
FixedSizeList
import React, { useState, useEffect, useRef } from 'react';import PropTypes from 'prop-types';import classNames from 'classnames';FixedSizeList.propTypes = {width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),height: PropTypes.number,itemSize: PropTypes.number,itemCount: PropTypes.number,className: PropTypes.string,};function FixedSizeList(props) {const { width, height, itemSize, itemCount, className, children } = props;const rootRef = useRef(null);const [scrollTop, setScrollTop] = useState(0);// 要显示的元素起始和结束索引const [startIndex, setStartIndex] = useState(0);const CHILDREN = [];// 可视区显示多少个const pageSize = Math.ceil(height / itemSize);const endIndex = startIndex + pageSize;useEffect(init, []);function init() {const el = rootRef.current;el.addEventListener('scroll', onScroll);return () => {el.removeEventListener('scroll', onScroll);};}// 滚动时,重新计算开始的索引function onScroll(e) {let { scrollTop } = e.target;const _endIndex = itemCount - endIndex;// 起始值要向下取整let index = Math.floor(scrollTop / itemSize);if (index >= _endIndex) index = _endIndex;setStartIndex(index);setScrollTop(scrollTop);console.log('e', scrollTop, scrollTop % itemSize, index);}const style = { width: '100%', height: itemSize };for (let i = startIndex; i < endIndex; i++) {CHILDREN.push(children({ index: i, style }));}const rootClass = classNames({[classNames]: Boolean(className)});const rootStyle = { width, height, position: 'relative', overflow: 'auto' };// 核心style,设置滚动时的高度const transformStyle = {transform: `translate3d(0, ${scrollTop}px, 0)`,transition: 'transform 60ms linear',willChange: 'transform',};return (<divstyle={rootStyle}ref={rootRef}className={rootClass}><div style={{ height: itemSize * itemCount }}><div style={transformStyle}>{CHILDREN}</div></div></div>);}export default FixedSizeList
index.less
:global {.odd {background-color: rgba(156, 179, 197, 0.26);}.scrollbar{&::-webkit-scrollbar{width:8px;}&::-webkit-scrollbar-track{background-color: #fafafa;border-radius: 4px;}// 滚动部分的样式&::-webkit-scrollbar-thumb{background-color: rgba(0, 0, 0, 0.45);border-radius: 8px;transition: background-color 300ms linear;&:hover {background-color: rgba(0, 0, 0, 0.65)}}// 2个滚动条对齐的样式&::-webkit-scrollbar-corner{background-color: rgba(187,187,187, 1);}}}
