前言
虚拟列表,顾名思义,不是真实的列表,它一般只存在于人类的美好遐想之中...
跑题了,重来。
这话是引用element-plus中的,我觉得说的挺有道理,就小小地借鉴一下。虚拟列表的出现是为了解决列表中数据内容过长,过多,导致的加载缓慢和快速滚动白屏。
开始
首先,先来看一个例子 我们再container中,动态添加20000个列表项,高度固定24,会发现页面加载时,出现了明显的延迟卡顿。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#container {
width: 240px;
height: 300px;
margin-top: 24px;
overflow-y: auto;
}
</style>
</head>
<body>
<div>list-container: </div>
<div id="container"></div>
<script>
const NUMBER = 20000, HEIGHT = 24;
const container = document.getElementById('container');
let str = ``;
for (let i = 0; i < NUMBER; i++) {
let s = ``;
s += `
<div
style="height: 24px;display: flex;align-items: center;box-sizing: border-box
justify-content: space-between;font-size: 14px;border-bottom: 1px solid #ddd;"
>
<div>list</div>
<div>${i}</div>
</div>
`
str += s;
}
container.innerHTML = str;
</script>
</body>
</html>
简单的一个列表需要0.8秒的时间,而且拖动滑块快速滑动时,有时还会出现短暂的空白情况。
解决
为了更好的客户体验,我们可以使用虚拟列表来解决这个问题。
原理很简单,监听滚动事件时,我们通过视窗的高度,和滚动条的滚动距离,来计算出当前应该显示给使用者的列表,并在前后补充几个作为缓冲。
然后根据滚动距离,通过 定位 或者 translate偏移 将列表移动到当前显示的位置。在客户的感知中,与正常列表无异,而实际上,我们一直只渲染了这十几二十个列表项。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#container {
width: 240px;
height: 300px;
margin-top: 24px;
overflow-y: auto;
}
#list-container {
position: relative;
}
#scroll-div {
width: 100%;
position: absolute;
top: 0;
left: 0;
}
</style>
</head>
<body>
<div>list-container: </div>
<div id="container">
<div id="list-container">
<div id="scroll-div"></div>
</div>
</div>
<script>
const NUMBER = 20000, HEIGHT = 24;
const container = document.getElementById('container');
const scrollDiv = document.getElementById('scroll-div');
const listContainer = document.getElementById('list-container');
listContainer.style.height = NUMBER * HEIGHT + 'px';
const height = container.offsetHeight;
// 取超过高度的数量
const num = Math.ceil(height / 24);
// 滚动时候的回调函数
const scrollCallback = function(e) {
const h = e ? e.target.scrollTop : 0;
console.log('h', h);
// 找到该显示列表中的第几个,然后加上num,再往前取5个,往后取5个,得到需要渲染的列表
const n = Math.ceil(h / HEIGHT);
const start = n > 5 ? n - 5 : 0;
const end = n + (num - 1) > NUMBER - 5 ? NUMBER : n + (num - 1) + 5;
let str = ``;
for (let i = start; i < end; i++) {
let s = ``;
s += `
<div
style="height: 24px;display: flex;align-items: center;box-sizing: border-box;
justify-content: space-between;font-size: 14px;border-bottom: 1px solid #ddd;"
>
<div>list</div>
<div>${i}</div>
</div>
`;
str += s;
}
const top = start * HEIGHT;
scrollDiv.style.top = top + 'px';
scrollDiv.innerHTML = str;
}
// 初始化
scrollCallback();
// 监听滚动事件
container.onscroll = scrollCallback;
</script>
</body>
</html>
结语
仅仅是一次简单的虚拟列表的实现,因为高度都是固定的,十分有局限性。由于这次是初探,宽以待己,争取下次中探时候,能找到自适应高度的良好解决方法。
由于最近沉迷炉石战棋,加上对flutter继续“坚持不懈”的探索与学习,我终于上到了5500分。导致这个文章写得太少太浅,深感愧疚,自我鞭策一下,以后尽量还是保证一礼拜至少写一篇吧。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!