可視區渲染方案原理分析

移動端頁面隨着滑動的dom愈來愈長,會出現卡頓的現象,進而下降用戶體驗,因而可視區渲染方案出來。html

可視區渲染就像一句話說的:敵不動我動,山不就我我就山。dom

可視區渲染原理:ide

1,有個滾動區域,下面的content類,要求overflow:auto,也就是能夠使用滾動;在實際項目開發中這個根據可視區窗口大小變化函數

2,一個足夠高的渲染盒子,下面中viewArea類,其高度等於全部內容條數x單條內容高度,在實際項目中這個會受限於手機html的最大高度限制ui

3,可視區顯示的內容條數viewArea類裏面的內容,內容多少能夠經過pageSize控制orm

4,經過監聽滾動事件,觸發可視區內容更新,包括更新呈現的內容以及更新內容的位置,後者實際上是人爲製造了一種滾動效果htm

<!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>
相關文章
相關標籤/搜索