如何讓vue長列表快速加載
vue-long-list-load,滿足特殊條件的長列表加載。支持:1、各個節點高度不同且可自由設定 2、各個節點可修改不影響加載效果 3、可精確的滾動到指定位置。
背景
有個長列表渲染的需求,本來用vue-virtual-scroll-list的。但是每個節點的高度不一樣,用著有點問題。如果也有相應的需求可以參考下我的方案。歡迎大傢交流!
vue-long-list-load
滿足特殊條件的的長列表加載。 列表內各個節點高度不一,各個節點可以進行修改,定位到指定位置指定節點。 www.npmjs.com/package/vue…
主要內容
- vue-long-list-load 與 vue-virtual-scroll-list 對比
- vue-long-list-load實現思路
- 基本代碼
- 插件使用方式
- 插件參數說明
一、組件對比
vue-long-list-load ,vue-virtual-scroll-list兩個插件各有優缺點,當我們在選擇插件的時候要選擇最適合應用場景的插件。下面是兩個插件的基本功能對比。vue-long-list-load 主要特點是適用於各個節點尺寸不統一的場景,vue-virtual-scroll-list更適用於高度統一節點以列表長度以w計的這種列表。
組件 | vue-long-list-load | vue-virtual-scroll-list |
---|---|---|
npm地址 | www.npmjs.com/package/vue… | www.npmjs.com/package/vue… |
核心 | 先空dom占位,顯示區域內組件掛載顯示 | 計算當前顯示區域內要顯示的組件掛載 |
橫向 | 支持 | 支持 |
列表內高度一致 | 支持 | 支持 |
列表內高度不一致 | 支持 | 支持不好 |
滾動到指定組件 | 支持 | 高度不一致時計算不準確 |
滾動事件 | 支持 | 支持 |
組件高度改變事件 | 支持 | 支持 |
隱藏組件 | 支持 | 不支持 |
二、實現思路
主要思想就是通過\color{red}{虛擬dom}虛擬dom占位各個節點,根據可顯示視口的變化來展示該展示的節點。影響可顯示視口的因素的監聽,頁面整體寬高變化、節點高度變化、頁面的滾動定位到某一個節點等都可能會影響到視口的變化。當視口發生變化後計算可顯示的節點,將可顯示的節點掛載上節點的組件,不在視口內的節點銷毀組件緊保留一個空的div。下圖為實現思路的流程圖。
三、關鍵方法源碼分析
主入口html結構如下,\color{red}{v-for}v−for 展示長列表長度的的節點,並且通過:style 來設置一個\color{red}{最小高度}最小高度,設置最小高度的原因是這個高度值可能不準確,當真正組件渲染完之後計算出最準確的高度,如果直接height的話可能會使節點內的組件展示不全。同時每個節點設置唯一id(scrollItem_ 唯一標識),在根據數據獲取dom信息時候使用。節點組件定義瞭唯一的class (long-item- 唯一標識),主要用來掛載真實列表組件,同時監聽組件的高度變化。showList[index]來控制節點是否時候顯示的唯一標識。
<!--html代碼--> <template> <div : :style="{'min-height': (item.height>=0?item.height:height) + 'px'}" :key="item[dataKey]" :id="'scrollItem_' + item[dataKey]" v-for="(item,index) in dataList" > <long-item v-if="showList[index]" :dataKey="dataKey" :item="item" :boxHeight="item.height||0" :direction="direction" :heightChange="heightChange" :extendCcomments="extendCcomments"> </long-item> </div> </template>
當showList[index]為true的時候,對應的節點顯示。long-item 在mounted生命周期時,回調extendCcomments。通過\color{red}{Vue.extend Profile}Vue.extendProfile掛載到對應的dom上。componentProps是節點組件傳過來的一些參數,在掛載的時候全部掛載上。
<!--掛載組件--> extendCcomments(item){ this.componentProps.item=item var Profile = Vue.extend(this.dataComponent); // 創建 Profile 實例,並掛載到一個元素上 new Profile({ propsData:this.componentProps } ).$mount('.long-item-'+item[this.dataKey]); }
通過\color{red}{element-resize-detector}element−resize−detector來監聽dom尺寸的變化,每個節點的寬高發生變化的時候,並且與原來的尺寸不一樣回調heightChange方法,進行尺寸的更新及顯示節點的操作計算。
<!--每個節點尺寸發生變化--> this.$nextTick(()=> { this.$DomListener.listenTo(document.getElementById('long-item-'+this.item[this.dataKey]), (element)=>{ if(this.boxHeight != element[this.directionConfig.width]){ this.heightChange(this.item, element[this.directionConfig.width]) } }) });
獲取可顯示的視口區域的方法,頁面滾動和尺寸變化都會調用到這個方法,所以這個方法在調用的時候做防抖處理300ms內有連續調用隻會執行最後一次調用,要不然會頻繁計算影響性能。可顯示視口區域計算方式是當前視口 及 前後兩個視口總共三個視口的尺寸。這樣在小的滾動范圍內會有較好的體驗。
getShowLimit(startTop) { const scrollTop = startTop || this.scrollWrap[this.directionConfig.scrollTo] || 0; // 滾動距離 this.viewClientHeight = this.scrollWrap[this.directionConfig.width]; // 可視區域高度 this.scrollTop = scrollTop this.showStart = scrollTop - this.viewClientHeight this.showEnd = scrollTop + 2*this.viewClientHeight if(this.setTopTimer){ clearTimeout(this.setTopTimer) } this.setTopTimer = setTimeout(() => { this.setItemTopheight() }, 300); },
根據高度或者寬度來計算節點是否顯示,因為這個計算量比較大避免而且這個方法與其他方法沒有什麼關聯,直接單獨開一個\color{red}{獨立線程}獨立線程進行計算。通過引入\color{red}{simple-web-worker}simple−web−worker這個插件單獨開一個線程進行計算顯示節點。計算方法主要有三點:當前節點的開頭在顯示視口內、當前節點的結尾在顯示視口內、當前節點開頭和結尾都不在顯示視口內。分為這三種情況,隻要滿足一種情況,則該節點就顯示在顯示視口中。
// 根據高度計算節點是否顯示 setItemTopheight(){ let stsartId = this.dataList[0]&&this.dataList[0][this.dataKey] let startDom = stsartId && document.getElementById('scrollItem_'+stsartId) let startTop = startDom ? startDom[this.directionConfig.offset] : 0 this.worker = this.$worker.run((dataList,showStart,showEnd, startTop,hideIds,dataKey,height) =>{ let topHeight = startTop; // 題目頂部距離頂部距離 let bottomHeight = 0; // 題目底部距離頂部距離 let showList = [] for(let i=0,len=dataList.length;i<len;i++){ let item = dataList[i] if(hideIds.indexOf(item[dataKey]) != -1){ showList[i] = false; continue; } bottomHeight = topHeight + (item.height>=0?item.height:height) // 判斷 1.題目頂部在顯示范圍內 2.題目底部在顯示范圍內 3.題目頂部和底部都不在顯示范圍內 if((topHeight>=showStart && topHeight<=showEnd)|| (bottomHeight>=showStart && bottomHeight<=showEnd)|| (topHeight<showStart && bottomHeight>showEnd) ){ showList[i] = true} else{ showList[i] = false } topHeight += ((item.height>=0?item.height:height)); } return showList }, [this.dataList, this.showStart, this.showEnd, startTop, this.hideIds,this.dataKey,this.height]) .then(res => { this.showList = res }) this.worker = null },
四、使用方式
安裝vue-long-list-load:
npm install vue-long-list-load --save
項目內調用
<long-list ref="vueLongList" dataKey='id' scrollWrap :dataList="dataList" :dataComponent="dataComponent" :componentProps="componentProps" height=100 > </long-list>
五、參數說明
參數 | 說明 | 類型 | 必填 | 可選值 | 默認值 |
---|---|---|---|---|---|
scrollWrapId | 列表滾動容器id | string | true | — | — |
dataKey | 節點數據內唯一鍵值 | String | true | — | — |
dataList | 列表數據 | Array | true | 具體見下方說明 | — |
dataComponent | 自定義的節點組件 | — | true | — | — |
ref | 調用組件內部方法 | string | false | — | — |
direction | 滾動方向 | Number | false | 0:縱向,1橫向 | 0 |
hideIds | 列表中需要隱藏的節點 | Array | false | 具體見下方說明 | [] |
height | 節點高度 | Number | false | — | 100 |
componentProps | 節點組件要傳遞的參數 | Object | false | — | {} |
scroll | 滾動區域內滾動回調方法 | Function | false | – | — |
resized | 某個節點寬高發生變化回調方法 | Function | false | 具體見下方說明 |
部分參數說明
<--假設 dataKey=id--> <--列表中需要隱藏的節點--> hideIds:[1, 2] <--列表數據 dataList 內 height 為 **Number**。--> dataList:[ {id:1,height:100}, {id:2,height:200}, {id:3,height:300}, {id:4,height:300}, {id:5,height:300} ] <--節點高度--> height:100 <--如果dataList的數據內有height值 不需要設置這個height--> <--如果dataList 和 height 都不傳遞的話,默認為100 可能滾動略有卡頓;--> <--建議在每個高度都不相同的時候通過dataList傳遞,都相同時候通過height傳遞--> <--某個節點寬高發生變化回調方法 返回參數為id 與高度--> resized(id, height){ }
總結
項目中實踐數據,基本每個節點至少500個dom節點,平均也在800個dom節點以上,用vue-long-list-load 不在渲染區域內的題目隻會渲染2個dom節點。按正常800左右個dom節點的題目計算 一般渲染區域渲染的節點在9個左右,如果是n節點的列表 ,每次加載 dom操作都減少(n-9)x(800-2)個dom的渲染,如果\color{red}{1000個節點}1000個節點的列表每次加載和操作的時候相當於減少瞭\color{red}{726180}726180個dom節點的渲染。首次渲染還有修改後的重繪都大大減少瞭dom的渲染加快瞭加載速度提高瞭用戶體驗。 此方案已經在項目中實踐一段時間,用戶反饋很好。如果大傢也有類似的場景需求,歡迎大傢使用!交流!
以上就是如何讓vue長列表快速加載的詳細內容,更多關於vue 長列表快速加載的資料請關註WalkonNet其它相關文章!