1. 程式人生 > 其它 >效能優化:虛擬列表,如何渲染5萬條資料的dom,頁面同時不卡頓

效能優化:虛擬列表,如何渲染5萬條資料的dom,頁面同時不卡頓

最近做的一個需求,當列表大概有5萬條資料,又不讓做成分頁,如果頁面直接渲染5萬條資料,在一些低配電腦上可能會照成頁面卡死,基於這個需求,研究分析前端渲染卡頓原因,準備手寫一個虛擬列表。

1.實現思路

  1. 列表中固定只顯示少量的資料,比如60條
  2. 在列表滾動的時候不斷的去插入刪除dom
  3. startIndex、endIndex,不斷的改變這個值來獲取最新的顯示列表
  4. paddingTop、paddingBottom撐開容器的滾動區域

首先看一下當直接插入10萬條列表時,頁面的效能。

2.方式對比

情況一

  • 直接渲染出5萬條資料

可以看到火焰圖中已經有了紅色的部分了,dom渲染也耗時也有5s多

  • 優化前效果

情況二

  • 採用虛擬列表載入方式

假設有一個容器,高度為600px,列表項每個高度為30px,那麼根據列表的length我們就可以計算出滾動容器的總高度,也可以知道顯示60條資料的高度,我們此時可以給容器加一個paddingBottom,來撐開容器,來模擬頁面應該滾動的高度

this.paddingBottom = this.allHeight - this.scrollList.length * 30

容器同時還需要paddingTop用做當容器滾動頂部資料移除後撐起scrollTop

最後我們需要監聽容器的滾動事件來不斷的修改paddingTop、paddingBottom、startIndex、endIndex。

調整為虛擬列表之後,可以看到載入渲染在1秒左右!

  • 優化後效果

3.實現程式碼

<!doctype html>
<html lang="zh">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
            content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="
X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> .container { width: 500px; height: 600px; overflow: auto; border: 1px solid; margin: 100px auto; } .item { height: 29px; line-height: 30px; border-bottom: 1px solid #aaa; padding-left: 20px; display: flex; text-align: center; } .item span{ flex: 1; } </style> </head> <body> <div id="app"> <button @click="add">新增資料</button> <div class="container" ref="container"> <div class="scroll-wrapper" :style="style"> <div v-for="(item, index) in scrollList" :key="index" class="item"> <span>{{item.name}}</span> <span>{{item.price}}</span> <span>{{item.category}}</span> </div> </div> </div> </div> <script src="./js/vue.js"></script> <script> new Vue({ el: '#app', data: { list: [ {name:'名稱',price:'單價',category:'型別'} ], startIndex: 0, endIndex: 60, paddingTop: 0, paddingBottom: 0, allHeight: 0 }, computed: { scrollList() { return this.list.slice(this.startIndex, this.endIndex) }, style() { return { paddingTop: this.paddingTop + 'px', paddingBottom: this.paddingBottom + 'px' } } }, watch: { list(val) { const valLen = val.length this.allHeight = valLen * 30 this.paddingBottom = this.allHeight - this.scrollList.length * 30 } }, mounted() { const container = this.$refs.container container.addEventListener('scroll', () => { const top = container.scrollTop this.startIndex = Math.floor(top / 30) this.endIndex = this.startIndex + 60 this.paddingTop = top if (this.endIndex >= this.list.length - 1) { this.paddingBottom = 0 return } this.paddingBottom = this.allHeight - 600 - top }) }, methods: { add() { let arr = new Array(100000).fill(0) arr = arr.map((item, index) => { return { name: "名稱_" + index, price: Math.ceil(Math.random()*10)+'', category: Math.random() > 0.5 ? '蔬菜' : '水果' } }) this.list = [ ...this.list, ...arr ] } } }) </script> </body> </html>

總結:由於不斷操作dom節點,會導致渲染慢,而且滾動起來非常卡頓,通過虛擬列表的方式,大大地提高了渲染效率和滾動流暢度!

作者:IT民工鄭小江 出處:http://a876459952.cnblogs.com/ 本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連線,否則保留追究法律責任的權利。