笔者在之前的面试中遇到了“我一次性给你1万条数据,如何让它不卡顿”的问题。要回答这类问题,提到的解决方案过于简单,还涉及到防抖、节流等性能优化点。这篇文章原计划写在2022年1月29日,但是因为春节的缘故推迟了。发现有3种方案:虚拟列表(也叫按需渲染或者可见区域渲染)延迟渲染(也就是惰性渲染)时间分片虚拟列表是最主流的方案,不渲染所有数据,只渲染区域内可见的数据。当用户滑动(滚动)时,监听滚动判断是向上滑动还是向下滑动,从而更新数据。同样,IntersectionObserver和getBoundingClientRect都可以实现延迟渲染,也就是所谓的延迟加载。顾名思义,一开始并不渲染所有数据,只渲染可视区域的数据(与虚拟列表一致)。滚动到页面底部时,添加数据(concat),添加DOM进行视图渲染。时间分片主要是批量渲染DOM,使用requestAnimationFrame让动画更流畅。先说最主流的解决方案虚榜。什么是虚拟列表?按需显示的一种实现方式,即只渲染可见区域,不渲染或部分渲染不可见区域的数据。是一种针对长列表渲染的优化方法。就是显示可见区域。上下滚动时,通过DOMAPI替换可见区域的数据,从而动态加载10万条数据。两种解决方案关于无限滚动,最常见的解决方案是在早期计划中监听滚动事件。可以去图片懒加载查看。简单来说就是通过子项的offsetTop(偏移高度)与innerHeight(窗口高度)+scrollTop(滚动高度)的比较来实现的。当偏移高度<窗口高度+滚动高度时,描述已经滚动到底部,可以显示图片。在图片的懒加载中,我们也提到了IntersectionObserver(交叉观察者)API来解决scroll没有的效果,即IntersectionObserverAPI是异步的,不跟随目标元素。滚动是同步触发的,性能消耗小。当然也可以通过getBoundingClientRect来实现。getBoundingClientRect方法返回元素的大小和机器相对于窗口的位置。PS:所以目前有3种方法,单独使用这三种方案的代码会在文末的demo中附在这里,所以我的力量有限,并没有解决getBoundingClientRect时页面抖动的问题向上滑动。解决方案只有两种:scroll和IntersectionObserver(getBoundingClientRect方法也放在代码里,但是向上滑动会晃动),就是将它发送过来的数据拆分显示,使用slice方法,会返回一个新的数组。我们假设单个列表的高度为30px,页面显示的列表个数为constcount=Math.ceil(listheight/30),显示的数据为visibleData=data.slice(start,start+count)(start开始为0)滚动时,动态修改start和visibleDataimportconst[开始,setStart]=useState(0);const[visibleCount,setVisibleCount]=useState(null);const[visibleData,setVisibleData]=useState([]);constvirtualRef=useRef(null);constvirtualContentRef=useRef(null);useEffect(()=>{constcount=Math.ceil(virtualRef.current.clientHeight/30);setVisibleCount(count);setVisibleData(data.slice(start,start+count));},[]);constonHandleScroll=()=>{constscrollTop=virtualRef.current.scrollTop;constfixedScrollTop=scrollTop-(scrollTop%30);virtualContentRef.current.style.webkitTransform=`translate3d(0,${fixedScrollTop}px,0)`;setStart(Math.floor(scrollTop/30));setVisibleData(data.slice(start,start+visibleCount));};返回(
