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, ${currentOffset}px, 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 * itemHeight}px`}}></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;
}

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Antd Table 是 Ant Design 框架中的一个表格组件,而 react-window 则是一个能够帮助 React 应用中高效渲染大量数据的组件。使用 react-window 能够减少因为渲染大量数据而导致页面卡顿的情况,提升用户的使用体验。 如果你希望在 Antd Table 中使用 react-window 的虚拟列表功能,可以先安装 react-window: ``` npm install react-window ``` 然后,在 Antd Table 中使用 react-window 的虚拟列表功能,需要进行如下操作: 1. 引入 react-window 库中的 List 组件 2. 在 columns 配置项中,设置 fixed 属性,以确保表头的列不会被虚拟化 3. 在 dataSource 中,只保留当前可见区域的数据,而不是全部数据。 下面是一个 Antd Table 中使用 react-window 的示例代码: ```jsx import { Table } from 'antd'; import { List } from 'react-window'; const VirtualTable = props => { const { columns, dataSource } = props; const renderRow = ({ index, style }) => { const rowData = dataSource[index]; return ( <div style={style}> <Table.Row key={rowData.key} record={rowData} index={index} columns={columns} /> </div> ); }; return ( <Table {...props} columns={columns.map(column => ({ ...column, fixed: column.fixed || 'left', }))} pagination={false} components={{ body: ({ children, ...restProps }) => { return ( <List height={400} itemCount={dataSource.length} itemSize={54} width={1000} {...restProps} > {renderRow} </List> ); }, }} /> ); }; export default VirtualTable; ``` 在上述代码中,我们将 Antd Table 包装在一个名为 VirtualTable 的组件中,该组件使用 react-window 的 List 组件来渲染表格数据。其中,itemCount 和 itemSize 属性分别设置了数据总数和每一行的高度,height 和 width 属性则分别设置了表格的高度和宽度。在 renderRow 函数中,我们根据当前的 index 和 style 来渲染每一行的数据。最后,我们将 List 组件作为 Antd Table 的 body 组件,以实现虚拟列表的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值