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 的结合,我们可以轻松地实现这一功能。希望这篇文章能够帮助你在项目中实现类似的瀑布流效果。

相关推荐
里欧跑得慢9 分钟前
CSS 模块化架构的演进:BEM、CSS Modules 到 CSS-in-JS 的反思
前端·css·flutter·web·css-in-js
IT_陈寒21 分钟前
Vue的computed属性把我坑惨了,原来我一直用错姿势
前端·人工智能·后端
小灰灰搞电子1 小时前
Rust+Slint 实现温度计源码分享
前端·rust·slint
计算机魔术师1 小时前
面壁智能 OpenBMB 推出 MathForm,面向 Lean 4 数学自动形式化的开源框架、数据集与模型
前端
NeilCarmack2 小时前
Deepseek-harness增加桌面版端序列:第 2 讲 · spawn Electron:当前进程如何“交棒“
前端·javascript·electron
上海魁鲸科技有限公司2 小时前
APS高级排产系统到底有什么用?一文讲清功能、选型与落地建议
前端·microsoft·excel
陈随易2 小时前
Bun v1.4 更新总结:把浏览器、图片、定时任务和工程工具都装进一个运行时
前端·后端·程序员
东风破_4 小时前
TypeScript 高级类型进阶:keyof、Exclude、Record 与类型组合思想
前端·后端·typescript
DS随心转插件4 小时前
Grok生成的html怎么导出——AI导出鸭:大模型结构化输出的“最后一公里”工程化解构
前端·人工智能·ai·html·豆包·deepseek·ai导出鸭
এ慕ོ冬℘゜4 小时前
使用 jQuery 动态渲染表格与状态切换
前端·javascript·jquery