Vue中虛擬列表的原理與實現詳解
前言
最近在工作中遇到了一個列表的需求,因為做的是C端,所以對性能體驗要求很高,主要有下面幾點要求,也可以說是痛點
- 就算加載上千條數據,也能夠立即加載,而不會卡頓,等待時間不能太長
- 加載好以后用戶能立馬進行交互,而不是要等待,體驗必須絲滑
仔細想想, 加載上千條數據,加載時間肯定會相對長一些,而又要求立即加載,這不是一個矛盾的需求么,所以如果使用常規(guī)的操作,肯定難以解決這個痛點,所以必須引出我們今天的主角才能解決今天的問題
什么是虛擬列表
虛擬列表是一種技術,它只渲染用戶當前可見的列表項,而不是渲染整個列表。
虛擬列表的原理是什么
只渲染可視區(qū)域內的列表項,而不是渲染整個列表
當用戶滾動容器時,虛擬列表會根據滾動位置和可視區(qū)域的大小計算出當前應該顯示的列表項。
首先實現一個可以滑動的列表
因為我們主要講的是虛擬列表,為了不增加大家負擔,那么列表容器的高度,列表項的高度,我們都設置為已知的,而實際使用的時候,可以根據場景,動態(tài)獲取
代碼很簡單,然后我們一次性渲染10萬條數據數據
<template> <div class="about"> <div class="scrollView"> <div class="list"> <div class="item" v-for="item in list" :key="item"> {{ item }} </div> </div> </div> </div> </template> <script> export default { data() { return { list: [], }; }, mounted() { const total = 100000; const list = []; for (let i = 0; i < total; i++) { list.push(i); } this.list = list; } }; </script> <style> .scrollView { width: 200px; height: 300px; background-color: red; overflow-y: scroll; position: relative; } .item { height: 50px; } </style>
測試結果非??植?,因為數據量龐大,發(fā)現才開始的時候一直卡著不動,有1s多的時間是什么也看不到的,這無疑是致命的
實現虛擬列表
列表高度為300,列表項高度為50,那么我們只需要展示6條數據就可以了,因為有可能上拉數據,那么有可能展示第7條數據,所以我們要展示7條數據,但是首次加載我們只用展示6條
所以此時我們改一下mounted
生命周期
mounted() { const total = 100000; const list = []; for (let i = 0; i < total; i++) { list.push(i); } this.data = list; this.list = list.slice(0, 6); },
問題一:我們只展示可視區(qū)域的列表,那么如何顯示滾動條呢
這個問題就是一個關鍵,需要我們設置一個虛擬的列表,定義好高度
<template> <div class="about"> <div class="scrollView" @scroll="onScroll" ref="list"> <!-- 虛擬列表 --> <div class="virtualScroller" :style="{ height: listHeight + 'px' }"></div> <div class="list"> <div class="item" v-for="item in list" :key="item"> {{ item }} </div> </div> </div> </div> </template> <script> export default { data() { return { list: [], listHeight: 0, itemSize: 50, containerHeight: 300, visibleCount: 6, data: [], startOffset: 0, }; }, mounted() { .... this.listHeight = list.length * this.itemSize; ..... } }; </script> <style> .list { position: absolute; top: 0; left: 0; } </style>
問題二:下拉列表以后,如何讓列表內容顯示到可視區(qū)域內
現在我們的效果是這樣的,下拉的時候,列表內容都上移了
所以我們要讓列表內容在滾動的時候,移動到可視區(qū)域內
我們監(jiān)聽scrollView
的 scroll
事件
<div class="scrollView" @scroll="onScroll" ref="list">
onScroll
的實現包括以下幾個內容
- 滾動距離:
scrollTop
- 列表開始索引:
startIndex
- 列表結束索引:
endIndex
- 列表移動距離:
startOffset
: 這個是重點
this.startOffset = scrollTop - (scrollTop % this.itemSize);
所以我們的onScroll方法的實現是
onScroll() { //當前滾動位置 let scrollTop = this.$refs.list.scrollTop; // 列表開始索引 let startIndex = Math.floor(scrollTop / this.itemSize); // 列表結束索引 let endIndex = Math.ceil((scrollTop + this.containerHeight) / this.itemSize); this.list = this.data.slice(startIndex, endIndex); // 列表移動距離 this.startOffset = scrollTop - (scrollTop % this.itemSize); }
此時我們的虛擬列表就實現了
完整代碼如下:
<template> <div class="about"> <div class="scrollView" @scroll="onScroll" ref="list"> <!-- 虛擬列表 --> <div class="virtualScroller" :style="{ height: listHeight + 'px' }"></div> <div class="list" :style="{ transform: `translateY(${this.startOffset}px)` }"> <div class="item" v-for="item in list" :key="item"> {{ item }} </div> </div> </div> </div> </template> <script> export default { data() { return { list: [], listHeight: 0, itemSize: 50, containerHeight: 300, visibleCount: 6, data: [], startOffset: 0, }; }, mounted() { const total = 100000; const list = []; for (let i = 0; i < total; i++) { list.push(i); } this.listHeight = list.length * this.itemSize; this.data = list; this.list = list.slice(0, 6); }, methods: { onScroll() { //當前滾動位置 let scrollTop = this.$refs.list.scrollTop; // 列表開始索引 let startIndex = Math.floor(scrollTop / this.itemSize); // 列表結束索引 let endIndex = Math.ceil((scrollTop + this.containerHeight) / this.itemSize); this.list = this.data.slice(startIndex, endIndex); // 列表移動距離 this.startOffset = scrollTop - (scrollTop % this.itemSize); } } }; </script> <style> .scrollView { width: 200px; height: 300px; background-color: red; overflow-y: scroll; position: relative; } .item { height: 50px; } .list { position: absolute; top: 0; left: 0; } </style>
那么虛擬列表和下拉加載更多有什么區(qū)別呢
虛擬列表(Virtual List)和下拉加載更多(Infinite Scroll)都是用于優(yōu)化長列表或大數據集的用戶界面的技術,但它們有一些區(qū)別。
虛擬列表通過動態(tài)渲染當前可見的列表項來提高性能和內存利用率,而下拉加載更多是在用戶滾動到列表底部時自動加載更多數據。兩者都是為了優(yōu)化大數據集或長列表的用戶界面,提供更好的性能和用戶體驗。具體選擇哪種技術取決于具體的需求和場景。
參考
到此這篇關于Vue中虛擬列表的原理與實現詳解的文章就介紹到這了,更多相關Vue虛擬列表內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
@click.native和@click的區(qū)別及說明
這篇文章主要介紹了@click.native和@click的區(qū)別及說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-08-08vue3+Element Plus實現自定義穿梭框的詳細代碼
找到一個好用的vue樹形穿梭框組件都很難,又不想僅僅因為一個穿梭框在element-ui之外其他重量級插件,本文給大家分享vue3+Element Plus實現自定義穿梭框的示例代碼,感興趣的朋友一起看看吧2024-01-01Vue中ElementUI結合transform使用時彈框定位不準確問題解析
在近期開發(fā)中,需要將1920*1080放到更大像素大屏上演示,所以需要使用到transform來對頁面進行縮放,但是此時發(fā)現彈框定位出錯問題,無法準備定位到實際位置,本文給大家分享Vue中ElementUI結合transform使用時彈框定位不準確解決方法,感興趣的朋友一起看看吧2024-01-01element-ui?tree?異步樹實現勾選自動展開、指定展開、指定勾選功能
這篇文章主要介紹了element-ui?tree?異步樹實現勾選自動展開、指定展開、指定勾選,項目中用到了vue的element-ui框架,用到了el-tree組件,由于數據量很大,使用了數據懶加載模式,即異步樹,需要的朋友可以參考下2022-08-08