SOURCE

console 命令行工具 X clear

                    
>
console
console.log(`虚拟列表是根据滚动容器元素可视区域大小动态渲染原始长数据的某一段数据的技术`)

window.onload = function () {


    console.log(``);

    // window.onload = function () {

    let state = {
        startOffset: 0, // 撑大容器上部分
        endOffset: 0, // 撑大容器下部分

        startIndex: 0, // 可视区域数组在原数组起始下标
        endIndex: 0, // 可视区域数组在原数组结束下标

        scrollTop: 0, // 容器滚动高度

        visibleData: []
    }

    // 1000条为true数组
    let data = new Array(1000).fill(true)
    data.map((item, index) => {
        data[index] = index
    })

    var container = document.querySelector('#container')
    var list = document.querySelector('#list')
    // console.log('clientheight:'+ container.clientHeight)

    let itemHeight = 80 // 每项高度
    let bufferSize = 5 // 缓冲个数
    // 可视区域数据个数
    let visibleCount = 0


    var setPadding = function () {
        container.style.paddingTop = state.scrollTop + 'px'
        //  state.scrollTop+'px'
        // state.startOffset + 'px'
        container.style.paddingBottom = state.endOffset + 'px'
        // console.log(container)
    }

    var updateVisibleData = function () {

        state.startIndex = Math.ceil(state.scrollTop / itemHeight)
        state.startOffset = state.startIndex * itemHeight
        console.log('startIndex:' + state.startIndex)

        state.endIndex = state.startIndex + visibleCount
        state.endOffset = itemHeight * data.length - state.scrollTop - visibleCount * itemHeight
        //  (data.length - state.endIndex) * itemHeight
        console.log('endIndex:' + state.endIndex)

        console.log(state.startOffset)
        console.log(state.endOffset)
        console.log('差值:' + (state.endIndex - state.startIndex));

        // 截取数据---每次都是新数据--能不能缓存?
        state.visibleData = data.slice(state.startIndex, state.endIndex)

        let len = state.visibleData.length
        let html = ''
        for (let i = 0; i < len; i++) {
            html += `<div class="item"> 
                <div>` + state.visibleData[i] + '-' + faker.lorem.words() + `</div>
                <div>` + faker.lorem.sentences() + `</div>
                </div>`
        }
        container.innerHTML = html
        setTimeout(() => {
            setPadding()
        }, 0)


    }

    // 初始化数据
    var initData = function () {
        // 可视区域个数+缓存数
        visibleCount = Math.ceil(list.clientHeight / itemHeight) + bufferSize

        // 开始数+显示数
        state.endIndex = state.startIndex + visibleCount
        updateVisibleData()
    }
    initData()


    function handleScroll(e) {
        console.log('scroll:', e && e.target.scrollTop)
        let top = e && e.target.scrollTop || 0
        state.scrollTop = top
        updateVisibleData()
    }


    // window.onscroll = function (e) {
    //     console.log(e)
    //     handleScroll(e)
    // }
    handleScroll()
    list.onscroll = function (e) {
        handleScroll(e)
    }


    // **************************  改进   **************************


    /** 
     * 对列表高度位置信息进行缓存
     * getBoundingClientRect 介绍
     * top:元素上边界距视口距离
     * bottom:元素下边界距视口距离
     * height:元素高度
     */
    // 缓存已渲染元素信息
    // var cache = []
    // 缓存锚点原本苏信息
    // anchorItem = {
    //     index: 0, // 锚点索引,即元素下标
    //     top: 0, // startOffset=top+window.pageYOffset
    //     bottom: 0 // top+height
    // }
    // anchorItem = cache.find(item => item.bottom >= scrollTop)
    // state.startIndex = anchorItem.index
    // state.endIndex = state.startIndex + visibleCount

    // 对于不固定高度的列表visibleCount该如何算?
    // 给列表一个预估高度 estimatedItemHeight=80

    // 计算可渲染的元素个数
    // this.visibleCount = Math.ceil(window.innerHeight / estimatedItemHeight) + bufferSize


}









<html>

<head>

	<title>虚拟列表--动态数据渲染</title>
</head>

<body>

<div>参考文章:https://github.com/dwqs/blog/issues/70</div>
    <div class="list" id="list">

        <div id='container' class="container" onscroll="handleScroll()">
            123
        </div>
    </div>
</body>

</html>
 html,
        body {
            margin: 0;
            padding: 0;
        }

        .container {
            background: chocolate;

        }

        .container .item {
            /* height: 30px; */
            padding: 10px;
        }

        .list {
            height: 400px;
            overflow: auto;
        }

本项目引用的自定义外部资源