最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Vue3實現(xiàn)列表無限滾動的示例詳解

 更新時間:2023年07月16日 16:39:53   作者:一只大加號  
這篇文章主要為大家詳細介紹了如何使用Vue3實現(xiàn)列表無限滾動的效果,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起了解一下

先看成果

無限滾動列表

無限滾動列表(Infinite Scroll)是一種在網(wǎng)頁或應用程序中加載和顯示大量數(shù)據(jù)的技術。它通過在用戶滾動到頁面底部時動態(tài)加載更多內(nèi)容,實現(xiàn)無縫的滾動體驗,避免一次性加載所有數(shù)據(jù)而導致性能問題。供更流暢的用戶體驗。但需要注意在實現(xiàn)時,要考慮合適的加載閾值、數(shù)據(jù)加載的順序和流暢度,以及處理加載錯誤或無更多數(shù)據(jù)的情況,下面我們用IntersectionObserver來實現(xiàn)無線滾動,并且在vue3+ts中封裝成一個可用的hook。

IntersectionObserver是什么

IntersectionObserver(交叉觀察器)是一個Web API,用于有效地跟蹤網(wǎng)頁中元素在視口中的可見性。它提供了一種異步觀察目標元素與祖先元素或視口之間交叉區(qū)域變化的方式。 IntersectionObserver的主要目的是確定一個元素何時進入或離開視口,或者與另一個元素相交。它在各種場景下非常有用,例如延遲加載圖片或其他資源,實現(xiàn)無限滾動等。

這里用一個demo來做演示

demo代碼如下,其實就是用IntersectionObserver來對某個元素做一個監(jiān)聽,通過siIntersecting屬性來判斷監(jiān)聽元素的顯示和隱藏。

 const observer = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
        console.log('元素出現(xiàn)');
    } else{
      console.log('元素隱藏');
    }
  });
});
observer.observe(bottom);

無限滾動實現(xiàn)

下面我們開始動手

1.數(shù)據(jù)模擬

模擬獲取數(shù)據(jù),比如分頁的數(shù)據(jù),這里是模擬的表格滾動的數(shù)據(jù),每次只加載十條,類似于平時的翻頁效果,這里寫的比較簡單, 在這里給它加了一個最大限度30條,超過30條就不再繼續(xù)增加了

<template>
  <div ref="container" class="container">
    <div v-for="item in list" class="box">{{ item.id }}</div>
  </div>
</template>
<script setup lang="ts">
const list: any[] = reactive([]);
let idx = 0;
function getList() {
  return new Promise((res) => {
    if(idx<30){
      for (let i = idx; i < idx + 10; i++) {
        list.push({ id: i });
      }
      idx += 10
    }
    res(1);
  });
</script>

2.hook實現(xiàn)

import { createVNode, render, Ref } from 'vue';
/**
 接受一個列表函數(shù)、列表容器、底部樣式
 */
export function useScroll() {
    // 用ts定義傳入的三個參數(shù)類型
    async function init(fn:()=>Promise<any[] | unknown>,container:Ref) {
        const res = await fn();
      }
    return { init }
}

執(zhí)行init就相當于加載了第一次列表 后續(xù)通過滾動繼續(xù)加載列表

import { useScroll } from "../hooks/useScroll.ts";
onMounted(() => {
  const {init} = useScroll()
  //三個參數(shù)分別是 加載分頁的函數(shù) 放置數(shù)據(jù)的容器 結尾的提示dom
  init(getList,container,bottom)
});

3.監(jiān)聽元素

export function useScroll() {
    // 用ts定義傳入的三個參數(shù)類型
    async function init(fn:()=>Promise<any[] | unknown>,container:Ref,bottom?:HTMLDivElement) {
        const res = await fn();
        // 使用IntersectionObserver來監(jiān)聽bottom的出現(xiàn)
        const observer = new IntersectionObserver((entries) => {
          entries.forEach((entry) => {
            if (entry.isIntersecting) {
                fn();
                console.log('元素出現(xiàn)');
            } else{
              console.log('元素隱藏');
            }
          });
        });
        observer.observe(bottom);
      }
    return { init }
}

4.hook初始化

獲取需要做無限滾動的容器 這里我們用ref的方式來直接獲取到dom節(jié)點 大家也可以嘗試下用getCurrentInstance這個api來獲取到

整個實例,其實就是類似于vue2中的this.$refs.container來獲取到dom節(jié)點容器

根據(jù)生命周期我們知道dom節(jié)點是在mounted中再掛載的,所以想要拿到dom節(jié)點,要在onMounted里面獲取到,畢竟沒掛載肯定是拿不到的嘛

const container = ref<HTMLElement | null>(null);
onMounted(() => {
  const vnode = createVNode('div', { id: 'bottom',style:"color:#000" }, '到底了~');
  render(vnode, container.value!);
  const bottom = document.getElementById('bottom') as HTMLDivElement;
  // 用到的是createVNode來生成虛擬節(jié)點 然后掛載到容器container中
  const {init} = useScroll()
  //三個參數(shù)分別是 加載分頁的函數(shù) 放置數(shù)據(jù)的容器 結尾的提示dom
  init(getList,container,bottom)
});

這部分代碼是生成放到末尾的dom節(jié)點 封裝的init方法可以自定義傳入末尾的提示dom,也可以不傳,封裝的方法中有默認的dom

優(yōu)化功能

自定義默認底部提示dom

async function init(fn:()=>Promise<any[] | unknown>,container:Ref,bottom?:HTMLDivElement) {
        const res = await fn();
        // 如果沒有傳入自定義的底部dom 那么就生成一個默認底部節(jié)點 
        if(!bottom){
          const vnode = createVNode('div', { id: 'bottom',style:"color:#000" }, '已經(jīng)到底啦~');
          render(vnode, container.value!);
          bottom = document.getElementById('bottom') as HTMLDivElement;
        }
        // 使用IntersectionObserver來監(jiān)聽bottom的出現(xiàn)
        const observer = new IntersectionObserver((entries) => {
          entries.forEach((entry) => {
            if (entry.isIntersecting) {
                fn();
                console.log('元素出現(xiàn)');
            } else{
              console.log('元素隱藏');
            }
          });
        });
        observer.observe(bottom);
      }

完整代碼

import { createVNode, render, Ref } from 'vue';
/**
 接受一個列表函數(shù)、列表容器、底部樣式
 */
export function useScroll() {
    async function init(fn:()=>Promise<any[] | unknown>,container:Ref,bottom?:HTMLDivElement) {
        const res = await fn();
        // 生成一個默認底部節(jié)點
        if(!bottom){
          const vnode = createVNode('div', { id: 'bottom' }, '已經(jīng)到底啦~');
          render(vnode, container.value!);
          bottom = document.getElementById('bottom') as HTMLDivElement;
        }
        const observer = new IntersectionObserver((entries) => {
          entries.forEach((entry) => {
            if (entry.isIntersecting) {
                fn();
            } 
          });
        });
        observer.observe(bottom);
      }
    return { init }
}
<template>
  <div ref="container" class="container">
    <div v-for="item in list" class="box">{{ item.id }}</div>
  </div>
</template>
<script setup lang="ts">
import { onMounted, createVNode, render, ref, reactive } from 'vue';
import { useScroll } from "../hooks/useScroll.ts";
const list: any[] = reactive([]);
let idx = 0;
function getList() {
  return new Promise((res,rej) => {
    if(idx<=30){
      for (let i = idx; i < idx + 10; i++) {
        list.push({ id: i });
      }
      idx += 10
      res(1);
    }
    rej(0)
  });
}
const container = ref<HTMLElement | null>(null);
onMounted(() => {
  const vnode = createVNode('div', { id: 'bottom' }, '到底了~');
  render(vnode, container.value!);
  const bottom = document.getElementById('bottom') as HTMLDivElement;
  const {init} = useScroll()
  init(getList,container,bottom)
});
</script>
<style scoped>
.container {
  border: 1px solid black;
  width: 200px;
  height: 100px;
  overflow: overlay
}
.box {
  height: 30px;
  width: 100px;
  background: red;
  margin-bottom: 10px
}</style>

到此這篇關于Vue3實現(xiàn)列表無限滾動的示例詳解的文章就介紹到這了,更多相關Vue3列表無限滾動內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 手把手帶你安裝vue-cli并創(chuàng)建第一個vue-cli應用程序

    手把手帶你安裝vue-cli并創(chuàng)建第一個vue-cli應用程序

    vue-cli這個構建工具大大降低了webpack的使用難度,支持熱更新,有webpack-dev-server的支持,相當于啟動了一個請求服務器,給你搭建了一個測試環(huán)境,下面這篇文章主要給大家介紹了關于安裝vue-cli并創(chuàng)建第一個vue-cli應用程序的相關資料,需要的朋友可以參考下
    2022-08-08
  • 解決vux 中popup 組件Mask 遮罩在最上層的問題

    解決vux 中popup 組件Mask 遮罩在最上層的問題

    這篇文章主要介紹了解決vux 中popup 組件Mask 遮罩在最上層的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • Vue3+TypeScript項目中安裝PDF.js詳細的步驟

    Vue3+TypeScript項目中安裝PDF.js詳細的步驟

    這篇文章主要介紹了Vue3+TypeScript項目中安裝PDF.js詳細的步驟,通過示例代碼詳細介紹了包括安裝步驟、基礎使用示例、創(chuàng)建可復用PDF查看器組件、注意事項等,需要的朋友可以參考下
    2026-01-01
  • 利用v-viewer圖片預覽插件放大需要預覽的圖片

    利用v-viewer圖片預覽插件放大需要預覽的圖片

    本文介紹了v-viewer插件的安裝和使用步驟,包括npm安裝、在main.js文件中全局引入,以及常用的三種使用方式,文章提供了簡單的布局頁面效果,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-10-10
  • Vue中的計算屬性computed傳參方式

    Vue中的計算屬性computed傳參方式

    這篇文章主要介紹了Vue中的計算屬性computed傳參方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • vue組件props不同數(shù)據(jù)類型傳參的默認值問題

    vue組件props不同數(shù)據(jù)類型傳參的默認值問題

    這篇文章主要介紹了vue組件props不同數(shù)據(jù)類型傳參的默認值問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • Vue-cli配置打包文件本地使用的教程圖解

    Vue-cli配置打包文件本地使用的教程圖解

    這篇文章主要介紹了Vue-cli配置打包文件本地使用的教程圖解,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-08-08
  • Vue+canvas實現(xiàn)視頻截圖功能

    Vue+canvas實現(xiàn)視頻截圖功能

    這篇文章主要為大家詳細介紹了Vue+canvas實現(xiàn)視頻截圖功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • vue?this.$toast?失效問題解決方案

    vue?this.$toast?失效問題解決方案

    這篇文章主要介紹了vue?this.$toast?失效問題匯總,本文給大家分享完美解決方案,感興趣的朋友跟隨小編一起看看吧
    2024-03-03
  • 使用sessionStorage解決vuex在頁面刷新后數(shù)據(jù)被清除的問題

    使用sessionStorage解決vuex在頁面刷新后數(shù)據(jù)被清除的問題

    localStorage沒有時間期限,除非將它移除,sessionStorage即會話,當瀏覽器關閉時會話結束,有時間期限,具有自行百度。本文使用的是sessionStorage解決vuex在頁面刷新后數(shù)據(jù)被清除的問題,需要的朋友可以參考下
    2018-04-04

最新評論

新宾| 涿州市| 区。| 霍林郭勒市| 潞城市| 金湖县| 潜山县| 凉城县| 咸阳市| 隆安县| 辰溪县| 鄂托克旗| 育儿| 织金县| 永丰县| 乌兰浩特市| 桦川县| 景东| 潮安县| 偏关县| 广宁县| 南昌市| 卓尼县| 南丰县| 香港 | 东丽区| 荔波县| 平湖市| 册亨县| 柏乡县| 松阳县| 华容县| 长武县| 台南市| 化德县| 广丰县| 资兴市| 通渭县| 疏附县| 武强县| 晋城|