js实现虚拟表格

<!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>虚拟表格</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        #list {
            width: 300px;
            height: 500px;
            overflow-y: auto;
            position: relative;
        }

        #parent {
            position: relative;
            width: 100%;
        }

        #content {
            -webkit-willChange: 'transform';
            willChange: 'transform';
            position: absolute;
            width: 100%;
            left: 0;
            top: 0;
        }

        #bg {
            position: absolute;
            z-index: 10;
            width: 100%;
            height: 100%;
            top: 0;
            left: 0;
            background: #fff;
            opacity: 0;
            display: none;
        }

        .item {
            min-height: 50px;
            margin-bottom: 5px;
            border: 1px solid #ccc;
            display: flex;
            justify-content: center;
            align-items: center;
        }
    </style>
</head>

<body>
    <div id="list">
        <div id="parent">
            <!-- 用来装载内容 -->
            <div id="content"></div>
            <!-- 用来遮挡渲染内容,避免鼠标在不断渲染的content上面的时候导致卡顿无法触发滚动 -->
            <div id="bg"></div>
        </div>
    </div>

    <script>
        let itemNum = 100; // 内容总数
        let itemHeight = 52; // 每个内容单元高度
        let list = document.getElementById('list')
        let parent = document.getElementById('parent')
        parent.style.height = `${itemNum*itemHeight}px` // 内容总高度撑开滚动条
        let content = document.getElementById('content')
        let bg = document.getElementById('bg')

        let cNum = Math.ceil(list.offsetHeight / itemHeight) // 可视区域个数
        let startIndex = 0 // 可视区域开始index
        let endIndex = startIndex + cNum // 可视区域结束index


        let data = [...new Array(itemNum).keys()] // 生成所有数据

        // 渲染初始数据
        data.slice(startIndex, endIndex).forEach(item => {
            let div = document.createElement('div')
            div.innerHTML = item
            div.setAttribute('class', 'item')
            content.appendChild(div)
        })


        let timer = null; // 滚动定时器,用于检测是否滚动结束
        let scrollTop = 0; // 当前滚动条高度
        let scrollEndTop = 0; // 停止时滚动条高度


        function scrollCallBack() {
            clearTimeout(timer);
            timer = setTimeout(isScrollEnd, 500);
            scrollTop = list.scrollTop
            bg.style.display = 'block'
            let sTop = Math.max(list.scrollTop, 0) // 滚动距离,最小取0
            startIndex = Math.floor(sTop / itemHeight) // 可视区域开始index
            endIndex = startIndex + cNum // 可视区域结束index
            content.style.transform = `translateY(${startIndex*itemHeight}px)` // 内容区域偏移
            // 新的数据渲染
            let newData = data.slice(startIndex, endIndex)
            let html = ''
            newData.forEach(item => {
                html += `<div class="item">${item}</div>`
            })
            content.innerHTML = html
        }

        // 判断是否滚动结束,将bg遮罩层隐藏
        function isScrollEnd() {
            scrollEndTop = list.scrollTop;
            if (scrollTop === scrollEndTop) {
                console.log('滚动条停止滚动');
                bg.style.display = 'none'
            }
        }

        scrollCallBack()

        list.addEventListener('scroll', scrollCallBack)
    </script>
</body>

</html>

  

posted @ 2022-08-18 16:33  火星_PGY  阅读(151)  评论(0编辑  收藏  举报