【阿里前端面试题】虚拟列表滚动组件开发的原因,以及关键技术点实现

大家好,我是“寻找DX3906”。每天进步一点。日积月累,有朝一日定会厚积薄发!
在这里插入图片描述

前言:
前面已经和大家分享阿里的了6篇前端面试题:
《【阿里前端面试题】浏览器的加载渲染过程》
《【阿里前端面试题】客户端和服务器交互,为什么选用tcp协议建立链接?》
《【阿里前端面试题】客户端和服务器交互的过程中,丢包是怎么产生的?》
《【阿里前端面试题】知道了解浏览器渲染对自己有什么帮助?》
《【阿里前端面试题】聊聊前端性能优化的方案,解决过什么样的性能问题?》
《【阿里前端面试题】前端页面懒加载的时间分片为什么能对加载性能优化?》
虚拟列表(Virtual List)是一种性能优化技术,用于渲染长列表,通过只渲染可见的列表项来减少DOM操作和提高性能。以下是使用React开发虚拟列表滚动组件的基本步骤和示例代码:

1. 基本组件结构

首先,定义一个虚拟列表组件,它接收列表数据和其他必要的props。

import React, { useState, useRef, useEffect, useCallback } from 'react';

const VirtualList = ({ itemCount, itemHeight, renderItem, overscanCount = 5 }) => {
  // ...
  return (
    <div className="virtual-list" style={{ height: '300px', overflow: 'auto' }}>
      <div
        className="virtual-list-items"
        style={{ transform: `translateY(${startIndex * itemHeight}px)` }}
      >
        {itemsToRender.map((id) => renderItem(id))}
      </div>
    </div>
  );
};

2. 使用useState和useRef

使用useState来存储当前滚动位置和渲染的列表项范围,使用useRef来引用滚动容器和滚动位置。

const [scrollPos, setScrollPos] = useState(0);
const itemsRef = useRef([]);
const listRef = useRef(null);

3. 计算可见项

根据滚动位置和列表项高度,计算当前应该渲染哪些列表项。

useEffect(() => {
  const list = listRef.current;
  const scrollTop = list.scrollTop;
  const startIndex = Math.floor(scrollTop / itemHeight);
  const endIndex = startIndex + visibleItemCount + overscanCount;
  const itemsToRender = new Array(endIndex - startIndex);

  itemsToRender.forEach((_, index) => {
    itemsToRender[index] = renderItem(startIndex + index);
  });

  setScrollPos(scrollTop);
  itemsRef.current = itemsToRender;
}, [itemCount, itemHeight]);

4. 监听滚动事件

使用useCallback来创建一个处理滚动事件的回调函数,并在组件挂载时添加滚动事件监听器,在卸载时移除。

const handleScroll = useCallback(() => {
  if (listRef.current) {
    const scrollTop = listRef.current.scrollTop;
    setScrollPos(scrollTop);
  }
}, [itemHeight]);

useEffect(() => {
  listRef.current.addEventListener('scroll', handleScroll);
  return () => {
    listRef.current.removeEventListener('scroll', handleScroll);
  };
}, [handleScroll]);

5. 样式和性能优化

确保虚拟列表和滚动容器有适当的CSS样式,使用transform属性来移动列表项,以获得更好的性能。

.virtual-list {
  position: relative;
  width: 100%;
  max-height: 300px;
  overflow: auto;
}

.virtual-list-items {
  position: absolute;
  width: 100%;
  top: 0;
  left: 0;
}

6. 完整的组件示例

将上述代码片段组合成一个完整的虚拟列表组件。

const VirtualList = ({ itemCount, itemHeight, renderItem, overscanCount = 5 }) => {
  const [scrollPos, setScrollPos] = useState(0);
  const itemsRef = useRef([]);
  const listRef = useRef(null);
  const visibleItemCount = 20; // 根据容器高度和项高度计算

  useEffect(() => {
    const list = listRef.current;
    const handleScroll = () => {
      const scrollTop = list.scrollTop;
      const startIndex = Math.floor(scrollTop / itemHeight) - overscanCount;
      const endIndex = startIndex + visibleItemCount + (2 * overscanCount);
      const itemsToRender = [];

      for (let i = startIndex; i < endIndex; i++) {
        if (i >= 0 && i < itemCount) {
          itemsToRender.push(renderItem(i));
        }
      }

      setScrollPos(scrollTop);
      itemsRef.current = itemsToRender;
    };

    list.addEventListener('scroll', handleScroll);
    return () => list.removeEventListener('scroll', handleScroll);
  }, [itemCount, itemHeight]);

  return (
    <div className="virtual-list" ref={listRef} style={{ height: '300px', overflow: 'auto' }}>
      <div
        className="virtual-list-items"
        style={{
          transform: `translateY(-${Math.floor(scrollPos / itemHeight) * itemHeight}px)`,
          position: 'absolute',
          top: 0,
        }}
      >
        {itemsRef.current.map((item, index) => (
          <div key={index}>{item}</div>
        ))}
      </div>
    </div>
  );
};

这个虚拟列表组件可以根据实际需要进行调整和扩展,例如添加动态高度支持、更复杂的项渲染逻辑等。记住,虚拟列表的关键是在保持高性能的同时,只渲染可见的列表项或近可见区域的项。

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

寻找DX3906

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值