定義問題
先前有對大資料渲染進行調察研究,得知瞬間大資料的渲染,會造成瀏覽器卡頓不回應,並得出可以透過分時渲染、捲動式渲染、虛擬列表,解決高併發渲染的問題。
而籃足球比賽比分列表,一遇假日就會有1000~2000 筆的比賽需要同時顯示,且依使用者需求,不能分頁顯示。
虛擬捲軸 VS 分段渲染
虛擬捲軸概念
設計概念,一開始先傳入高度,並將每一筆 item 的 邊界 getBoundingClientRect 結果快取起來,直到渲染出來會重新計算快取高度,透過容器的卷軸事件,css translate3d,操作 y 軸,達到到平移捲動的效果,只有利用實體捲軸的高度及捲動事件,但不是透過實體捲軸顯示,因此這就是為什麼稱之虛擬捲軸的原因。
分段渲染概念
跟虛擬捲軸最大的差異,分段捲軸一開始採用的用的真實的實體捲軸,除buffer item 其餘都僅渲染空 div 支撐捲軸高度,直到捲到 buffer item 時,才開始渲染該區間的元件。
和傳統渲染效能比較
拿 1000 筆左右的數據,資料採用分段渲染和一般炫染效能做比較,因為要渲染的筆數少了,其實可以預期效能差了快1x倍之多。
一般渲染
分段渲染
使用方式
虛擬捲軸
<VirtualScroller
:list="news"
class="news-list-wrapper"
:item-default-height="100"
:uni-key="'id'"
:enable-scroll-up="!isLastPage"
:auto-load-more="true"
:enable-scroll-down="true"
:buffer-size="4"
@scrollDown="scrollDown"
@scrollUp="scrollUp"
>
<template #default="slotScope">
<NewsCard
:id="'news-' + slotScope.item[slotScope.uniKey]"
:key="'news-' + slotScope.item[slotScope.uniKey]"
:start="slotScope.start"
:end="slotScope.end"
:index="slotScope.index"
:h="slotScope.height"
:news="slotScope.item"
:sport-id="slotScope.item.sportId"
/>
</template>
</VirtualScroller>
分段捲軸
<PartRenderingScroller :scroll-element-id="'schedule-container'" :list="early.early" :item-default-height="100" uni-key="matchId" class="schedule-list p-l-20 p-r-20" :buffer-size="50">
<template #default="slotScope">
<ScheduleCard
:id="'live-' + slotScope.item[slotScope.uniKey]"
:key="'live-' + slotScope.item[slotScope.uniKey]"
:class="{'p-t-20':slotScope.index===0}"
:start="slotScope.start"
:end="slotScope.end"
:index="slotScope.index"
:h="slotScope.height"
:sport-id="sportId"
:schedule="slotScope.item"
:lottery-type="lotteryType"
/>
</template>
</PartRenderingScroller>
如果要設計的東西,未來要套虛擬捲軸或分段捲軸時,可能要留意一下
- 分段捲軸 Desktop 網站架構是是 body 捲動,而 mobile 架構是 div 在捲動,可以透過傳入 scrollElementId 決定,沒傳則是 body 捲動
- list 外容器,不能撐padding ,要由 item 去支撐撐高,item 最外層不能用 margin,因為用程式抓寬高抓不到 margin => 之後或許可以擴充用 window.getComputedStyle 來擴充支援 margin
- list-item 的 css 要加 box-sizing: border-box; 不然不會把 padding 算進去
- 分段或虛擬捲軸, 結構要用 div ,不能用 ul li 或table 等等,因為虛擬捲軸組件會額外渲染出額外的 div
- 為了重算高度,list item 一定要給 id ,並用減號分隔 => “-“
- 儘量避免和其他有用到捲軸的套件整合 better scroller、vant dialog、 swiper,因為每個套件有自己的生命週期,如果一定整合進來,可能自己擴充組件功能會比較不會衝突
實作過程遇到的問題
1. 評估過 vue-virtual-scroller and vue-virtual-scroll-list 簡單功能可以套用,但遇到複雜的情境就不好套用。
原始碼也不易理解及改動,最後決定自己刻了。
2. 而在實作過程中發現,桌面版非滿版網頁,或是需要多個虛擬捲軸同時存在,則使用者體驗不是這麼好,會變成雙出現內外卷軸的情境,對於使用者來說並不是很好的體驗,
此時情境可能不適合用虛擬捲軸,而是要分段渲染卷軸。
3. 每一筆資料都不同高度,分段元件及虛擬捲軸得支援動態高度。
元件初始化時,先給預設高,並快取起來,直到渲染出來,在去更新高度,postion 的快取。
4. 虛擬捲軸在套聊天室時發現筆數一多,從最舊的資料渲染到最新時,透過自動捲動渲染,顯示時就會變得非常卡頓。
聊天室最後將渲染索引反過來渲染,最先渲染使用者看得到的,直到使用者往上捲動。
5. 先前的 Height light 資料機制,是透過操作 dom 去給 class,只要元件一重新渲染就會消失。
改用 vuex 去記錄 hight light 的 match ,依據 vuex 去判透過 vue bind 判斷需不需要 hight light。
6.同一頁有有 n 個資料,需要顯示分組相關資訊
可以將分組資訊塞到該組第一個卡片上或是採用多個分段捲軸。
7.整合 vue better scroll( 上拉整理、下拉取得資料) 、 swiper
上述都是類似虛擬捲軸機制的套件,如果要整合捲軸類型的套件,最好還是自己擴充虛擬捲軸,不然要解決兩個虛擬捲軸機制在裡面衝突。
相關程式碼
待整理