感谢阅读本文 · 欢迎在下方留言交流你的想法
探索更多文章 →虚拟列表即可视区域渲染
![]()
虚拟列表分为动态高度和固定高度
不考虑任何可变因素,实现一个最简单的例子,假定列表的li标签高度为30px,可视区域大小为300px,所以,我们在上下滚动时,可视元素为10个左右,只需要考虑如何渲染这10个元素
例子采用react实现,原生和vue同理
思路
list.slice(start,end)即可jsximport { useEffect, useRef, useState, Profiler } from "react"; import "./styles.css"; const total = 10000; const arr = Array.from({ length: total }).map((_, idx) => idx); export default function App() { const appRef = useRef(); const [start, setStart] = useState(0); const [scrollTop, setScrollTop] = useState(0); const [offset, setOffset] = useState(0); const [list, setList] = useState([]); const onScroll = (e) => { requestAnimationFrame(() => { setScrollTop(e.target.scrollTop); let start = Math.floor(e.target.scrollTop / 30); setStart(start); let end = start + 10; setList(arr.slice(start, end)); }); }; useEffect(() => { const container = appRef.current; container.addEventListener("scroll", onScroll); }, []); useEffect(() => { setOffset(start * 30); }, [start]); function callBack(...arg) { console.log(arg[2]); } return ( <div> {scrollTop} <Profiler id="vl" onRender={callBack}> <div ref={appRef} className="App"> <div className="mask" style={{ height: "300000px" }}></div> <ul style={{ transform: `translate3d(0, ${offset}px, 0)` }}> {list.map((item) => ( <li key={item}>{item}</li> ))} </ul> </div> </Profiler> </div> ); }
css
.App {
font-family: sans-serif;
text-align: center;
background-color: aqua;
height: 300px;
overflow-y: auto;
position: relative;
}
.mask {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
ul {
transform: translate3d(0, 0, 0);
}
li {
height: 30px;
}
li:nth-of-type(odd) {
background-color: #f00;
}
li:nth-of-type(even) {
background-color: #0f0;
}