工作中解决过如题的问题,4万条数据需要瞬间渲染到页面上,趁最近需要,重新整理一遍
第一次优化采用了数据分组分多次渲染的方法,能迅速渲染上一组数据,达到很好的初始视觉效果,但是总的dom元素数量还是一样庞大,当渲染完所有dom,滑动时还是会卡顿。
所以在更高要求下还是要用虚拟滚动,就是只渲染当前视口及附近的数据,通过滚动位置和每条高度来计算当前视口应该展示哪些数据,这样渲染的数据量小,不会因dom数量大而卡顿。当时没找到现成合适的插件,需要自己写,这个方案需要处理的细节很多,此demo处理了核心逻辑,开发时需要注意细节。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>渲染优化</title> <style> html, body { width: 100%; height: 100%; position: relative; overflow: hidden; } #wrapper { width: 500px; height: 100%; position: relative; overflow-y: scroll; overflow-x: hidden; } .background { width: 500px; height: 4025520px; position: absolute; top: 0; left: 0; } .list { height: 100%; position: absolute; top: 0; left: 0; } .cell { margin: 0; padding: 0; height: 20px; border-bottom: 1px solid gray; box-sizing: border-box; } </style> </head> <body> <div id="wrapper"> <div class="background"></div> <div class="list"></div> </div> </body> <script> let data = [] for(let i = 0; i < 200000; i ++) { data.push(i+1) } let wrapper = document.querySelector('#wrapper') let list = document.querySelector('.list') let scrollRange = [] let num = Math.ceil(wrapper.clientHeight / 20) render(0) wrapper.onscroll = function(e) { let n = e.target.scrollTop let first = Math.ceil(n/20) if(first > scrollRange[0] && first+num < scrollRange[1]) return render(n) }
function render(n) { let str = '' let first = Math.ceil(n / 20) let leftData = data.slice(first-num, first) let centerData = data.slice(first, first + num) let rightData = data.slice(first + num, first + 2*num) let runData = [...leftData, ...centerData, ...rightData] for(let i = 0; i < runData.length; i ++) { str += `<p class='cell'>${runData[i]}</p>` } list.innerHTML = str list.style.top = 0 + n - leftData.length * 20 + 'px' scrollRange = [first-leftData.length, first+2*num] }
</script> <script>
</script> </html>
|