移动端页面随着滑动的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; 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>