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

相关推荐
To_OC7 小时前
别再串行写 await 了,Promise.all 才是并行请求的正确打开方式
前端·javascript·promise
vipbic8 小时前
中后台越做越乱后,我用插件化把它救回来了
前端·vue.js
Hyyy8 小时前
Computer Use 适合做什么,不适合做什么——一次真实使用后的思考
前端
小和尚同志8 小时前
前端 AI 单元测试思考与落地
前端·人工智能·aigc
invicinble10 小时前
c端系统,其实更像一个信息展示平台
前端
李姆斯10 小时前
管理是否可以被完全量化
前端·产品经理·团队管理
名字还没想好☜11 小时前
Next.js 中间件实战:鉴权、重定向与 A/B 分流
开发语言·前端·javascript·中间件·react·next.js
广州灵眸科技有限公司11 小时前
瑞芯微RV1126B开发板(EASY-EAI-PI2) INI文件操作
java·前端·javascript·网络·人工智能
kaiking_g12 小时前
vue项目中,静态导入 vs 动态导入 详解
前端·javascript·vue.js
江华森12 小时前
Web 开发基础:HTTP 与 REST
前端·网络协议·http