手写虚拟列表:提升前端性能的利器

在现代前端开发中,处理大量数据时,性能问题总是不可避免。虚拟列表(Virtual List)是一种有效的解决方案,可以显著提升页面的渲染性能。本文将教你如何使用 JavaScript 手写一个简单的虚拟列表。

什么是虚拟列表?

虚拟列表是一种优化技术,通过只渲染可视区域内的元素,来减少 DOM 节点的数量,从而提升渲染性能。当用户滚动页面时,虚拟列表会动态加载和卸载元素。

实现思路

  1. 计算可视区域:根据容器的高度和单个项的高度,计算出可视区域内需要展示的项。
  2. 动态渲染:根据滚动位置动态更新可见项的列表。
  3. 保持长列表的滚动体验:通过设置容器的总高度,保持滚动条的完整性。

代码实现

下面是一个简单的虚拟列表实现示例:

HTML 结构

<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
    div {
        box-sizing: border-box;
    }

    ul {
        list-style: none;
        margin: 0;
        padding: 0;
    }

    #container {
        height: 400px;
        width: 350px;
        margin: auto;
        border: 1px solid black;
        overflow: auto;
    }

    .item {
        display: flex;
        height: 41px;
        gap: 10px;
    }
</style>
</head>
<body>
    <div id="container">
        <div class="item"></div>
    </div>
</body>

</html>

JavaScript 代码


<script>

    let data = []
    for (let i = 0; i < 200; i++) {
        data.push({
            id: i,
            name: Math.random() * 10 * i
        })
    }

    // 获取页面结构的数据,为了不写死
    let containerDom = document.querySelector('#container')
    let containerDomHeight = containerDom.clientHeight  //不包括边框
    let itemDom = document.querySelector('.item')
    let itemDomHeight = itemDom.offsetHeight

    let maxVisibleMount = Math.round(containerDomHeight / itemDomHeight)
    let startIndex = 0
    let endIndex = maxVisibleMount - 1


    function renderItem() {
        let distance = containerDom.scrollTop  //滚动距离要先存起来,不能等后面清空
        let fragment = document.createDocumentFragment()
        let ul = document.createElement('ul')
        for (let i = startIndex; i <= endIndex; i++) {
            let liDom = document.createElement('li')
            liDom.classList.add('item')
            liDom.innerHTML = `  <span>${data[i].id}</span> --
                                 <span>${data[i].name}</span>`
            ul.appendChild(liDom)
        }
        fragment.appendChild(ul)
        containerDom.innerHTML = ''
        containerDom.appendChild(fragment)

        ul.style.paddingTop = distance + 'px'
        ul.style.paddingBottom = (data.length * itemDomHeight - itemDomHeight * maxVisibleMount - distance) + 'px'
        //容器空间占位(特殊注意,box-sizing: border-box下,paddingBottom超过高度设置的值,也会溢出。所以不宜操作container)
    }

    renderItem()  //初始调用一次

    containerDom.addEventListener('scroll', function () {
        let distance = containerDom.scrollTop
        startIndex = Math.ceil(distance / itemDomHeight) - 1 //想象,显示一半的也要显示
        endIndex = Math.min(startIndex + maxVisibleMount - 1, data.length - 1)
        renderItem()
    })

</script>

代码解析

  1. HTML 结构: 创建一个固定高度的容器用于显示列表。
  2. 样式设置: 每个项的高度为 设置好。
  3. JavaScript 实现:
    • 通过  计算出可见项的数量。
    • 设置容器的总高度,并添加滚动事件监听器。
    • 计算当前可见项的索引,并调用 renderItem 渲染这些项。
    • renderItem 函数负责生成和插入可见项的 HTML。

总结

通过手写虚拟列表,我们可以有效地提升网页的性能,尤其是在处理大量数据时。这个简单的实现提供了一个基本框架,可以根据项目需求进一步扩展功能,比如支持动态加载、虚拟滚动等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值