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

相关推荐
Jolyne_几秒前
css实现圆柱体
前端·css·react.js
亦黑迷失7 分钟前
canvas + ts 实现将图片一分为二的功能,并打包发布至 npm
前端·typescript·canvas
....49212 分钟前
antvX6自定义 HTML 节点创建与更新教程
前端·html·antvx6
禹曦a15 分钟前
Web开发:常用 HTML 表单标签介绍
前端·html·web
姑苏洛言37 分钟前
如何让用户回到上次阅读的位置?——前端视角下的用户体验优化实践
前端
kovlistudio42 分钟前
红宝书第三十一讲:通俗易懂的包管理器指南:npm 与 Yarn
开发语言·前端·javascript·学习·npm·node.js
我爱吃干果1 小时前
ZoomCharts使用方法
前端·javascript·笔记·zoom
旧厂街小江1 小时前
LeetCode 第111题:二叉树的最小深度
前端·算法·程序员
&白帝&1 小时前
vue实现大转盘抽奖
前端·javascript·vue.js
DataFunTalk1 小时前
不是劝退,但“BI”基础不佳就先“别搞”ChatBI了!
前端·后端