这是我在面试题中遇到的一个问题,就是如何优化前端性能,其中虚拟列表也是优化前端性能的一种方法。
原理:
当页面加载的数据很多时,会让浏览器的性能降低,此时我们可以按需加载,只加载我们可以看到的区域,而虚拟列表就是这个功能。
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="list-container">
<div id="list-wrapper">
<div id="list-viewport">
<!-- 可视区域内的列表项会动态渲染,其余项则不会渲染 -->
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>0</li>
<li>9</li>
<li>7</li>
<li>6</li>
<li>4</li>
<li>2</li>
<li>2</li>
<li>5</li>
<li>7</li>
<li>5</li>
<li>3</li>
<li>2</li>
<li>34</li>
<li>23</li>
<li>23</li>
<li>1</li>
<li>6</li>
<li>1</li>
<li>8</li>
<li>1</li>
<li>8</li>
</ul>
</div>
</div>
</div>
</body>
<script>
const listContainer = document.getElementById("list-container");
const listViewport = document.getElementById("list-viewport");
// 计算每个列表项的高度,例如每个项目高度为 50px。
const ITEM_HEIGHT = 50;
// 计算列表项总数,例如有 1000 个列表项。
const ITEM_COUNT = 1000;
// 计算可视区域内最多可容纳几个列表项。
const VISIBLE_ITEM_COUNT = Math.ceil(
listContainer.clientHeight / ITEM_HEIGHT
);
// 监听滚动事件,计算需要展示的列表项和其位置。
listContainer.addEventListener("scroll", () => {
const scrollTop = listContainer.scrollTop;
const startIndex = Math.floor(scrollTop / ITEM_HEIGHT);
const endIndex = Math.min(startIndex + VISIBLE_ITEM_COUNT, ITEM_COUNT);
// 动态渲染可视区域内的列表项。
let itemsHtml = "";
for (let i = startIndex; i < endIndex; i++) {
itemsHtml += `<div class="list-item" style="top:${
i * ITEM_HEIGHT
}px;">${i}</div>`;
}
listViewport.innerHTML = itemsHtml;
});
</script>
</html>
<style>
#list-container {
overflow-y: auto; /* 设置容器为滚动条自动出现 */
height: 300px; /* 设置容器高度 */
}
#list-viewport {
position: relative; /* 设置列表视口为相对定位 */
}
.list-item {
position: absolute; /* 设置列表项为绝对定位,便于后面计算位置 */
}
</style>
总结出的步骤就是
1、设置每个item项的高度 、最多有几个item ,利用listContainer.clientHeight可视区域高度/item的高度,从而求出可视区域有几个item
2、添加监听事件scroll,通过鼠标滚动的高度求出可视区域第一个item的索引(startIndex),再根据可视区域可展示的总数(VISIBLE_ITEM_COUNT)计算出可视区域最后一个item的索引
3、最后渲染到list-viewport里面
有什么不对的地方请多指指点点喔~~