React实现虚拟列表

Posted 不想掉头发啊!!

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React实现虚拟列表相关的知识,希望对你有一定的参考价值。

/*
思路:
1.通过 useRef 获取元素,缓存变量。
2.useEffect 初始化计算容器的高度。截取初始化列表长度。这里需要 div 占位,撑起滚动条。
3.通过监听滚动容器的 onScroll 事件,根据 scrollTop 来计算渲染区域向上偏移量, 这里需要注意的是,当用户向下滑动的时候,为了渲染区域,能在可视区域内,可视区域要向上滚动;当用户向上滑动的时候,可视区域要向下滚动。
4.通过重新计算 end 和 start 来重新渲染列表。
*/
const App = () => 
    const content = useRef(null)
    const scrollBox = useRef(null)
    const scrollList = useRef(null)
    const [data, setData] = useState([])
    const [start, setStart] = useState(0)
    const [end, setEnd] = useState(0)
    const scrollInfo = useRef(
        boxHeight: 500,
        itemHeight: 50,
        renderCount: 0,
        bufferSize: 8
    )

    useEffect(() => 
        // 获取数据
        const res = new Array(2000).fill(1).map((item, index) => item + index)
        setData(res)
        // 获取渲染的个数
        const itemHeight, boxHeight, bufferSize = scrollInfo.current
        const renderCount = Math.ceil(boxHeight / itemHeight) + bufferSize
        scrollInfo.current.renderCount = renderCount
        // 获取首次渲染时截取数据的索引
        setEnd(renderCount)
    , [])

    // 处理滚动
    const handleScroll = () => 
        const itemHeight, boxHeight, bufferSize, renderCount = scrollInfo.current
        // 获取元素中的内容”超出“元素上边界”的高度
        const scrollTop = scrollBox.current
        // 获取开始截取数据的值
        const bufferVal = bufferSize / 2
        const newStartIndex = Math.floor(scrollTop / itemHeight)
        // 获取结束截取的数据的值
        const newEndIndex = newStartIndex + renderCount
        // 如果发生变化,那么就重新渲染
        if (newEndIndex !== end || newStartIndex !== start) 
            setStart(newStartIndex)
            setEnd(newEndIndex)
        
        const currentOffset = scrollTop - (scrollTop % itemHeight)
        scrollList.current.style.transform = `translate3d(0, $currentOffsetpx, 0)` /* 偏移,造成下滑效果 */
    
    // 对数据进行截取进行渲染
    const renderList = data.slice(start, end)
    const itemHeight = scrollInfo.current
    return <div ref=content>
        <div ref=scrollBox className="scroll_box" onScroll=handleScroll>
            /* 撑开div 让其滚动 */
            <div className="scroll_hold" style=height: `$data.length * itemHeightpx`></div>
            <ul className="list" ref=scrollList>
                
                    renderList.map(item => <li key=item style=height: '50px'>item</li>)
                
            </ul>
        </div>
    </div>

.scroll_box 
    overflow-y: scroll;
    position: relative;
    height: 500px;


.scroll_hold 
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    z-index: -1;


.list
    position: absolute;
    left: 0;
    right: 0;
    top: 0;


li
    width: 100%;
    list-style: none;
    padding: 5px;


以上是关于React实现虚拟列表的主要内容,如果未能解决你的问题,请参考以下文章

React实现虚拟列表

React实现虚拟列表

高德地图判断点的位置是否在浏览器可视区域内

React懒加载组件实现

前端性能优化分析

js实现可视化区域内拖拽