长列表优化方案,虚拟列表

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>虚拟列表实现</title>
        <style type="text/css">
            .section{
                height: 50vh;
                width: 50%;
                margin: 25vh auto;
                background-color: gainsboro;
                overflow: auto;
            }
            .list{
                height: auto;
                width: 80%;
                margin: auto;
                background-color: antiquewhite;
            }

            html ,body, section{
                margin: 0px;
                padding: 0px;
            }
        </style>
    </head>
    <body>
       <div class="section">
        <div class="list"></div>
       </div>

        <script>
            window.onload = function(){
                //真实列表数据
                let itemListData = initListData();
                //列表容器
                let section = document.querySelector(".section");
                //列表高度
                let sectionHeight = getNodeHeight(section);
                //列表子项样式
                let listStyle = {
                    height: "20px",
                }
                //列表子项高度
                let listItemHeight = 20;
                //可以容纳多少列表子项
                let canVisible = Math.ceil(sectionHeight/listItemHeight) +1;
                const proxyItemList = createListProxy(listStyle);

                initScrollEvent(section, canVisible, listItemHeight, itemListData, listItemHeight, proxyItemList);

                // console.log(sectionHeight, sectionHeight, canVisible);
                for(let i = 0; i < canVisible; i++){
                    proxyItemList.push(i);
                }
            }

            //初始化列表数据
            function initListData(){
                let total = 10000;
                let itemData = [];
                for(let i = 0; i < total; i++){
                    itemData.push(i);
                }
                return itemData;
            }

            //初始化容器滚动事件
            function initScrollEvent(node, canVisible, itemHeight,itemListData, listItemHeight,proxyItemList){
                let list = document.querySelector(".list");
                node.onscroll = function(event){
                    //获取到顶部高度
                    let scrollTop = event.target.scrollTop;
                    //确定起始索引
                    let startIndex = Math.floor(scrollTop / itemHeight);
                    //确定结束索引
                    let endIndex = startIndex + canVisible;
                    //确定展示数据
                    let showData = itemListData.slice(startIndex, endIndex);

                    console.log(startIndex, endIndex, showData);

                    proxyItemList.length = 0;
                    for(let data of showData){
                        proxyItemList.push(data);
                    }

                    let startOffset = scrollTop - (scrollTop % listItemHeight);
                    // let startOffset = scrollTop;
                    console.log(startOffset)
                    list.style.transform = `translate3d(0,${startOffset}px,0)`
                    // console.log(event.target.scrollTop);
                }
            }

            function createListProxy(listStyle){
                //列表数据
                let itemList = [];
                //列表容器
                let list = document.querySelector(".list");

                const handleItemList = {
                    set(target, propety, value){
                        // console.log(target,propety, value);
                        if(propety == "length" && value != 0){
                            for(let i = list.childElementCount - 1; i >= 0; i--){
                                list.removeChild(list.children[i]);
                            }
                            for(let i = 0; i < target.length; i++){
                                if(target[i] != null){
                                    let item = document.createElement("div");
                                    item.innerText = "I am " + target[i];
                                    setStyle(item, listStyle);
                                    list.appendChild(item);
                                }
                            }
                        }else{
                            for(let i = list.childElementCount - 1; i >= 0; i--){
                                list.removeChild(list.children[i]);
                            }
                        }
                        return Reflect.set(...arguments);
                    }
                }

                return new Proxy(itemList, handleItemList);
            }

            function setStyle(node,obj){
                for(let key of Object.keys(obj)){
                    node.style[key] = obj[key];
                }
            }
        
            function getNodeHeight(node){
                return window.getComputedStyle(node, null).height.replace(/[^\d.]/g, "");
            }

            function computedItemHeight(listStyle){
                let div = document.createElement("div");
                setStyle(div, listStyle);
                let style = window.getComputedStyle(div, null)
                let total = style.marginTop.replace(/[^\d.]/g, "")
                + style.marginBottom.replace(/[^\d.]/g, "")
                + style.paddingTop.replace(/[^\d.]/g, "")
                + style.paddingBottom.replace(/[^\d.]/g, "")
                + style.height.replace(/[^\d.]/g, "");

                return total;
            }

        </script>
    </body>
</html>


<!-- <!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>虚拟列表实现</title>
    </head>
    <body>
        <button id="button">button</button><br>
        <ul id="container"></ul> 

        <script>
            let button = document.querySelector("#button");
            button.onclick = function(){
                let now = Date.now();
                
                let total = 10000;
                let ul = document.querySelector("ul");

                for(let i = 0; i < total; i++){
                    let li = document.createElement("li");
                    ul.appendChild(li);
                }
                console.log(Date.now() - now);
                setTimeout(()=>{
                    console.log(Date.now() - now)
                }, 0)
            }
        </script>
    </body>
</html> -->

猜你喜欢

转载自blog.csdn.net/m0_57033755/article/details/131760765