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