虛擬列表渲染是一種優化長列表性能的技術,其核心在于僅渲染可視區域內的列表項。1. 監聽滾動事件;2. 計算可視區域的起始索引和結束索引;3. 渲染對應索引的列表項;4. 設置占位元素保證滾動條正常顯示。為提升性能,可采取以下措施:5. 減少dom操作,復用dom元素;6. 使用requestanimationframe優化ui更新。當列表項高度不一致時,需維護一個高度數組,并通過遍歷該數組累加高度來確定起始和結束索引。虛擬列表不適用于列表項數量少、高度頻繁變化或需要快速滾動的場景。為避免白屏或閃爍,可采用預渲染、css transform、圖片懶加載及雙緩沖技術等手段。上述方法共同保障了虛擬列表在復雜場景下的流暢表現。
虛擬列表渲染,簡單來說,就是只渲染可視區域內的列表項,而不是一次性渲染整個列表。這樣可以大幅提升長列表的性能,避免頁面卡頓。
解決方案
核心思路是:監聽滾動事件,計算可視區域的起始索引和結束索引,然后只渲染這些索引對應的列表項。
-
計算可視區域高度: 獲取列表容器的高度,例如 containerHeight = container.offsetHeight;
-
計算列表項高度: 假設每個列表項高度一致,獲取一個列表項的高度,例如 itemHeight = listItem.offsetHeight; 如果列表項高度不一致,需要維護一個高度數組,記錄每個列表項的高度。
-
計算可視區域內的起始索引和結束索引: 根據滾動條位置和列表項高度,計算出可視區域內的起始索引 startIndex 和結束索引 endIndex。 公式如下:
startIndex = Math.floor(scrollTop / itemHeight); endIndex = Math.min(listData.length - 1, startIndex + Math.ceil(containerHeight / itemHeight));
-
渲染可視區域內的列表項: 只渲染 startIndex 到 endIndex 之間的列表項。
-
處理滾動條位置: 為了讓滾動條正常顯示,需要設置列表容器的總高度。 總高度 = 列表項數量 * 列表項高度。 可以通過設置一個空的占位元素的高度來實現。
-
減少DOM操作: 這是最關鍵的優化點。 盡量復用DOM元素,避免頻繁創建和銷毀DOM節點。 可以維護一個DOM池,從DOM池中獲取可用的DOM元素,渲染完成后再放回DOM池。
-
使用requestAnimationFrame: 將更新UI的操作放在 requestAnimationFrame 中執行,可以避免阻塞主線程,提高頁面流暢度。
-
節流或防抖滾動事件: 滾動事件觸發頻率很高,如果每次觸發都重新計算和渲染,會造成性能問題。 可以使用節流或防抖來降低滾動事件的觸發頻率。
-
使用Intersection Observer API: Intersection Observer API 可以更精確地監聽元素是否進入可視區域,避免不必要的計算和渲染。 相比于監聽滾動事件,Intersection Observer API 的性能更好。
-
優化數據結構: 如果列表數據量很大,可以考慮使用分塊加載或懶加載的方式,減少初始加載的數據量。 同時,選擇合適的數據結構,例如使用map代替Array,可以提高查找效率。
-
使用Web Worker: 將復雜的計算任務放在Web Worker中執行,可以避免阻塞主線程,提高頁面響應速度。 例如,計算可視區域內的起始索引和結束索引,可以在Web Worker中執行。
如何處理列表項高度不一致的情況?
如果列表項高度不一致,就不能簡單地使用 itemHeight 來計算起始索引和結束索引了。 需要維護一個高度數組,記錄每個列表項的高度。 計算起始索引和結束索引時,需要遍歷高度數組,累加高度,直到累加的高度超過滾動條位置。
具體步驟如下:
- 維護高度數組: 在初始化時,或者在列表項渲染完成后,獲取每個列表項的高度,并將其存儲到高度數組中。
- 計算起始索引: 遍歷高度數組,累加高度,直到累加的高度超過滾動條位置。 當前索引就是起始索引。
- 計算結束索引: 從起始索引開始,繼續遍歷高度數組,累加高度,直到累加的高度超過滾動條位置加上可視區域高度。 當前索引就是結束索引。
虛擬列表在哪些場景下不適用?
雖然虛擬列表可以大幅提升長列表的性能,但并非所有場景都適用。
- 列表項數量很少: 如果列表項數量很少,虛擬列表的優勢不明顯,甚至可能帶來額外的性能開銷。
- 列表項高度動態變化且頻繁: 如果列表項高度動態變化且非常頻繁,維護高度數組的成本會很高,可能會影響性能。
- 需要支持快速滾動: 如果需要支持快速滾動,虛擬列表可能會出現白屏或閃爍的情況。 需要進行額外的優化,例如預渲染一部分列表項。
如何避免虛擬列表渲染時的白屏或閃爍問題?
白屏或閃爍問題通常是由于渲染速度跟不上滾動速度造成的。 可以采取以下措施來緩解這個問題:
- 預渲染: 在可視區域之外,預渲染一部分列表項。 這樣可以在滾動時快速顯示內容,避免白屏或閃爍。
- 使用css transform: 使用CSS transform 來移動列表項,而不是直接修改DOM元素的top或left屬性。 CSS transform 的性能更好。
- 優化圖片加載: 如果列表項包含圖片,可以使用懶加載或預加載的方式來優化圖片加載。 避免一次性加載所有圖片,造成頁面卡頓。
- 使用雙緩沖技術: 使用兩個緩沖區,一個用于顯示,一個用于渲染。 在渲染完成后,將兩個緩沖區進行交換。 這樣可以避免渲染過程中出現白屏或閃爍。