<template>
<div class="waterfall" @scroll="loadMore">
<div class="masonry" ref="masonry">
<div
class="item"
v-for="(item, index) in showPicList"
:key="index"
>
<img class="picture" v-real-img="item.src" :src="imgDefault" @load="imageOnLoad" />
</div>
</div>
<div v-if="!addPicList.length" class="placeholder">数据已加载完毕</div>
</div>
</template>
<script>
export default {
name: 'Waterfall',
data() {
return {
addPicList: [],
showPicList: [],
pageNumber: 1,
imgDefault: require('../../assets/imgs/picError.png'),
}
},
mounted() {
this.getData()
const debounceWaterfall = this.debounce(this.waterfall, 50)
window.addEventListener('resize', () => debounceWaterfall())
this.$eventBus.$on('imageOnLoad', () => debounceWaterfall())
},
methods: {
getData() {
// 发送接口
this.$store.dispatch('api' + this.pageNumber).then((res) => {
this.addPicList = []
if (res.data.pageRecords.length) {
this.pageNumber += 1 // 下一页
this.addPicList = res.data.pageRecords
this.showPicList = [...this.showPicList, ...this.addPicList]
}
})
},
debounce(func, delay) {
let timer = null
return function (...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
func.apply(this, args)
}, delay)
}
},
imageOnLoad() {
this.$eventBus.$emit('imageOnLoad')
},
waterfall() {
var items = this.$refs.masonry.children
var columns = 5 // 每行展示几列
var arr = []
// 距离左右边缘的距离固定,item的缝隙固定
var gapToTop = 10 // 与顶部之间的距离,避免盒子重合
var gap = 10 // 上下间距
var gapBetween = 10 // 左右item之间的距离
var gapToSide = 10 // 到masonry左、右边缘的距离
var calcItemWidth = (this.$refs.masonry.clientWidth - 2 * gapToSide - (columns - 1) * gapBetween) / columns
for (var i = 0; i < items.length; i++) {
this.$refs.masonry.children[i].style.width = calcItemWidth + 'px'
if (i < columns) {
items[i].style.top = gapToTop + 'px'
// 调节第一行偏移量,让整个瀑布流区域居中
items[i].style.left = (calcItemWidth + gapBetween) * i + gapToSide + 'px'
arr.push(items[i].offsetHeight + gap)
} else {
var minHeight = arr[0]
var index = 0
for (var j = 0; j < arr.length; j++) {
if (minHeight > arr[j]) {
minHeight = arr[j]
index = j
}
}
items[i].style.top = arr[index] + gapToTop + 'px'
items[i].style.left = items[index].offsetLeft + 'px'
arr[index] = arr[index] + items[i].offsetHeight + gap
}
}
this.$refs.masonry.style.height = Math.max(...arr) + gap + 'px'
},
loadMore(event) {
const el = event.target
if (Math.ceil(el.scrollTop + el.clientHeight) >= el.scrollHeight) {
this.getData()
}
},
}
}
</script>
<style lang="less">
.waterfall {
overflow-y: scroll;
max-height: 1000px;
.masonry {
position: relative;
background-color: rgb(233, 233, 233);
.item {
position: absolute;
overflow: hidden;
border-radius: 10px;
background-color: #ffffff;
img {
width: 100%;
cursor: pointer;
}
}
}
}
</style>