Fusion Design體系在經歷阿里巴巴集團內部三年多的錘鍊後終於在上個月對外開放了,作為設計系統的基礎骨架——Next元件庫也在正式開源啦??
Fusion Next(包名@alifd/next)是一個基於 React 實現,面向 PC 端的可配置元件庫。為阿里集團2000+個專案服務的同時,沉澱出了不少基礎元件,現在已經達到50+。這個系列將通過實際需求場景,來介紹Fusion元件庫的各種有意思的功能、分析實現原理,歡迎討論?
使用場景
長列表情境下,例如一個有上千條資料的商品類目選擇,初始化選項組時間較長,有明顯示卡頓。
原因分析
在React環境下,卡頓可能的原因有很多種,例如隨意setState、未設定shouldComponentUpdate父元件更新引起所有子元件重繪、DOM節點多層級深導致HTML解析過慢等。在當前場景下,原因顯然是最後一個,頁面DOM節點數過多,導致虛擬DOM的對比、渲染消耗過大,頁面卡頓。
解決方案
無論是IOS、Android客戶端,還是H5、PC頁面,業內對於這種長列表的優化都有一致的呼聲——虛擬滾動。
既然是DOM節點多導致的問題,那就減少節點數。頁面DOM結構設計不合理,需要優化DOM結構,移除不必要的節點,減少DOM操作耗費的資源。
效果
先來一組對比資料,對比的是從開始渲染到渲染結束所耗費的時長。從圖中可以看出當資料量越來越大時,虛擬滾動表現突出,耗費的時間保持在80ms以內。
原理
螢幕高度有限,使用者每次看到的項可能只有十幾個,維護一個陣列domArray,用來存放最終展示到頁面上的列表項,將待渲染列表項個數始終控制在一定範圍之內。在滾動時,根據縱向滾動的位置動態更新這個陣列,並配合transform: translateY達到無限滾動的效果。
關鍵點有兩個:
-
列表體transform: translateY(offset) 值的變化
-
最終渲染到頁面上的陣列domArray的更新規則
1. 相對位移如何變化
translateY(offset)可以使所在元素相對父元素向下偏移offset。jsfiddle.net/youluna/w6d…
使用者的上下滾動會引起可視區陣列domArray包含元素的變化,當陣列的首個元素從第 from 個切換為 from+1 的時,整個列表看起來是向上瞬移了第from個元素的高度,這時利用translateY增加第from個元素的高度,就能維持 第 from+1 個元素在相對位置不變。
2. 陣列何時更新
domArray儲存著使用者可能會看到的那部分列表項,一般取自超長源資料中的一段[from, from + size] 例如下圖中的[36, 53]。
-
from值是如何來的?
為保證domArray元素保持較少個數,需要記錄滾動距離scrollTop,在滾動時動態增刪陣列內元素。保證如下公式成立,根據scrollTop的變化動態更新from的值:
前from個元素高度的加和 <
滾動距離scrollTop – bufferHeight <
前from + 1個元素高度的加和
-
from + size 值需要滿足什麼要求?
要求[from, from + size] 這些元素渲染到頁面上的總高度(domsHeight)剛好大於可視區域高度(visibleHeight)+緩衝區(buffer*2)高度,即:
domsHeight >
visibleHeight + bufferHeight*2
一旦高度條件不滿足,就重新計算更新from、size的值,從而更新domArray。
domArray的更新與translateY值的改變相配合,營造視覺上連續不斷的滾動效果。Fusion已內建VirtualList元件,目前已經可以與Select元件、Cascader元件配合使用,Table元件較為複雜但也通過自身改造支援了無限滾動。
Fusion Next元件庫還有各種有意思的功能,期待大家發掘,快來體驗使用吧~ ?戳我檢視 說到體驗使用,就想起了元件倉庫 github.com/alibaba-fus…,我將在github繼續扮演commiter,歡迎各位大佬前來把玩,issue/PR兩開花??