项目框架:vue3+JS+vite
瀑布流框架:vue-waterfall-next
问了chatGPT,对于vue3有哪些好用的瀑布流插件,回答如下:
对于 Vue 3,有一些瀑布流插件可供选择。以下是几个常用的 Vue 3 瀑布流插件:
vue-waterfall-next:这是一个基于 Vue 3 的瀑布流插件,它提供了简单易用的 API,可以帮助你实现瀑布流布局。它支持动态加载数据和无限滚动,并且具有自定义配置选项,如列数、间距等。
vue-masonry-wall:这是一个基于 Vue 3 的瀑布流插件,它使用 Masonry 布局算法来实现瀑布流效果。它支持自适应布局和动态加载数据,并且可以根据需要进行自定义样式。
vue-infinite-scroll:虽然不是专门针对瀑布流设计的插件,但它可以与瀑布流布局结合使用,实现无限滚动加载。它支持 Vue 3,并提供了简单的指令来处理滚动加载的逻辑。
这些插件都可以通过 npm 安装,并且有详细的文档和示例代码,你可以根据自己的需求选择合适的插件进行使用。记得检查插件的版本和兼容性,以确保与你的 Vue 3 项目兼容。
结合项目实际,最后选择用vue-waterfall-next,
插件可在github上找到,用法如下:
安装
npm install vue-waterfall-plugin-next
使用
在vue项目中引入:
import { LazyImg, Waterfall } from ‘vue-waterfall-plugin-next’
import ‘vue-waterfall-plugin-next/dist/style.css’
由于该插件只能实现瀑布流布局,不能实现滚动分页加载,而vant的无限滚动功能在此使用会有问题,所以无限滚动这块用的是原生js去实现
具体代码如下:
// 父组件index.vue
<template><div class="container" id="main"><productCard :productList="productList"></productCard><div v-if="loading">加载中</div><div v-if="finish">没有更多了</div></div>
</template>
<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 = () => {if (loading.value || finish.value) returnloading.value = trueconst params = {page: page.value,size: size.value,body: {goodsTypeID: className,},}getAllGoods (params).then(res => {loading.value = falseif (res.code === 20000) {if (res.data.list.length > 0) {productList.value = [...productList.value, ...res.data.list]total.value = Number(res.data.totalPages)if (page.value === Number(res.data.totalPages)) {finish.value = true}}} else {loading.value = falsefinish.value = true}}).catch(err => {loading.value = falsefinish.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++getProduct()}}onMounted(() => {getProduct(tabModule.activeType.value, tabModule.activeClass.value)window.addEventListener('scroll', handleScroll)})onUnmounted(() => {window.removeEventListener('scroll', handleScroll)})return {productList,loading,finish,}}
}
</script><style lang="scss" scoped>.container {padding: 0 12px;}
</style>// 子组件productCard.vue
<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: {//当屏幕宽度小于等于1200rowPerView: 4,},800: {//当屏幕宽度小于等于800rowPerView: 3,},500: {//当屏幕宽度小于等于500rowPerView: 2,},})return {breakpoints,list,}},
}
</script><style lang="scss" scoped>
.card_content {border-radius: 4px;background: #fff;box-sizing: border-box;.card_img {margin-bottom: 7px;&.active {border: 1px solid #e7e7e7;}:deep(.lazy__img) {width: 100%;border-radius: 4px;font-size: 0;height: 100%;}}.content {padding: 0 8px;.store {color: rgba(0, 0, 0, 0.4);font-size: 12px;font-weight: 400;margin-bottom: 4px;}.title {font-size: 16px;font-weight: 500;margin-bottom: 14px;}.tags {display: flex;flex-wrap: wrap;.tags-item {background: rgba(153, 151, 255, 0.05);border-radius: 2px;padding: 3px 4px;margin: 0 5px 5px 0;color: rgba(0, 0, 0, 0.4);font-size: 12px;border: 1px solid rgb(244, 244, 249);&:last-child {margin-right: 0;}}}}
}
</style>
测试的时候发现滚动的太快页面会出现抖动现象,所以在监听页面滚动这里需要加一个防抖,代码如下:
//防抖函数
const debounce = (fn, delay) => {let timeoutreturn function () {clearTimeout(timeout)timeout = setTimeout(() => {fn.apply(this, arguments)}, delay)}
}
onMounted(() => {getProduct()window.addEventListener('scroll', debounce(handleScroll, 200))
})