如果你不懂虚拟列表没有关系,读完不懂 你来打我。
什么是虚拟列表,就是假的列表😀,哈哈哈。虚拟列表,通过模拟长列表的形式,来渲染小部分数据, 达到性能优化。
原理:通过滚动的scrollTop,来确定要渲染的数据index下标,然后slice切割出来要渲染的数据。通过css属性sticky来固定渲染的数据。
废话不多说上代码😄
第一步先看dom结构
<div class="virtual-scroll"> // 提供滚动框架
<div id="container"> // 模拟长列表高度
<div id="item-container"></div> // 存放渲染数据
</div>
</div>
第二步保证item-comtainer 一直在渲染区域
<style>
.virtual-scroll {
width: 200px;
height: 300px;
overflow: auto;
}
#container {
background-color: #4fc08d;
position: relative;
}
#container > div {
position: sticky; // 这个属性能保证item-container能在渲染区域 哪怕滚动
top: 0;
}
</style>
第三步 获取要渲染的数据,通过scrllTop 除以 展示item的高度来获取第一个数据下标
<script>
const containerDom = document.querySelector("#container")
const scrollDom = document.querySelector(".virtual-scroll")
const itemDom = document.querySelector("#item-container")
const render = (initIndex = 0, data = []) => {
// slice 要渲染的数据 默认渲染10
const renderData = data.slice(initIndex, initIndex + 10);
const fragment = document.createDocumentFragment();
renderData.forEach((item) => {
const div = document.createElement('div');
div.innerText = item.id
div.style.cssText = "height: 30px"
fragment.appendChild(div)
})
itemDom.replaceChildren(fragment)
}
fetch('https://xxx.ai/mock/59/table') // 列表接口
.then(res => res.json()).then(({data}) => {
const list = data.list;
const totalLen = list.length; // 计算滚动dom 高度
const scrollHeight = totalLen * 30 // 30 是每一个item的固定高度 目前取固定
containerDom.style.cssText = `height: ${scrollHeight}px;` // 模拟长列表
render(0, list) // 初始化
const eventFun = ({target}) => {
const scrollTop = target.scrollTop;
const newShowNumber = Math.ceil(scrollTop / 30); // 获取要渲染数据的初始化下标
render(newShowNumber, list)
}
scrollDom.addEventListener('scroll', _.throttle(eventFun, 200))
})
</script>
三个div分别对应了滚动区域div(virtual-scroll), 模拟长列表div(container), 渲染区域div(item-container),由此 一个最小化的虚拟列表已经完成。
利用stricty完成只能算是偷懒,在动画方面缺陷有点大。大家可以想想如何解决哈😄
[完整代码](www.yuque.com/docs/share/… 《30行JS带你完成一个最小化虚拟列表》)