Fork me on GitHub

可视区渲染方案原理分析

移动端页面随着滑动的dom越来越长,会出现卡顿的现象,进而降低用户体验,于是可视区渲染方案出来。

可视区渲染就像一句话说的:敌不动我动,山不就我我就山。

可视区渲染原理:

1,有个滚动区域,下面的content类,要求overflow:auto,也就是可以使用滚动;在实际项目开发中这个根据可视区窗口大小变化

2,一个足够高的渲染盒子,下面中viewArea类,其高度等于所有内容条数x单条内容高度,在实际项目中这个会受限于手机html的最大高度限制

3,可视区显示的内容条数viewArea类里面的内容,内容多少可以通过pageSize控制

4,通过监听滚动事件,触发可视区内容更新,包括更新呈现的内容以及更新内容的位置,后者其实是人为制造了一种滚动效果

<!DOCTYPE html>
<html lang="en">

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>无限滚动中的虚拟列表(只渲染可视区域,dom元素可复用)</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta name="format-detection" content="telephone=no, email=no">
</head>

<body>
    <header>
        <!-- <h1>无限滚动中的虚拟列表-防抖和节流(只渲染可视区域,dom元素可复用)</h1> -->
        <h1>无限滚动中的虚拟列表(只渲染可视区域,dom元素可复用)</h1>
    </header>
    </article>
    <article class="d-part d-effect">
        <style>
            .container {
                height: 600px;
                overflow: auto;
            }

            .item {
                min-height: 60px;
                border-bottom: 1px solid #cccccc;
                border-top: 1px solid #cccccc;
                width: 100%;
                text-align: center;
                background-color: darkgray;
                /* padding: 30px 0;
                box-sizing: border-box; */
            }
        </style>
        <div class="container">
            <div class="content">
                <div class="viewArea">
                    <div class="item">0</div>
                    <div class="item">1</div>
                    <div class="item">2</div>
                    <div class="item">3</div>
                    <div class="item">4</div>
                    <div class="item">5</div>
                    <div class="item">6</div>
                    <div class="item">7</div>
                    <div class="item">8</div>
                    <div class="item">9</div>
                </div>

            </div>
        </div>
        <script>
            var item = document.querySelector('.viewArea .item');  //需要渲染的单个列表元素
            var container = document.querySelector('.container');  //可视区域元素盒子

            console.log(item);
            var start = 0; // 开始位置
            var pageSize = 10; // 每页展示的数据
            var total = 100000; //数据总长度

            // var itemHeight = 61; // 每个item的高度
            var itemStyle = getComputedStyle(item); // 获取元素最终样式
            var itemHeight = Number(itemStyle.height.split('px')[0]) + Number(itemStyle.borderTopWidth.split('px')[0]) + Number(itemStyle.borderBottomWidth.split('px')[0]); // 每个item的高度
            console.log('itemHeight', itemHeight);


            // 设置数据列表的总高度
            document.querySelector('.container .content').style.height = itemHeight * total + 'px';
            updateDom(start, pageSize, 0);
            
            //更新渲染列表的高度和数据
            function updateDom(start, pageSize, height) {
                document.querySelector('.container .content .viewArea').style.transform = 'translateY(' + height + 'px)';
                let all = document.querySelectorAll('.viewArea .item'); // 获取所有渲染列表
                for (var i = start, itemIndex = 0, len = start + pageSize; i < len; i++, itemIndex++) {
                    all[itemIndex].innerHTML = i;
                }
            }
            // 滚动处理函数
            function handleScroller() {
                var lastStart = 0; // 上次开始的位置
                return () => {
                    var currentScrollTop = container.scrollTop;
                    var fixedScrollTop = currentScrollTop - currentScrollTop % itemHeight;  // currentScrollTop % itemHeight这个是为了让滚动效果更自然
                    console.log(currentScrollTop, currentScrollTop % itemHeight)
                    var start = Math.floor(currentScrollTop / itemHeight);
                    if (lastStart !== start) {   // 这块避免一些重复性渲染,这样也不用计算方向了
                        lastStart = start;
                        updateDom(start, pageSize, fixedScrollTop);
                    }
                }
            }

            document.querySelector('.container').addEventListener('scroll', handleScroller(), false);
        </script>
    </article>
    </div>
</body>

</html>

 

posted @ 2021-04-24 10:52  我站在山顶上  阅读(732)  评论(0编辑  收藏  举报