Vue3 实现滚动分页加载瀑布流列表

前言

在现代 Web 开发中,瀑布流布局因其视觉吸引力和高效的屏幕空间利用率而广受欢迎。Vue3 作为前端开发的热门框架,提供了丰富的工具和插件来实现各种复杂的 UI 效果。今天,我们就来探讨如何在 Vue3 项目中实现一个滚动分页加载的瀑布流列表。

选择合适的瀑布流插件

在 Vue3 生态系统中,有多个瀑布流插件可供选择。经过对比和实际测试,我们最终选择了 vue-waterfall-next 插件。它提供了简单易用的 API,支持动态加载数据和无限滚动,并且具有自定义配置选项,如列数、间距等。

安装和引入插件

首先,我们需要安装 vue-waterfall-next 插件。在项目根目录下运行以下命令:

lua 复制代码
npm install vue-waterfall-plugin-next

然后,在 Vue 项目中引入插件:

javascript 复制代码
import { LazyImg, Waterfall } from 'vue-waterfall-plugin-next'
import 'vue-waterfall-plugin-next/dist/style.css'

实现滚动分页加载

虽然 vue-waterfall-next 插件可以实现瀑布流布局,但它本身并不支持滚动分页加载。为了解决这个问题,我们使用了原生 JavaScript 来实现无限滚动加载。

父组件实现

在父组件中,我们定义了分页相关的变量和方法:

ini 复制代码
<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([])

    // 获取接口数据
    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()
      window.addEventListener('scroll', handleScroll)
    })

    onUnmounted(() => {
      window.removeEventListener('scroll', handleScroll)
    })

    return {
      productList,
      loading,
      finish,
    }
  }
}
</script>

子组件实现

在子组件中,我们使用 vue-waterfall-next 插件来实现瀑布流布局:

xml 复制代码
<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: {
        rowPerView: 4,
      },
      800: {
        rowPerView: 3,
      },
      500: {
        rowPerView: 2,
      },
    })

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

优化滚动加载

在测试过程中,我们发现滚动过快时页面会出现抖动现象。为了解决这个问题,我们在监听页面滚动时添加了一个防抖函数:

javascript 复制代码
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))
})

通过这种方式,我们有效地减少了滚动事件的触发频率,从而避免了页面抖动问题。

在线演示效果

总结

在 Vue3 项目中实现滚动分页加载瀑布流列表并不复杂。通过使用 vue-waterfall-next 插件和原生 JavaScript 的结合,我们可以轻松地实现这一功能。希望这篇文章能够帮助你在项目中实现类似的瀑布流效果。

相关推荐
IT_陈寒2 小时前
JavaScript项目实战经验分享
前端·人工智能·后端
用户47949283569153 小时前
6w star,GitHub 趋势第一的 Ponytail,这个agent插件到底在火什么
前端·后端
薛定喵的谔4 小时前
我开源了一个精致的 Next.js 博客模板:Skyplume
前端·前端框架·next.js
张龙6875 小时前
构建生产级 AI Agent:工具调用与记忆架构实战指南
前端
kyriewen6 小时前
2026 年了,还在用 Node.js?Bun 迁移实战:20 分钟搞定,附踩坑记录
前端·javascript·node.js
青山Coding7 小时前
Cesium应用(八):物体运动的实现思路
前端·cesium
用户41659673693557 小时前
Android WebView 加载 file:// 离线页面调试教程
android·前端
Asmewill7 小时前
curl命令学习笔记一
前端
我是一只快乐的小螃蟹7 小时前
1.2 ArrayList 源码解析
前端
星栈7 小时前
我用 Rust + Dioxus 做了个全栈跨平台笔记应用:再把新建、编辑和交付补上
前端·rust·前端框架