动态

详情 返回 返回

vue3封裝一個容器級的滾頂條觸底加載函數 - 动态 详情

代碼可直接複製使用,主要用於頁面容器內的滾動觸底加載
主要參數:
● element 滾動容器dom
● loading 是否加載中
● hasMore 是否有更多,根據分頁總數跟total判斷
● pageInfo 分頁參數信息{ pageNo: number, pageSize: number, total: number }
● loadMore 加載列表的函數,比如getList,該函數是一個asyncPromise函數
● threshold 滾頂條距離底部多少px觸發到底事件

/**
 * 容器級別的觸底加載更多
 * @param {Ref<HTMLElement>} element 滾動容器dom
 * @param {Ref<boolean>} loading 加載中
 * @param {Ref<boolean>} hasMore 是否有更多
 * @param {Ref<{ pageNo: number, pageSize: number, total: number }>} pageInfo 分頁信息
 * @param {() => Promise<void>} loadMore 查詢分頁函數
 * @param {number} threshold 閾值
 */
export function containeScroll(
  element: Ref<HTMLElement>,
  loading: Ref<boolean>,
  hasMore: Ref<boolean>,
  pageInfo: Ref<{ pageNo: number, pageSize: number, total: number }>,
  loadMore: () => Promise<void>,
  threshold: number = 10) {
  // 加載中 或 沒有更多
  if (loading.value || !hasMore.value) return;

  // 判斷滾動容器是否存在
  if (!element.value) return;

  const container = element.value;
  // 滾動容器高度 + 滾動距離 >= 內容總高度 - 10px(緩衝值)
  const isBottom = container.clientHeight + container.scrollTop >= container.scrollHeight - threshold;

  if (isBottom && !loading.value && hasMore.value) {
    pageInfo.value.pageNo++;
    loadMore(); // 到底了,調用加載函數
  }
}

頁面結構

<div ref="scrollContainer" @scroll="handleScroll">
   <div class="body"></div>
</div>
<script setup lang='ts'>
import { containeScroll } from '@/hook/useInfiniteScroll'

// 加載中
const loading = ref(false)
// 是否有下一頁
const hasMore = ref(true)
// 分頁參數
const pageInfo = ref({
  pageNo: 1,
  pageSize: 10,
  total: 0,
})
// 列表數據
const list = ref([])
async function getList() {
  try {
    let params = {
      pageNo: pageInfo.value.pageNo,
      pageSize: pageInfo.value.pageSize
    }
    loading.value = true
    let res = await getListAPI(params)
    list.value.push(...res.list)
    pageInfo.value.total = res.total
    if (pageInfo.value.pageNo * pageInfo.value.pageSize >= pageInfo.value.total) {
      hasMore.value = false
    }
    else {
      hasMore.value = true
    }
  }
  finally {
    loading.value = false
  }
}

// 初始化查詢
getList();

// 滾動容器 dom
const scrollContainer = ref<HTMLDivElement | null>(null)
// 防抖函數,節省性能
const onScroll = debounce(containeScroll, 300)

// 每次滾動時觸發
function handleScroll() {
  onScroll(scrollContainer, loading, hasMore, pageInfo, getList)
}
</script>

輔助函數

// 防抖函數
function debounce<T extends (...args: any[]) => any>(fn: T, delay: number): ((...args: Parameters<T>) => void) {
  let timer: NodeJS.Timeout | null = null
  return function (this: ThisParameterType<T>, ...args: Parameters<T>) {
    if (timer)
      clearTimeout(timer)
    timer = setTimeout(() => {
      // 使用 apply 綁定 this 上下文
      fn.apply(this, args)
      timer = null
    }, delay)
  }
}

Add a new 评论

Some HTML is okay.