React实现虚拟滚动列表
原理: 只渲染可视节点以减少DOM开销,提升加载速度以下代码是伪代码,具体实现看这如果你想在项目中使用复杂的虚拟滚动,可以看下react-virtualized。本文只提供虚拟列表实现思路实现步骤创建容器<div className="container"><div className="virtual-container" /></div>.container
·
原理: 只渲染可视节点以减少DOM开销,提升加载速度
以下代码是伪代码,具体实现看这
如果你想在项目中使用复杂的虚拟滚动,可以看下react-virtualized 。本文只提供虚拟列表实现思路
实现步骤
创建容器
<div className="container">
<div className="virtual-container" />
</div>
.container {
height: 200px;
width: 200px;
border: 1px solid black;
overflow-y: scroll;
}
.virtual-container {
position: relative;
overflow: hidden;
}
计算高度
通过每行高度乘以数据长度计算高度。这里是每行高度固定的情况,如果不固定可以参考实现中virtual-list-autoheight.js文件的实现(高度不固定,但一定要知道行的最大高度)
const containerHeight = itemHeight * datasource.length;
refVirtualContainer.current.style.height = containerHeight + "px";
实现滚动效果
因为我们只渲染一部分数据,无数据部分不能滚动,所以需要自己实现滚动。
我们利用transformY实现滚动效果
const refVirtualContainer = useRef();
const [scrollDis, setScrollDis] = useState(0);
useEffect(() => {
refContainer.current.addEventListener("scroll", (e) => {
setScrollDis(scrollTop);
});
}, [])
<div className="virtual-container" ref={refVirtualContainer}>
<div className="virtual" style={{ transform: `translateY(${scrollDis}px)` }}/>
</div>
更新数据
通过以上两步我们实现了可滚动的列表,之后需要在每次滚动时更新数据即可。
具体实现
const [dataSlice, setDataSlice] = useState([]); //数据切片
refContainer.current.addEventListener("scroll", (e) => {
setData(e.target.scrollTop, refContainerHeight, containerHeight);
});
const setData = (scrollTop, refContainerHeight, containerHeight) => {
const beginNum = Math.ceil(
(scrollTop / containerHeight) * datasource.length
);
const domNum = Math.ceil(refContainerHeight / itemHeight);
setDataSlice(datasource.slice(beginNum, domNum * 2 + beginNum));
};
{dataSlice.map((item, idx) => (
<div
key={idx}
className="item"
ref={refItem}
style={{ height: itemHeight, lineHeight: `${itemHeight}px` }}
>
<Button>{item * 80}</Button>
</div>
))}
注意
- 我们把key设置成idx,这样就能利用react机制使节点复用,减少性能消耗
setDataSlice(datasource.slice(beginNum, domNum * 2 + beginNum));
- 这一段中 domNum * 2是为了在滚动时去掉闪烁,可以去掉试一下效果
更多推荐
已为社区贡献1条内容
所有评论(0)