基于Vue3實(shí)現(xiàn)列表虛擬滾動效果
前言
近期在做一個網(wǎng)頁播放器項(xiàng)目中,用到很多需要展示歌單的列表
一個歌單動輒千百首歌曲,頁面中的元素太多導(dǎo)致熱重載的時候 chrome 直接崩了 ??
于是無限滾動列表提上日程
寫的有點(diǎn)亂,也是第一次用 typescript 寫項(xiàng)目,先記錄一下
完成效果
思路和需要解決的問題
與懶加載不同,虛擬滾動需要一次性獲取所有數(shù)據(jù),但是只顯示屏幕可見范圍內(nèi)的數(shù)據(jù)
要做到這些我需要知道:
- 一行的高度
- 屏幕范圍內(nèi)能顯示的行數(shù)
- 列表在頁面中距離網(wǎng)頁頂部的位置
- 滾動條高度
假設(shè)滿屏能容納 10 條數(shù)據(jù),需要加載的數(shù)據(jù)是一個數(shù)組listData
,只需要裁剪數(shù)據(jù)范圍listData.slice(0, 10)
隨著滾動條向下,將滾動條高度/一行的高度可以計算出當(dāng)前行數(shù)
而要模擬滾動條高度就要在頁面掛載時就手動設(shè)置頁面的高度一行高度*listData.length
最后也是最關(guān)鍵的是保持列表一直保持在當(dāng)前位置上,手動設(shè)置列表容器padding-top
等于當(dā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)能顯示個數(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)前滾動高度 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 // 計算每行高度 data.unitH = ulRef.value.children[0].offsetHeight // 計算屏幕內(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)列表虛擬滾動效果的文章就介紹到這了,更多相關(guān)Vue列表虛擬滾動內(nèi)容請搜索腳本之家以前的文章或繼續(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從一個頁面跳轉(zhuǎn)到另一個頁面并攜帶參數(shù)的解決方法
這篇文章主要介紹了vue從一個頁面跳轉(zhuǎn)到另一個頁面并攜帶參數(shù)的解決方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08vue-cli項(xiàng)目中遇到的eslint的坑及解決
這篇文章主要介紹了vue-cli項(xiàng)目中遇到的eslint的坑及解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-04-04解決vue項(xiàng)目中前后端交互的跨域問題、nginx代理配置方式
這篇文章主要介紹了解決vue項(xiàng)目中前后端交互的跨域問題、nginx代理配置方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09vue中重定向redirect:‘/index‘,不顯示問題、跳轉(zhuǎn)出錯的完美解決
這篇文章主要介紹了vue中重定向redirect:‘/index‘,不顯示問題、跳轉(zhuǎn)出錯的完美解決方案,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2020-09-09Vue實(shí)現(xiàn)用戶自定義字段顯示數(shù)據(jù)的方法
今天小編就為大家分享一篇Vue實(shí)現(xiàn)用戶自定義字段顯示數(shù)據(jù)的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-08-08教你如何在 Nuxt 3 中使用 wavesurfer.js
這篇文章主要介紹了如何在 Nuxt 3 中使用 wavesurfer.js,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-01-01Vue3+vuedraggable實(shí)現(xiàn)動態(tài)配置頁面
這篇文章主要為大家詳細(xì)介紹了Vue3如何利用vuedraggable實(shí)現(xiàn)動態(tài)配置頁面,文中的示例代碼講解詳細(xì),具有一定的借鑒價值,需要的可以參考一下2023-12-12