30行JS带你完成一个最小化虚拟列表

1,111 阅读1分钟

如果你不懂虚拟列表没有关系,读完不懂 你来打我。

什么是虚拟列表,就是假的列表😀,哈哈哈。虚拟列表,通过模拟长列表的形式,来渲染小部分数据, 达到性能优化。

原理:通过滚动的scrollTop,来确定要渲染的数据index下标,然后slice切割出来要渲染的数据。通过css属性sticky来固定渲染的数据。

废话不多说上代码😄

在线demo

第一步先看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带你完成一个最小化虚拟列表》)