实现一个两列的瀑布流布局,支持无限滚动
**思路:**利用flex布局,将列表分为左右两侧,因为这种方式存在一个弊端,就是当有一侧的高度越来越高的时候,滑到底部的时候就会出现一个很明显的高度差,为了修复这个漏洞,写一个算法,计算每一页两侧列表的高度差,举个例子,当左侧高度比右侧高很多的时候,则把下一页列表的第一个数据放在右侧,补齐高度,反之同理;如果数据是无限滚动加载不会滑动到底部的话,则可以不做处理;
代码如下:
<template>
<div class="prod-list">
<van-list v-model:loading="loading" :finished="finish" finished=text="没有更多了" @load="load">
<div class="left">
<div id="left-box"
<productCard v-for="productItem in productListLeft" :key="productItem.id" :itemInfo="productItem" :itemType="itemType"></productCard>
</div>
</div>
<div class="right">
<div id="right-box">
<productCard v-for="productItem in productListRight" :key="productItem.id" :itemInfo="productItem" :itemType="itemType"></productCard>
</div>
</div>
</van-list>
</div>
</template>
<script>
import ref from 'vue
import { getAllstores,getAllGoods, getAllsuggest,getAllIntroduction } from '@/api/modules/goods.js'
import productCard from './productcard.vue'
export default {
props: {
itemType: String,
activeClass: Number
},
components: {
productCard,
Annotate
},
setup(props) {
const page = ref(0)
const size = ref(8)
const loading = ref(false)
const finish = ref(false)
const apiMap = { getAllsuggest, getAllGoods, getAllstores, getAllIntroduction }
const productList = ref([])
const productListLeft = ref([])
const productListRight = ref([])
const leftHeightNum = ref(0)
const rightHeightNum = ref(0)
const getContentHeight = () => {
const leftBox = document.querySelector('#left-box')
const rightBox = document.querySelector('#right-box')
leftHeightNum.value = leftBox ? leftBox.offsetHeight : 0
rightHeightNum.value = rightBox ? rightBox.offsetHeight : 0
}
const getorderList = (list, leftList, rightList, flag) = > {
for(let i = 0; i < list.length; i++) {
if (flag === left') {
if (i % 2 ==0 ) {
rightList.push(list[i])
} else {
leftList.push(list[i])
}
} else {
if (i % 2 == 0) {
leftList.push(list[i])
else {
rightList.push(list[i])
}
}
}
}
const getProduct = (path = 'getAllSuggest', className = 0, index) =>
loading.value = true
const targetApi = apiMap[path]
const params = {
page: page .value.
size: size.value,
body:
path !="getAllSuggest' || path != 'getAllIntroduction'
? {
goodsTypeID: className.
}
: null
}
targetApi(params)
.then(async res => {
if (res.code === 20000) {
if (page.value == 0) {
productList.value = []
productListLeft.value = []
productListRight.value = []
}
let leftList = []
let rightList = []
productList.value = res.data.list
finish.value = page.value >= Number(res.data.totalPages)
if (productList.value.length > 0) {
await getContentHeight()
if (page.value === 1) {
getorderList(productList.value, leftList, rightList, 'right')
} else {
if (leftHeightNum.value > rightHeightNum.value && leftHeightNum.value - rightHeightNum.value > 100) {
let firstItem = productList.value.shift()
rightList.push(firstItem)
getorderList(productList.value, leftList, rightList,'left') }
} else if ( leftHeightNum.value < rightHeightNum.value && rightHeightNum.value - leftHeightNum.value > 100) {
let firstItem = productList.value.shift()
leftList.push(firstItem)
getorderList(productList.value, leftList, rightList,'right')
} else {
getorderList(productList.value, leftList,rightList,'right')
}
}
productListLeft.value = [...productListLeft.value,...leftList]
productListRight.value = [...productListRight.value, ...rightList]
loading.value = false
} else {
loading.value=false;
finish.value =true
}
})
.catch(err => {
loading.value=false
finish.value =true
})
}
const onLoad = () => {
page.value += 1
getProduct(props.itemType,props.activeClass)
}
// 重置数据
const resetData = () => {
page.value = 1
productList.value = []
productListLeft.value = []
productListRight.value = []
loading.value = false
finish.value = false
}
return {
productList,
loadingfinish,
onLoad,
page,
getProduct,
productListLeft,
productListRight,
resetData,
}
</script>
<style lang="scss"scoped>
.prod-list {
.container {
width: 100%;
display: flex;
.left {
flex: 1;
margin-right: 8px;
}
.right {
flex: 1;
}
}
.van-list {
:deep(.van-list finished-text) {
width: 100%;
}
:deep(.van-list placeholder) {
width: 100%;
}
}
}
</style>