欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

基于Vue3實(shí)現(xiàn)列表虛擬滾動(dòng)效果

 更新時(shí)間:2022年04月15日 10:11:35   作者:yellowhomecar  
這篇文章主要為大家介紹了如何利用Vue3實(shí)現(xiàn)列表虛擬滾動(dòng)效果,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)或工作有一定價(jià)值,需要的可以參考一下

前言

近期在做一個(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)文章

最新評(píng)論