當頁面渲染太多標簽時,會出現卡頓的,典型就是類似table數據太多時,非常卡頓。如果選擇分頁,沒必要討論,這兒只討論采用滾動的情況。解決思路很簡單,就是頁面不展示出來的元素,從頁面上刪除掉,最難點在於滾動條的處理,這兒分享一些細節思路,以上下滾動為例。
上下滾動表格
- 每一行固定高度,一次性獲取所有數據。
- 每一行不固定高度,一次性獲取所有數據。
- 每一行不固定高度,分批獲取數據。
首先,布局如下:

當只顯示可視區的內容時,overflow的標簽需要刪除掉,但是刪除了之后,滾動條會變化,甚至消失,因此可添加padding-top和padding-bottom,以此模擬內容高度。
第一類,所有數據都能根據計算獲得,需要一個scrollTop對應的顯示數據的對照表,當滾動條位置變化時,去對照表種查看需要顯示的數據,以此來渲染。當然不是每個scrollTop都去生成對照表,只需要某個范圍生成就行了,比如:[{2000:顯示數據}, {5000: 顯示數據}](表示分別表示 0-2000,2000-5000顯示的數據) 去對比第一個大於scrollTop的數據,獲取其值,就是需要顯示的數據。
** 這兒需要注意的是,顯示數據必須有重復,且重復能占滿屏幕以上,避免出現空白(第一次是0-100條,第二次是80-180條)*
第二類,就不好計算了,比如某一格里面內容太多,會令整行高度增加。可采用隱藏標簽(opacity:0),循環渲染每一行,拿到那一行的高度。此種方式簡單,也容易實現,不過計算渲染數據時,保證屏幕不出現空白的計算會復雜一點。隱藏標簽渲染時,使用分批渲染,比如每次渲染10行,使用 requestAnimationFrame,setTimeout或者promise處理一下,不至於卡死。
第三類,只知道當前數據是多少,無法計算總高度。可以采取與第二種類似的方式,使用隱藏標簽計算出每一行的高度,最終計算出得到數據的總高度。當滾動條滾到某個值時,觸發后續數據獲取。一樣的方式,重新計算出總高度。
所有方法都有個前提,就是每一行數據渲染是同步的,有些情況是先渲染出框,等獲取數據后填充框。這種類似table的布局,會非常麻煩,需要設置一個回調函數,等所有數據渲染完成后再獲取高度。
還有一種方式,或許會更簡單,但是效果上會差一些。方法就是在滾動條距離底部某個位置的時候,觸發記錄:
- 記錄這一批次每一行元素的offsetTop
- 計算出此批次數據對照的scrollTop以及此批次數據對應的scrollHeight
- 記錄scrollHeight(往回滾動時用)。
還需要在此時切換數據,新批次數據必須有重復數據,避免空白。這樣就可以邊滾動,邊記錄,最終記錄完成所有行數據的offsetTop,scrollTop范圍對應的批數據,以及此批的scrollHeight。父元素的paddingTop永遠是那批次數據第一行的offsetTop,而最大的scrollHeight - 當前批次數據的scrollHeight = paddingBottom。
其他優化,舉例vue,可以使用Object.freeze() 凍結只需要顯示的數據,盡量保證頁面元素少,是優化卡頓的有效方式,所以,能用v-if,盡量不要用v-show,能夠銷毀的組件,不必留着,如果為了減少請求,應當保存數據而不是保存標簽,keep-alive非必要不要使用。保存標簽很容易出問題,比如使用v-if彈窗表單組件,需要手動清空數據,而直接銷毀,代碼會非常簡潔。重新渲染花費不了多少時間的。如果計算量實在太大,可以使用分批計算,異步方式處理。其作用就是在處理間隙,讓用戶的操作事件能夠響應。
