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

vue3實現(xiàn)一個滾動分頁加載瀑布流列表過程

 更新時間:2026年02月10日 08:53:25   作者:愛拍照的小碼農(nóng)  
文章介紹了如何使用Vue3和JavaScript實現(xiàn)一個滾動分頁加載的瀑布流列表項目框架,主要選擇了vue-waterfall-next插件,并結(jié)合原生JavaScript實現(xiàn)了滾動加載功能,包括防抖處理以優(yōu)化頁面性能

實現(xiàn)一個滾動分頁加載瀑布流列表

項目框架:vue3+JS+vite

瀑布流框架:vue-waterfall-next

問了chatGPT,對于vue3有哪些好用的瀑布流插件,回答如下:

對于 Vue 3,有一些瀑布流插件可供選擇。以下是幾個常用的 Vue 3 瀑布流插件:

  • vue-waterfall-next:這是一個基于 Vue 3 的瀑布流插件,它提供了簡單易用的 API,可以幫助你實現(xiàn)瀑布流布局。它支持動態(tài)加載數(shù)據(jù)和無限滾動,并且具有自定義配置選項,如列數(shù)、間距等。
  • vue-masonry-wall:這是一個基于 Vue 3 的瀑布流插件,它使用 Masonry 布局算法來實現(xiàn)瀑布流效果。它支持自適應(yīng)布局和動態(tài)加載數(shù)據(jù),并且可以根據(jù)需要進行自定義樣式。
  • vue-infinite-scroll:雖然不是專門針對瀑布流設(shè)計的插件,但它可以與瀑布流布局結(jié)合使用,實現(xiàn)無限滾動加載。它支持 Vue 3,并提供了簡單的指令來處理滾動加載的邏輯。

這些插件都可以通過 npm 安裝,并且有詳細的文檔和示例代碼,你可以根據(jù)自己的需求選擇合適的插件進行使用。記得檢查插件的版本和兼容性,以確保與你的 Vue 3 項目兼容。

結(jié)合項目實際,最后選擇用vue-waterfall-next,

插件可在github上找到,用法如下:

安裝

npm install vue-waterfall-plugin-next

使用

在vue項目中引入:

import { LazyImg, Waterfall } from ‘vue-waterfall-plugin-next'
import ‘vue-waterfall-plugin-next/dist/style.css'

由于該插件只能實現(xiàn)瀑布流布局,不能實現(xiàn)滾動分頁加載,而vant的無限滾動功能在此使用會有問題,所以無限滾動這塊用的是原生js去實現(xiàn)

具體代碼

如下所示:

// 父組件index.vue
<template>
	<div class="container" id="main">
    	<productCard :productList="productList"></productCard>
       	 <div class="loading-text" v-if="loading">加載中...</div>
         <div class="loading-text" v-if="finish">沒有更多了</div>
   	</div>
</template>
<script>
import productCard from '@/components/productCard.vue'
import { getAllGoods } from '@/api/modules/good.js'
export default {
	components: {
        productCard,
    },
     setup() {
		const page = ref(0)
        const size = ref(8)
        const loading = ref(false)
        const finish = ref(false)
        const productList = ref([])
        
        //獲取接口數(shù)據(jù)
        const getProduct = () => {
            loading.value = true
            const params = {
                page: page.value,
                size: size.value,
                body: {
                    goodsTypeID: className,
                },
            }
            getAllGoods (params)
                .then(res => {
                    if (res.code === 20000) {
                        total.value = Number(res.data.totalPages)
                        if (res.data.list.length > 0) {
                            productList.value = [...productList.value, ...res.data.list]
                        }
                        if (page.value == total.value + 1) {
                            finish.value = true
                            loading.value = false
                        }
                    } else {
                        loading.value = false
                        finish.value = true
                    }
                })
                .catch(err => {
                    loading.value = false
                    finish.value = true
                })
        }
        const handleScroll = () => {
            const scrollHeight = Math.max(document.documentElement.scrollHeight, document.body.scrollHeight)
            //滾動條滾動距離
            const scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
            //窗口可視范圍高度
            const clientHeight =
                window.innerHeight || Math.min(document.documentElement.clientHeight, document.body.clientHeight)

            if (clientHeight + scrollTop >= scrollHeight  && page.value <= total.value) {
                //快到底時----加載
                page.value++
                getProduct()
            }
        }
        onMounted(() => {
            getProduct(tabModule.activeType.value, tabModule.activeClass.value)
            window.addEventListener('scroll', handleScroll)
        })
        onUnmounted(() => {
            window.removeEventListener('scroll', handleScroll)
        })
        return {
            productList,
            loading,
            finish,
        }
	}
}
</script>

<style lang="scss" scoped>
	.loading-text {
	    text-align: center;
	    position: absolute;
	    left: 0;
	    right: 0;
	    z-index: 999;
	    margin: auto;
	    padding: 20px 0;
	    font-size: 16px;
	}
	:deep(.waterfall-list) {
	    background: none;
	}
	 .container {
        padding: 0 12px;
      }
</style>

// 子組件productCard.vue
<template>
    <Waterfall :lazyload="false" :breakpoints="breakpoints" :gutter="8" :list="list">
        <template #item="{ item, url, index }">
            <div class="card_content">
                <div class="card_img" :class="{ active: !item.goodsPicture && !item.storePicture }">
                    <LazyImg class="cover" :url="item.goodsPicture || item.storePicture || item.storeLogo" />
                </div>
                <div class="content">
                    <div class="store" v-if="item.type === 2">{{ item.storeName }}</div>
                    <div class="title" v-if="item.type === 1">{{ item.storeName }}</div>
                    <div class="title" v-if="item.type === 2">{{ item.goodsName }}</div>
                    <div class="tags">
                        <div class="tags-item" v-for="(ele, index) in item.tags" :key="index">
                            {{ ele }}
                        </div>
                    </div>
                </div>
            </div>
        </template>
    </Waterfall>
</template>

<script>
import { computed, ref } from 'vue'
import { LazyImg, Waterfall } from 'vue-waterfall-plugin-next'
import 'vue-waterfall-plugin-next/dist/style.css'
export default {
    props: {
        productList: Array,
    },
    components: {
        LazyImg,
        Waterfall,
    },
    setup(props) {
        const list = computed(() => {
            return props.productList
        })
        const breakpoints = ref({
            1200: {
                //當(dāng)屏幕寬度小于等于1200
                rowPerView: 4,
            },
            800: {
                //當(dāng)屏幕寬度小于等于800
                rowPerView: 3,
            },
            500: {
                //當(dāng)屏幕寬度小于等于500
                rowPerView: 2,
            },
        })

        return {
            breakpoints,
            list,
        }
    },
}
</script>

<style lang="scss" scoped>
.card_content {
    border-radius: 4px;
    background: #fff;
    box-sizing: border-box;
    .card_img {
        margin-bottom: 7px;
        &.active {
            border: 1px solid #e7e7e7;
        }
        :deep(.lazy__img) {
            width: 100%;
            border-radius: 4px;
            font-size: 0;
            height: 100%;
        }
    }
    .content {
        padding: 0 8px;
        .store {
            color: rgba(0, 0, 0, 0.4);
            font-size: 12px;
            font-weight: 400;
            margin-bottom: 4px;
        }
        .title {
            font-size: 16px;
            font-weight: 500;
            margin-bottom: 14px;
        }
        .tags {
            display: flex;
            flex-wrap: wrap;
            .tags-item {
                background: rgba(153, 151, 255, 0.05);
                border-radius: 2px;
                padding: 3px 4px;
                margin: 0 5px 5px 0;
                color: rgba(0, 0, 0, 0.4);
                font-size: 12px;
                border: 1px solid rgb(244, 244, 249);
                &:last-child {
                    margin-right: 0;
                }
            }
        }
    }
}
</style>

測試的時候發(fā)現(xiàn)滾動的太快頁面會出現(xiàn)抖動現(xiàn)象,所以在監(jiān)聽頁面滾動這里需要加一個防抖,代碼如下:

//防抖函數(shù)
const debounce = (fn, delay) => {
    let timeout
    return function () {
        clearTimeout(timeout)
        timeout = setTimeout(() => {
            fn.apply(this, arguments)
        }, delay)
    }
}
onMounted(() => {
   getProduct()
   window.addEventListener('scroll', debounce(handleScroll, 200))
})

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • vue3使用自定義hooks獲取dom元素的問題說明

    vue3使用自定義hooks獲取dom元素的問題說明

    這篇文章主要介紹了vue3使用自定義hooks獲取dom元素的問題說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • vue實現(xiàn)輪播圖的多種方式

    vue實現(xiàn)輪播圖的多種方式

    這篇文章給大家介紹了vue實現(xiàn)輪播圖的多種方式,文中給出了四種實現(xiàn)方式,并通過代碼示例給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作有一定的幫助,感興趣的朋友可以參考下
    2024-02-02
  • vue打包后修改配置后端IP地址、端口等信息兩種方法

    vue打包后修改配置后端IP地址、端口等信息兩種方法

    這篇文章主要給大家介紹了關(guān)于vue打包后修改配置后端IP地址、端口等信息的兩種方法,文中通過代碼示例以及圖文介紹的非常詳細,對大家學(xué)習(xí)或者使用vue打包具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-09-09
  • vue組件文檔生成備注詳解

    vue組件文檔生成備注詳解

    這篇文章主要介紹了vue組件文檔生成備注詳解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • 在Vue中使用scoped屬性實現(xiàn)樣式隔離的原因解析

    在Vue中使用scoped屬性實現(xiàn)樣式隔離的原因解析

    scoped是Vue的一個特殊屬性,可以應(yīng)用于<style>標(biāo)簽中的樣式,這篇文章給大家介紹在Vue中,使用scoped屬性為什么可以實現(xiàn)樣式隔離,感興趣的朋友一起看看吧
    2023-12-12
  • 一文完全掌握Vue中的$set方法

    一文完全掌握Vue中的$set方法

    這篇文章主要給大家介紹了關(guān)于如何完全掌握Vue中$set方法的相關(guān)資料,vue中$set方法對數(shù)組和對象的處理本質(zhì)上的一樣的,對新增的值添加響應(yīng)然后手動觸發(fā)派發(fā)更新,需要的朋友可以參考下
    2023-11-11
  • Vue跑馬燈marquee組件使用方法詳解

    Vue跑馬燈marquee組件使用方法詳解

    這篇文章主要為大家詳細介紹了Vue跑馬燈marquee組件的使用方法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • vue-element-admin?登陸及目錄權(quán)限控制的實現(xiàn)

    vue-element-admin?登陸及目錄權(quán)限控制的實現(xiàn)

    本文主要介紹了vue-element-admin?登陸及目錄權(quán)限控制的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • 如何使用vue-json-viewer插件展示JSON格式數(shù)據(jù)

    如何使用vue-json-viewer插件展示JSON格式數(shù)據(jù)

    這篇文章主要給大家介紹了關(guān)于如何使用vue-json-viewer插件展示JSON格式數(shù)據(jù)的相關(guān)資料,Vue-json-viewer是一個Vue組件,用于在Vue應(yīng)用中顯示JSON數(shù)據(jù)的可視化工具,需要的朋友可以參考下
    2023-11-11
  • Vuex進行Echarts數(shù)據(jù)頁面初始化后如何更新dom

    Vuex進行Echarts數(shù)據(jù)頁面初始化后如何更新dom

    這篇文章主要為大家詳細介紹了使用Vuex做Echarts數(shù)據(jù)時,當(dāng)頁面初始化后如何更新dom,文中的示例代碼講解詳細,有需要的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-11-11

最新評論

辽阳县| 临沂市| 江永县| 涟源市| 子长县| 清水河县| 桃江县| 通山县| 靖安县| 正安县| 莱阳市| 平潭县| 湖北省| 垣曲县| 车险| 若羌县| 朝阳区| 太保市| 子长县| 漯河市| 呼玛县| 车险| 郧西县| 曲阳县| 宁晋县| 靖边县| 弥渡县| 安溪县| 承德市| 遂宁市| 鄂州市| 松原市| 左贡县| 平邑县| 玛多县| 桂阳县| 富宁县| 密山市| 文昌市| 彝良县| 保德县|