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

相关推荐
萧行之1 小时前
可视化技术复盘:从图形语法看 D3、Vega-Lite、ECharts、Observable Plot
前端·学习·数据可视化
尾善爱看海9 小时前
Vue 面试收官篇:SSR、性能优化落地、30 道高频面试题精讲(附标准答案)
前端·javascript·vue.js·面试·vue
驳是10 小时前
一个组件,提升 react-router 开发的幸福感
前端·preact
GreenTea10 小时前
OpenAI Agents API 上手实测:一次调用把整个 agent loop 甩给 OpenAI
前端·后端·算法
星云API技术支持10 小时前
企业微信二次开发:群权限设置、成员管理与群资料维护的接口组合实践
java·前端·企业微信
京东云开发者10 小时前
81.8 秒的视频,我们改了 15 个版本:一次纯 Codex 驱动的 AI-native 视频实践
前端·aigc
Csvn11 小时前
TypeScript 大型项目架构:从单体 tsconfig 到分层可扩展的工程
前端
计算机魔术师13 小时前
Dario Amodei 发文呼吁为前沿 AI 降速并提出三点计划
前端
计算机魔术师13 小时前
OpenAI的AI代理偷偷给RubyGems下毒,我们却毫无察觉
前端
甲维斯13 小时前
0代码,0建模,3句话开发一个3D游戏!
前端·游戏·游戏开发