前言
? ? 很早之前面視的時(shí)候有被問道過,當(dāng)時(shí)確實(shí)是沒遇到過這個(gè)問題,因此是直接回復(fù)了不知道授艰。雖然最后并沒有對(duì)面視產(chǎn)生很大的影響败砂,卻也一直是心中的一塊"病"赌渣,時(shí)不時(shí)的會(huì)想起來(lái)
? ? 這不,最近又想起來(lái)這事昌犹,故打算探究一波
什么是長(zhǎng)列表
? ? 長(zhǎng)列表是指一次性返回n條數(shù)據(jù)交由前端渲染坚芜,如何做到頁(yè)面不卡或性能最優(yōu)
示例
? ? 使用mock模擬一萬(wàn)條數(shù)據(jù)返回并一次性渲染,會(huì)發(fā)現(xiàn)頁(yè)面有長(zhǎng)時(shí)間的空白展示斜姥,如果涉及的dom結(jié)構(gòu)更為復(fù)雜鸿竖,則該時(shí)間將進(jìn)一步拉長(zhǎng)沧竟。因此要想辦法將這段"空窗期"填補(bǔ)上,先讓用戶"有事可做"
解決思路
? ? 為了避免用戶誤以為是程序缺陷缚忧,需要先將用戶可視區(qū)域內(nèi)的內(nèi)容展示出來(lái)悟泵。大致有如下三種:
????????分頁(yè):每次加載一部分,逐漸累加
? ??????分片加載:先把首屏加載闪水,剩下部分交瀏覽器空閑時(shí)繼續(xù)累加
? ??????虛擬列表:使用js動(dòng)態(tài)替換首屏內(nèi)容糕非,而不是加載更多
分片加載
? ??createDocumentFragment創(chuàng)建的dom片段在假如body之前是存在于內(nèi)存中的,故對(duì)其進(jìn)行的dom操作并不會(huì)引起瀏覽器的重繪或者重排等操作球榆,對(duì)于每一個(gè)li的內(nèi)容可以使用該api生成好后再向dom中插入
? ??requestAnimationFram能確保在每次刷新前被執(zhí)行一次朽肥,相比setTimeout其避免了丟幀
? ? 利用這兩個(gè)api,我們率先渲染可視區(qū)的n條數(shù)據(jù)芜果,后續(xù)的渲染則在屏幕刷新時(shí)繼續(xù)
虛擬列表
? ??頁(yè)面結(jié)構(gòu)
? ? ? ? ? ? ? ? 我們需要給最外層的容器設(shè)置可視區(qū)的高度
? ? ? ? ? ? ? ? 為了模擬滾動(dòng)條的高度變化鞠呈,不能直接替換10條數(shù)據(jù),故需要一個(gè)div標(biāo)識(shí)全部數(shù)據(jù)的高度以撐開可視區(qū)容器
? ? ? ? ? ? ? ? 需要一個(gè)div來(lái)展示真正的十條數(shù)據(jù)
? ??渲染靜態(tài)可視區(qū)數(shù)據(jù)
? ? ? ? 使用slice不斷的從總數(shù)據(jù)data中截取指定長(zhǎng)度的數(shù)據(jù)來(lái)做到動(dòng)態(tài)替換以保證頁(yè)面中始終只有n條數(shù)據(jù)右钾,為了達(dá)到這一目地蚁吝,需要實(shí)時(shí)計(jì)算記錄開始及結(jié)束位置,并單獨(dú)使用數(shù)組作為可視區(qū)的待渲染容器舀射,則初始值如下
? ??支持滑動(dòng)
? ? ? ? 在頁(yè)面滑動(dòng)過程中更新開始及結(jié)束位置并從data中截取對(duì)應(yīng)的列表數(shù)據(jù)
? ??修正缺陷
? ? ? ? 此時(shí)從控制臺(tái)的頁(yè)面結(jié)構(gòu)中來(lái)看已經(jīng)完成了虛擬列表的功能窘茁,但是頁(yè)面的顯示卻是不對(duì)的:可視區(qū)被滾跑了
? ? 為此,需要利用translate3d做一次"回滾"處理:向上滾動(dòng)是三個(gè)半脆烟,則可視區(qū)向下回滾三個(gè)半
? ? ? ? 此時(shí)山林,頁(yè)面效果如下