基于Vue3實(shí)現(xiàn)列表虛擬滾動(dòng)效果
前言
近期在做一個(gè)網(wǎng)頁播放器項(xiàng)目中,用到很多需要展示歌單的列表
一個(gè)歌單動(dòng)輒千百首歌曲,頁面中的元素太多導(dǎo)致熱重載的時(shí)候 chrome 直接崩了 ??
于是無限滾動(dòng)列表提上日程
寫的有點(diǎn)亂,也是第一次用 typescript 寫項(xiàng)目,先記錄一下
完成效果
思路和需要解決的問題
與懶加載不同,虛擬滾動(dòng)需要一次性獲取所有數(shù)據(jù),但是只顯示屏幕可見范圍內(nèi)的數(shù)據(jù)
要做到這些我需要知道:
- 一行的高度
- 屏幕范圍內(nèi)能顯示的行數(shù)
- 列表在頁面中距離網(wǎng)頁頂部的位置
- 滾動(dòng)條高度
假設(shè)滿屏能容納 10 條數(shù)據(jù),需要加載的數(shù)據(jù)是一個(gè)數(shù)組listData
,只需要裁剪數(shù)據(jù)范圍listData.slice(0, 10)
隨著滾動(dòng)條向下,將滾動(dòng)條高度/一行的高度可以計(jì)算出當(dāng)前行數(shù)
而要模擬滾動(dòng)條高度就要在頁面掛載時(shí)就手動(dòng)設(shè)置頁面的高度一行高度*listData.length
最后也是最關(guān)鍵的是保持列表一直保持在當(dāng)前位置上,手動(dòng)設(shè)置列表容器padding-top
等于當(dāng)前滾動(dòng)條高度
有一個(gè)仍未解決的問題,就是每次來回滾動(dòng)歌曲封面都要重新請(qǐng)求 ??
vue3+setup 寫的組件
<script lang="ts" setup> import { ref, computed, nextTick, reactive, watchEffect, onUnmounted } from 'vue' const props = defineProps<{ listData: Array<any> }>() // 列表HTMLElementDom const ulRef = ref<any>(null) // 屏幕高度 const screenH = document.documentElement.clientHeight const data = reactive<any>({ // 列表第一項(xiàng)的高度(起始高度) initH: 0, // 一行的高度 unitH: 0, // 屏幕范圍內(nèi)能顯示個(gè)數(shù) displayCount: 1, // 列表起始值 startIdx: 0 }) const listData = computed(() => { let endIdx = data.startIdx + data.displayCount if (endIdx >= props.listData.length) endIdx = props.listData.length return props.listData.slice(data.startIdx, endIdx).map((v, k) => { v.idx = data.startIdx + k + 1 return v }) }) function scrollHandler() { // 當(dāng)前滾動(dòng)高度 const curScrollTop = document.documentElement.scrollTop if (curScrollTop > data.initH) { const addCount = Math.floor((curScrollTop - data.initH) / data.unitH) ulRef.value.style.setProperty('padding-top', `${addCount * data.unitH}px`) data.startIdx = addCount } else { ulRef.value.style.setProperty('padding-top', '0px') data.startIdx = 0 } } watchEffect(() => { if (props.listData.length > 0) { nextTick(() => { // 列表距離頂部距離 data.initH = ulRef.value.getBoundingClientRect().top + document.documentElement.scrollTop // 計(jì)算每行高度 data.unitH = ulRef.value.children[0].offsetHeight // 計(jì)算屏幕內(nèi)能顯示的行數(shù) data.displayCount = Math.ceil(screenH / data.unitH) // 設(shè)置列表總高度 = 一行高度 * 行數(shù) const listH = data.unitH * props.listData.length ulRef.value.style.setProperty('height', `${listH}px`) window.removeEventListener('scroll', scrollHandler) window.addEventListener('scroll', scrollHandler) }) } }) onUnmounted(() => { window.removeEventListener('scroll', scrollHandler) }) </script> <template> <ul ref="ulRef"> <li v-for="(listItem, listIndex) in listData" :key="`list-${listIndex}`" :data-idx="listItem.idx"> <slot :listItem="listItem"></slot> </li> </ul> </template>
使用組件
<script lang="ts" setup> import InfiniteList from './InfiniteList.vue' const songs = [] // 列表數(shù)據(jù) </script> <template> <infinite-list :listData="songs"> <template #default="{ listItem }"> <div>{{ listItem.title }}</div> <!-- ... --> </template> </infinite-list> </template>
到此這篇關(guān)于基于Vue3實(shí)現(xiàn)列表虛擬滾動(dòng)效果的文章就介紹到這了,更多相關(guān)Vue列表虛擬滾動(dòng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
一文詳解如何在vue中實(shí)現(xiàn)文件預(yù)覽功能
很多Vue項(xiàng)目中都需要PDF文件預(yù)覽功能,比如合同ERP,銷售CRM,內(nèi)部文檔CMS管理系統(tǒng),內(nèi)置PDF文件在線預(yù)覽功能,下面這篇文章主要給大家介紹了關(guān)于如何在vue中實(shí)現(xiàn)文件預(yù)覽功能的相關(guān)資料,需要的朋友可以參考下2022-10-10基于el-table實(shí)現(xiàn)行內(nèi)增刪改功能
這篇文章主要介紹了基于el-table實(shí)現(xiàn)行內(nèi)增刪改功能,用過通過操作按鈕點(diǎn)擊刪除或者編輯功能即可實(shí)現(xiàn)相應(yīng)的效果,下面小編給大家分享實(shí)例代碼感興趣的朋友跟隨小編一起看看吧2024-04-04vue從一個(gè)頁面跳轉(zhuǎn)到另一個(gè)頁面并攜帶參數(shù)的解決方法
這篇文章主要介紹了vue從一個(gè)頁面跳轉(zhuǎn)到另一個(gè)頁面并攜帶參數(shù)的解決方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08vue-cli項(xiàng)目中遇到的eslint的坑及解決
這篇文章主要介紹了vue-cli項(xiàng)目中遇到的eslint的坑及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04解決vue項(xiàng)目中前后端交互的跨域問題、nginx代理配置方式
這篇文章主要介紹了解決vue項(xiàng)目中前后端交互的跨域問題、nginx代理配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09vue中重定向redirect:‘/index‘,不顯示問題、跳轉(zhuǎn)出錯(cuò)的完美解決
這篇文章主要介紹了vue中重定向redirect:‘/index‘,不顯示問題、跳轉(zhuǎn)出錯(cuò)的完美解決方案,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2020-09-09Vue實(shí)現(xiàn)用戶自定義字段顯示數(shù)據(jù)的方法
今天小編就為大家分享一篇Vue實(shí)現(xiàn)用戶自定義字段顯示數(shù)據(jù)的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-08-08教你如何在 Nuxt 3 中使用 wavesurfer.js
這篇文章主要介紹了如何在 Nuxt 3 中使用 wavesurfer.js,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-01-01一文帶你了解vite對(duì)瀏覽器的請(qǐng)求做了什么
Vite是一種新型前端構(gòu)建工具,能夠顯著提升前端開發(fā)體驗(yàn),下面這篇文章主要給大家介紹了關(guān)于vite對(duì)瀏覽器的請(qǐng)求做了什么的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2021-12-12Vue3+vuedraggable實(shí)現(xiàn)動(dòng)態(tài)配置頁面
這篇文章主要為大家詳細(xì)介紹了Vue3如何利用vuedraggable實(shí)現(xiàn)動(dòng)態(tài)配置頁面,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以參考一下2023-12-12