Vue?-?Table表格渲染

前端項(xiàng)目經(jīng)驗(yàn)總結(jié) - Vue - Table表格渲染上千數(shù)據(jù)優(yōu)化(分享自知乎網(wǎng))https://zhuanlan.zhihu.com/p/53455289?utm_source=com.jianshu.haruki&utm_medium=social&utm_oi=1020077929602007040

Vue - Table表格渲染上千數(shù)據(jù)優(yōu)化

Vue - Table表格渲染上千數(shù)據(jù)優(yōu)化

8 個(gè)月前 · 來自專欄 前端項(xiàng)目經(jīng)驗(yàn)總結(jié)

這次項(xiàng)目經(jīng)驗(yàn)會(huì)談?wù)劷?jīng)常在項(xiàng)目中哗蜈,針對(duì)成千上萬數(shù)據(jù)渲染優(yōu)化的不斷探索來談?wù)勛约旱捏w會(huì),其目的就是保證用戶瀏覽上萬條數(shù)據(jù)的時(shí)候访得,UI要很流暢,確保用戶操作過程中不會(huì)出現(xiàn)UI卡頓或者最糟糕的情況衷佃,直接瀏覽器奔潰。

其優(yōu)化目錄如下,由于內(nèi)容很多,會(huì)分兩篇文章進(jìn)行研究淮韭,

本文章主要會(huì)圍繞如何設(shè)計(jì)一個(gè)虛擬滾動(dòng)來渲染成千上萬的數(shù)據(jù)垢粮。

1.表格布局(To be continue)

2.Reflow & Repaint渲染方式(TBC)

3.瀏覽器API:window.requestAnimationFrame 渲染優(yōu)化(TBC)

4.虛擬滾動(dòng):Virtual scrolling

GITHUB-Vue Table表格渲染上千數(shù)據(jù) : 后續(xù)會(huì)加入Filter功能,針對(duì)Reflow和RequestAnimationFrame的渲染效果會(huì)更加明顯

虛擬滾動(dòng)(Virtual scrolling)篇

關(guān)鍵字:虛擬行渲染靠粪,transform數(shù)據(jù)移動(dòng)蜡吧,列表節(jié)點(diǎn)渲染優(yōu)化

NK0 - Background

本文的前提條件是前端已經(jīng)緩存了上萬條數(shù)據(jù),當(dāng)渲染數(shù)據(jù)到UI上時(shí)占键,如何讓用戶在使用過程中不會(huì)遭到卡頓昔善,用起來不流暢?

之前很多項(xiàng)目由于數(shù)據(jù)大體圍繞在上千左右畔乙,當(dāng)結(jié)果集結(jié)合其它功能君仆,例如Filter數(shù)據(jù)過濾功能一起使用的話,會(huì)采用以下幾種方式去優(yōu)化列表渲染,

(1)Version1: 采用display:none(對(duì)應(yīng)Vue的指令是v-show)返咱,再結(jié)合v-for中的Key來復(fù)用DOM元素和隱藏元素 =》該方式會(huì)導(dǎo)致UI Reflow即回流钥庇,所以UI會(huì)經(jīng)常出現(xiàn)短暫的卡頓,用戶體驗(yàn)不是很好

(2)Version2: 采用window對(duì)象的內(nèi)置API咖摹,即window.requestAnimation()评姨,來渲染成千上萬條數(shù)據(jù),即模擬動(dòng)畫效果讓用戶操作起來特別的順暢萤晴。

以上兩種方式都有個(gè)特點(diǎn):DOM中會(huì)插入數(shù)據(jù)量大小的元素吐句,盡管有些數(shù)據(jù)被隱藏起來,但都會(huì)導(dǎo)致HTML文件size會(huì)非常大店读,低端設(shè)備的速度會(huì)明顯變慢嗦枢。

所以基于以上兩種方式,還不能夠滿足去渲染上萬條數(shù)據(jù)两入!

也因此trigger出本文的主題 - 基于VUE列表的虛擬滾動(dòng)

本文的虛擬滾動(dòng)方式主要圍繞著

(1)虛擬行渲染:緩存數(shù)據(jù)和篩選數(shù)據(jù)净宵,除了要保留用戶的可視區(qū)域的數(shù)據(jù),還考慮到了如果用戶的滾動(dòng)范圍不是很大的話裹纳,就不需要去刷新頁面择葡,所以DOM中的元素除了可視區(qū)域的數(shù)據(jù),會(huì)多保留視圖的上下留閑數(shù)據(jù)剃氧。

(2)布局:主要是為了假裝所有數(shù)據(jù)元素都有在占用空間敏储,瀏覽過React virtualized庫,發(fā)現(xiàn)它在復(fù)用已有DOM元素的基礎(chǔ)上朋鞍,通過css的絕對(duì)定位position:absolute + top:偏移量已添,來移動(dòng)數(shù)據(jù),但是這樣滾動(dòng)元素的時(shí)候會(huì)引起瀏覽器回流滥酥,會(huì)增加更多的渲染開銷更舞,所以我這邊會(huì)采用另一種方式,即transform:translateY(偏移量)來優(yōu)化數(shù)據(jù)移動(dòng)坎吻,因?yàn)樵揅SS3元素不會(huì)引起Reflow和Repaint缆蝉。

(3)DOM復(fù)用:使DOM節(jié)點(diǎn)的數(shù)量保持在較低的水平,因?yàn)镈OM節(jié)點(diǎn)如果太大而無法管理瘦真,低端設(shè)備的速度會(huì)明顯變慢刊头,所以我們能做的是復(fù)用已有的DOM節(jié)點(diǎn)和減少每個(gè)節(jié)點(diǎn)的布局、樣式和繪制方面的開銷成本诸尽。而VUE提供了數(shù)組全新賦值和變異方法來復(fù)用DOM和減少DOM操作原杂,但是數(shù)組全新賦值的開銷成本比數(shù)組變異開銷更大,所以針對(duì)用戶的滾動(dòng)速度來優(yōu)化列表渲染您机。

NK1 - 虛擬滾動(dòng)(Virtual Scrolling)

TL;DR: 復(fù)用DOM元素穿肄,隱藏不在視圖內(nèi)的其它元素年局,使用占位符來延遲刷新數(shù)據(jù)。

下面是當(dāng)我們用虛擬滾動(dòng)方式來處理上萬條數(shù)據(jù)在UI的呈現(xiàn)效果被碗,

從上面的結(jié)果發(fā)現(xiàn)某宪,當(dāng)用鼠標(biāo)滾動(dòng)的時(shí)候,

(1)盡管數(shù)據(jù)量是上萬條锐朴,但是HTML標(biāo)簽元素永遠(yuǎn)就那么幾個(gè)

(2)有些HTML元素會(huì)被更新兴喂,而有些HTML元素不會(huì)變化

虛擬滾動(dòng)能夠很好優(yōu)化上萬條數(shù)據(jù)的呈現(xiàn)跟的上用戶滾動(dòng)操作的速度,猶如動(dòng)畫般的交互順滑焚志。

接下來會(huì)分享下虛擬滾動(dòng)的設(shè)計(jì)實(shí)現(xiàn)衣迷,

NK2 Virtual scrolling - Props Design(屬性設(shè)計(jì))

(1)viewport:這里看成是Table數(shù)據(jù)的可視區(qū)域,需要提供可視區(qū)域的高度酱酬,用于計(jì)算實(shí)際渲染在DOM中Item的數(shù)量壶谒。

(2)size:每條數(shù)據(jù)在DOM中占用的高度,用于統(tǒng)計(jì)虛擬列表的高度膳沽,默認(rèn)每行的高度為40px汗菜。

(3)Render Items:真正曾現(xiàn)在用戶視覺上的items。

(4)Remain Items:(向上/向下)可是區(qū)域之外的留閑數(shù)據(jù)高度挑社,不顯示在viewport中陨界,但是存在DOM中,其用于當(dāng)用戶滾動(dòng)的距離不是很大的時(shí)候痛阻,UI不需要重新去渲染菌瘪,為滾動(dòng)做了一層留長(zhǎng)優(yōu)化。

接下來講一下虛擬滾動(dòng)特征阱当,

NK3 Virtual scrolling - Virtual Row Render(虛擬行渲染)

Virtual Row Render - 在已知viewport有高度情況下俏扩,我們可以先把每條數(shù)據(jù)看作是每一個(gè)獨(dú)立的行數(shù)據(jù),用索引來標(biāo)記每條數(shù)據(jù)弊添,用Map對(duì)象封裝這些塊數(shù)據(jù)录淡,存在瀏覽器的內(nèi)存中,當(dāng)滾動(dòng)事件被觸發(fā)的時(shí)候油坝,我們只需要渲染能夠映射在viewport中對(duì)應(yīng)的塊數(shù)據(jù)嫉戚,而不是遍歷渲染所有塊,能有效的減少HTML file size免钻。

key = index彼水,我們用數(shù)據(jù)索引和每條數(shù)據(jù)的高度來作為虛擬塊Map的Key崔拥,結(jié)合滾動(dòng)的距離和viewport的高度极舔,來標(biāo)記實(shí)際要渲染在DOM中的items,即

另外每個(gè)Item會(huì)根據(jù)Key值來定義其顯示范圍链瓦,如item1的key為0拆魏,則它的顯示范圍應(yīng)該是[0~40)這個(gè)區(qū)間盯桦,而item2區(qū)間為[40,80),以此類推……其目的是用于計(jì)算item的顯示區(qū)間是否在滾動(dòng)的范圍內(nèi)渤刃。

NK4 Virtual scrolling - 數(shù)據(jù)移動(dòng)設(shè)計(jì)

場(chǎng)景:當(dāng)我們的列表有上萬條數(shù)據(jù)拥峦,我們給定

每條數(shù)據(jù)的高度為40px,即itemHeight = 40px,

留閑高度為80卖子,即remainHeight = 80px,

而表格的可視區(qū)域高度為80px略号,即viewportHeight = 80px,

由此我們可以設(shè)計(jì)存在DOM中的items最多可以渲染6條。

所以當(dāng)我們?cè)跐L動(dòng)的時(shí)候洋闽,當(dāng)滾動(dòng)的距離到item12的高度的時(shí)候玄柠,此時(shí)我們希望可視區(qū)域的數(shù)據(jù)會(huì)被刷新,并且DOM元素會(huì)被跟新如下诫舅,

但是羽利,當(dāng)用戶滾動(dòng)的距離不是很大的話,例如它從item1滾動(dòng)到item4的時(shí)候刊懈,我們希望DOM不需要被跟新这弧,即

接著我們來細(xì)節(jié)化模擬數(shù)據(jù)滾動(dòng),如下圖

實(shí)線虚汛,例如item1 ~ item6匾浪,代表已經(jīng)在DOM中存在的數(shù)據(jù)

黑色實(shí)體,例如item1~item2泽疆,顯示在可視區(qū)域的數(shù)據(jù)户矢,

反之灰色實(shí)體item3~item6的被隱藏了起來

而虛擬列表的數(shù)據(jù)Size決定了可視區(qū)域滾動(dòng)條的大小

滾動(dòng)公式設(shè)計(jì),主要是如何確定Dom items的高度范圍殉疼,即

向下滾動(dòng)場(chǎng)景模擬: 當(dāng)我們滾動(dòng)的距離 小于 向上的remainHeight(80px)的時(shí)候梯浪,

其minDomItemHeight = 0,

maxDomItemHeight = viewportHeight + 2 * remainHeight(向上/向下留閑) = 240px;

但DOM中的Items為 [item1,item2,item3,item4,item5,item6] -> 沒有變化

當(dāng)我們向下滾動(dòng)到100px的時(shí)候,

DOM中的Items為 [item1,item2,item3,item4,item5,item6,item7] -> 新增了一個(gè)item7

當(dāng)我們滾動(dòng)到120px的時(shí)候瓢娜,

DOM中的Items為 [item2,item3,item4,item5,item6,item7] -> item1DOM元素被移除了挂洛。

……

所以按照用戶滾動(dòng)的趨勢(shì),我們統(tǒng)計(jì)了滾動(dòng)距離時(shí)眠砾,我們的數(shù)據(jù)渲染情況如下

即滾動(dòng)公式

向下取整 minItemHeight = scrollTop > remainHeight ? Math.floor((scrollTop - remainHeight)/ itemHeight) * itemHeight : 0;

向上取整 maxItemHeight = scrollTop > remainHeight ? (Math.ceil((scrollTop + viewPortHeight + remainHeight) / itemHeight) )* itemHeight : defaultRenderItemsHeight;

而defaultRenderItemsHeight需要跟viewport的高度和留長(zhǎng)高度虏劲,來決定渲染在DOM中item的數(shù)量.

const renderItems = Math.ceil(viewPortHeight / itemHeight) + 2 * remainItems;

const renderItemsHeight = renderItems * itemHeight;

NK5 Virtual scrolling - CSS3 transform優(yōu)化數(shù)據(jù)移動(dòng)

當(dāng)數(shù)據(jù)往上/下滾動(dòng)的時(shí)候,我們需要復(fù)用和移動(dòng)DOM中的元素褒颈,使其能根據(jù)我們算出的高度顯示在viewport中柒巫,一般情況會(huì)使用position:relative + top來進(jìn)行元素垂直方向的偏移,但是我們知道當(dāng)采用top屬性谷丸,它會(huì)使UI Reflow,性能不是很好堡掏,所以我們采用CSS3中的transform變形屬性來移動(dòng),其優(yōu)點(diǎn)是不會(huì)是UI重新的Reflow和Repaint.

transform - translateY的特點(diǎn)如下刨疼,

(1)范圍:適用所有的HTML標(biāo)簽元素

(2)它是指Y軸(垂直軸)方向的移動(dòng)泉唁,單位可以是px,em或百分比等

(3)當(dāng)y為正時(shí)鹅龄,表示元素在垂直方向向下移動(dòng);

當(dāng)y為負(fù)時(shí)亭畜,表示元素在垂直方向向上移動(dòng)扮休,跟我們的數(shù)學(xué)坐標(biāo)系不同

(4)性能優(yōu)化:元素移動(dòng),不會(huì)引起Reflow和Repaint

所以我們?cè)诔跏蓟?跟新要渲染數(shù)據(jù)的時(shí)候拴鸵,可以為其綁定translateY的值

(translateY=itemIndex * itemHeight)玷坠,如,

NK6 Virtual scrolling - 列表渲染優(yōu)化

我們來比較下數(shù)組跟新的兩種方式:變異方法和替換數(shù)組如下

即變異方式和替換數(shù)組方式中的索引值替換劲藐,會(huì)復(fù)用需要更改的DOM元素侨糟,

而數(shù)組全新賦值方式則會(huì)復(fù)用渲染整個(gè)列表(DOM元素移位),

當(dāng)滾動(dòng)元素的時(shí)候瘩燥,數(shù)組全新賦值節(jié)點(diǎn)渲染情況如下秕重,

而局部跟新節(jié)點(diǎn)的渲染取下,

所以當(dāng)我們用translateY屬性來進(jìn)行元素位置移動(dòng)的時(shí)候厉膀,

即使元素插入DOM的位置不是按順序排列的溶耘,但是translateY能確保其元素它在垂直方向的距離如下圖,

紅色區(qū)域代表當(dāng)鼠標(biāo)往下滾動(dòng)的時(shí)候,需要跟新的DOM元素

黃色區(qū)域則代表不需要重新渲染

所以針對(duì)列表的優(yōu)化渲染服鹅,建議不要對(duì)數(shù)組全新賦值凳兵,可以考慮用數(shù)組替換 + 數(shù)組變異的方式來復(fù)用已有的節(jié)點(diǎn)。如果前后數(shù)組變化完全不相等的話企软,可以直接使用數(shù)組全新賦值方式庐扫。

彩蛋: 使用AVA成為該項(xiàng)目的測(cè)試驅(qū)動(dòng)框架,整個(gè)過程采用的是TDD(測(cè)試驅(qū)動(dòng)開發(fā))來實(shí)踐數(shù)據(jù)移動(dòng)的功能模塊仗哨,例如形庭,

當(dāng)要計(jì)算一個(gè)minDomItemHeight的時(shí)候,其測(cè)試用例如下厌漂,

而功能實(shí)現(xiàn)塊:

當(dāng)要計(jì)算一個(gè)maxDomItemHeight的時(shí)候萨醒,其測(cè)試用例如下,

當(dāng)要計(jì)算一個(gè)minDomItemHeight和maxDomItemHeight的時(shí)候苇倡,其測(cè)試用例只需要一個(gè)來驗(yàn)證就行富纸,其結(jié)果如下,

而功能實(shí)現(xiàn)

編輯于 2019-03-20

Vue.js

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
禁止轉(zhuǎn)載旨椒,如需轉(zhuǎn)載請(qǐng)通過簡(jiǎn)信或評(píng)論聯(lián)系作者晓褪。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市综慎,隨后出現(xiàn)的幾起案子涣仿,更是在濱河造成了極大的恐慌,老刑警劉巖寥粹,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件变过,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡涝涤,警方通過查閱死者的電腦和手機(jī)媚狰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來阔拳,“玉大人崭孤,你說我怎么就攤上這事『Γ” “怎么了辨宠?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)货裹。 經(jīng)常有香客問我嗤形,道長(zhǎng),這世上最難降的妖魔是什么弧圆? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任赋兵,我火速辦了婚禮,結(jié)果婚禮上搔预,老公的妹妹穿的比我還像新娘霹期。我一直安慰自己,他們只是感情好拯田,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布历造。 她就那樣靜靜地躺著,像睡著了一般船庇。 火紅的嫁衣襯著肌膚如雪吭产。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天鸭轮,我揣著相機(jī)與錄音垮刹,去河邊找鬼。 笑死张弛,一個(gè)胖子當(dāng)著我的面吹牛荒典,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播吞鸭,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼寺董,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了刻剥?” 一聲冷哼從身側(cè)響起遮咖,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎造虏,沒想到半個(gè)月后御吞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體麦箍,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年陶珠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了挟裂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡揍诽,死狀恐怖诀蓉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情暑脆,我是刑警寧澤渠啤,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站添吗,受9級(jí)特大地震影響沥曹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜碟联,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一架专、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧玄帕,春花似錦部脚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鹰椒,卻和暖如春锡移,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背漆际。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工淆珊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人奸汇。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓施符,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親擂找。 傳聞我的和親對(duì)象是個(gè)殘疾皇子戳吝,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 目錄一、介紹二贯涎、渲染引擎三听哭、解析與DOM樹構(gòu)建四、渲染樹構(gòu)建五、布局六陆盘、繪制七普筹、動(dòng)態(tài)變化八、渲染引擎的線程九隘马、CS...
    饑人谷_米彌輪閱讀 2,452評(píng)論 0 10
  • 本文闡述的內(nèi)容: Dom操作之重繪重排 結(jié)合vue源碼理解Vitrual Dom原理 理解這一部分是為了的目的: ...
    Jmingzi_閱讀 1,558評(píng)論 4 4
  • 一太防、瀏覽器如何渲染網(wǎng)頁 要了解瀏覽器渲染頁面的過程,首先得知道一個(gè)名詞——關(guān)鍵路徑渲染祟霍。關(guān)鍵渲染路徑(Critic...
    Srtian閱讀 989評(píng)論 1 3
  • ?? React 的列表渲染 key 與 Reconciliation List and Keys - ReactR...
    云之外閱讀 13,365評(píng)論 2 11
  • 瀏覽器 在介紹瀏覽器工作流程之前,先了解一下主流瀏覽器的基礎(chǔ)結(jié)構(gòu)盈包,本文所介紹的瀏覽器主要為開源的Chrome沸呐,F(xiàn)i...
    蔡森嶼閱讀 528評(píng)論 0 1