<template>
<div ref="waterfallFlow" class="waterfallFlow-wrapper" :style="{height:Math.max(...columns)+'px'}">
<div v-for="(item,index) in list" :style="{width:width+'px',transform:`translate(${item.x+'px'},${item.y+'px'})`}"
class="waterfallFlow-item" :key="item.url+index">
<img v-if="item.renderHeight" :style="{display: 'block',width: '100%'}" :src="item.url" alt="">
</div>
</div>
</template>
<script>
export default {
name: 'waterfallFlow',
data() {
return {
columns: [],
columnNums: 0,
width: 260,
loadMore: false,
list: [
{
url: 'https://photo.colorhub.me/7ctMvIy5wTY/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vZjYvNzYvOTYzM2VjZjI5ODk5MDVmMDg4NDE4MGRjZTVhNjdmZTljMDYxZjY3Ni5qcGVn.webp',
x: 0,
y: 0
},
{
url: 'https://img.colorhub.me/5tNgQlTNeGU/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vMDUvNGYvYzA4MTA1Yzc3ZWEwOWU1N2IzZTg1NTRlNGNiMTZlMDAxYTY5MDU0Zi5qcGVn.webp',
x: 0,
y: 0
}, {
url: 'https://cdn.colorhub.me/64ilh6vc2tw/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vOWYvODgvNmZiZmM3YWU5OWIwYmQyNzZmMWM5MWMwMWRiODAxNzU3YzkxOWY4OC5qcGc.webp',
x: 0,
y: 0
},
{
url: 'https://cdn.colorhub.me/0pxXm7FwgQU/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vMzIvZWIvMGQ0Y2ZiNzkzMjlmNDI0ZTJlY2U4YTI1MjZkY2Q3ZjZiOGQ4MzJlYi5qcGc.webp',
x: 0,
y: 0
},
{
url: 'https://img.colorhub.me/5HEmB2Et7lw/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vNDIvNzUvN2M3MjdmYzFiZDNmN2FhZmFkYzQ5Y2E5MjQ3ZGRjOGEzMzI3NDI3NS5qcGVn.webp',
x: 0,
y: 0
},
{
url: 'https://cdn.colorhub.me/Tlr2i3HcNYY/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vN2MvMDkvYmZkYzc3MTk4ZTE1Mjg2ZjVmNTI0OWMwZjNkZjY4YWE4OGZlN2MwOS5qcGVn.webp',
x: 0,
y: 0
},
{
url: 'https://cdn.colorhub.me/31EWPPaC3rM/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vMjQvMDUvYzZhMDU1NTdkZDE2NDdiZjJlNzYyNzkzM2U1OWM1OWVjZTFmMjQwNS5qcGVn.webp',
x: 0,
y: 0
},
{
url: 'https://cdn.colorhub.me/ojwHoKOthec/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vNmYvNjMvOGJjODJjNjNmMzYyM2M4MWI1NzkwYWY1MWE3Y2Y0YmNhYTAzNmY2My5qcGVn.webp',
x: 0,
y: 0
},
{
url: 'https://img.colorhub.me/G3S8lTFEJIQ/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vOGYvMGEvMTlmZjkyNjg1YTMxZDM0MzVjMDdhMGFiMzBhOGU5MzI1YzdlOGYwYS5qcGVn.webp',
x: 0,
y: 0
}, {
url: 'https://photo.colorhub.me/sYVTa7sM6G4/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vMWQvNDkvMmRiZTFlYmJjODc4MDg3OTIzZTE4MDQxMjg0MmQ3OGVkOTc1MWQ0OS5qcGVn.webp',
x: 0,
y: 0
},
{
url: 'https://photo.colorhub.me/v-a0VjH_zy8/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vOTAvNmYvMTVjMTc0MzgzMzllMTg2OGRiOWEzZTQxMDRiZjcwMjM4Y2Q1OTA2Zi5qcGVn.webp',
x: 0,
y: 0
},
{
url: 'https://img.colorhub.me/qaEWeUC5c9c/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vN2MvNWQvZjliOTc1YjFjMWI4NmE4MDhiYTYxNjhhM2JmM2UxOTEzMTgyN2M1ZC5qcGVn.webp',
x: 0,
y: 0
},
{
url: 'https://photo.colorhub.me/1ejmPjby2d0/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vY2UvNTcvM2Q4Mzg0YTQ3MGU4NzZlNTViNDg0ODFmYzUxYzM1MDU0NTk5Y2U1Ny5qcGc.webp',
x: 0,
y: 0
}, {
url: 'https://photo.colorhub.me/7AOB0NAaR0M/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vNzAvYWYvNzE1MjNmYTRkYTg3MDUwNzZmNWEwMGQ5ZDU1NTY4NWNhZGVjNzBhZi5qcGVn.webp',
x: 0,
y: 0
},
{
url: 'https://cdn.colorhub.me/Qf2HhLXPads/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vNzYvNzMvNWYwZjkyNDczNWVjZjM1NmIxNjllMzE5ZTI5NGZmN2Q4ZDQyNzY3My5qcGVn.webp',
x: 0,
y: 0
},
{
url: 'https://img.colorhub.me/_4JZX-83nJ8/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vZjgvZWYvMjUxMjQ4NjYzZDIzYmJhZmRlN2ViZTEwZTgzZDA5ZDA5ZWJiZjhlZi5qcGVn.webp',
x: 0,
y: 0
}, {
url: 'https://cdn.colorhub.me/uEfq-MyTM2o/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vYzYvOTcvMjJmZDQ3NDdhMTljZTI0NjJjNjQ2Y2ZhY2YyMGZiY2ZhMTUxYzY5Ny5qcGc.webp',
x: 0,
y: 0
},
{
url: 'https://cdn.colorhub.me/B4oQ_z1BvJc/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vOTkvNGYvMTA4ZGNlYmVlYWU1YWEyZGVlNzJmNzk5NjgwODAxYTkxZDY0OTk0Zi5qcGVn.webp',
x: 0,
y: 0
},
{
url: 'https://img.colorhub.me/8gK5WgsJi_0/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vMjUvNTIvOWFmOWM4Yjg3ZWMxZmU5ODg3Y2UyNzQ3MTQ1NjY0YTNiNWRiMjU1Mi5qcGVn.webp',
x: 0,
y: 0
},
{
url: 'https://img.colorhub.me/DAWB9Jj1Ais/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vYjUvZmUvODNlZGY0OTNhZmVhZTRlY2M1OGQ1MDY0YWQzYzJhYzNkYjM2YjVmZS5qcGVn.webp',
x: 0,
y: 0
},
{
url: 'https://img.colorhub.me/81plMyBlfqk/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vNzUvMjMvZTg4MzJlZmE3MTFiMWE4M2I3M2VmOWU5YzIyNzFmODAxZDVkNzUyMy5qcGVn.webp',
x: 0,
y: 0
}, {
url: 'https://cdn.colorhub.me/lDLUT-mvKks/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vZWMvNjkvY2NmMDlkZTc1ZTM3MzMxYTdkNTVhMDZkYjY3MDQxNjY0Y2FkZWM2OS5qcGVn.webp',
x: 0,
y: 0
},
],
dropDownData: [
{
url: 'https://photo.colorhub.me/4khg6amuZ9M/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vMzUvN2QvMjdhYjA2MmQzOGJjNmQwZDZmYTY0ZmQ3M2JmMTA5NzdjYjNhMzU3ZC5qcGVn.webp',
x: 0,
y: 0
},
{
url: 'https://photo.colorhub.me/s4HBOYxWq90/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vMmEvYWMvMmYyNWJlNWI0YmY5MzM5YzhiOWNkOGM2NzkxMzkwODJhMDFlMmFhYy5qcGVn.webp',
x: 0,
y: 0
}, {
url: 'https://cdn.colorhub.me/uv4uJAItejI/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vMDMvMTgvYWMwMDg1ODdhYTEzZDViNjI1OTA2OGJhOTg3MDNmNjc2MTMwMDMxOC5qcGVn.webp',
x: 0,
y: 0
},
{
url: 'https://cdn.colorhub.me/0pxXm7FwgQU/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vMzIvZWIvMGQ0Y2ZiNzkzMjlmNDI0ZTJlY2U4YTI1MjZkY2Q3ZjZiOGQ4MzJlYi5qcGc.webp',
x: 0,
y: 0
},
{
url: 'https://img.colorhub.me/5HEmB2Et7lw/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vNDIvNzUvN2M3MjdmYzFiZDNmN2FhZmFkYzQ5Y2E5MjQ3ZGRjOGEzMzI3NDI3NS5qcGVn.webp',
x: 0,
y: 0
},
{
url: 'https://cdn.colorhub.me/Tlr2i3HcNYY/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vN2MvMDkvYmZkYzc3MTk4ZTE1Mjg2ZjVmNTI0OWMwZjNkZjY4YWE4OGZlN2MwOS5qcGVn.webp',
x: 0,
y: 0
},
{
url: 'https://cdn.colorhub.me/31EWPPaC3rM/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vMjQvMDUvYzZhMDU1NTdkZDE2NDdiZjJlNzYyNzkzM2U1OWM1OWVjZTFmMjQwNS5qcGVn.webp',
x: 0,
y: 0
},
{
url: 'https://cdn.colorhub.me/ojwHoKOthec/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vNmYvNjMvOGJjODJjNjNmMzYyM2M4MWI1NzkwYWY1MWE3Y2Y0YmNhYTAzNmY2My5qcGVn.webp',
x: 0,
y: 0
},
{
url: 'https://img.colorhub.me/G3S8lTFEJIQ/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vOGYvMGEvMTlmZjkyNjg1YTMxZDM0MzVjMDdhMGFiMzBhOGU5MzI1YzdlOGYwYS5qcGVn.webp',
x: 0,
y: 0
}, {
url: 'https://photo.colorhub.me/sYVTa7sM6G4/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vMWQvNDkvMmRiZTFlYmJjODc4MDg3OTIzZTE4MDQxMjg0MmQ3OGVkOTc1MWQ0OS5qcGVn.webp',
x: 0,
y: 0
},
{
url: 'https://photo.colorhub.me/v-a0VjH_zy8/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vOTAvNmYvMTVjMTc0MzgzMzllMTg2OGRiOWEzZTQxMDRiZjcwMjM4Y2Q1OTA2Zi5qcGVn.webp',
x: 0,
y: 0
},
{
url: 'https://img.colorhub.me/qaEWeUC5c9c/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vN2MvNWQvZjliOTc1YjFjMWI4NmE4MDhiYTYxNjhhM2JmM2UxOTEzMTgyN2M1ZC5qcGVn.webp',
x: 0,
y: 0
},
{
url: 'https://photo.colorhub.me/1ejmPjby2d0/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vY2UvNTcvM2Q4Mzg0YTQ3MGU4NzZlNTViNDg0ODFmYzUxYzM1MDU0NTk5Y2U1Ny5qcGc.webp',
x: 0,
y: 0
}, {
url: 'https://photo.colorhub.me/7AOB0NAaR0M/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vNzAvYWYvNzE1MjNmYTRkYTg3MDUwNzZmNWEwMGQ5ZDU1NTY4NWNhZGVjNzBhZi5qcGVn.webp',
x: 0,
y: 0
},
{
url: 'https://cdn.colorhub.me/Qf2HhLXPads/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vNzYvNzMvNWYwZjkyNDczNWVjZjM1NmIxNjllMzE5ZTI5NGZmN2Q4ZDQyNzY3My5qcGVn.webp',
x: 0,
y: 0
},
{
url: 'https://img.colorhub.me/_4JZX-83nJ8/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vZjgvZWYvMjUxMjQ4NjYzZDIzYmJhZmRlN2ViZTEwZTgzZDA5ZDA5ZWJiZjhlZi5qcGVn.webp',
x: 0,
y: 0
}, {
url: 'https://cdn.colorhub.me/uEfq-MyTM2o/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vYzYvOTcvMjJmZDQ3NDdhMTljZTI0NjJjNjQ2Y2ZhY2YyMGZiY2ZhMTUxYzY5Ny5qcGc.webp',
x: 0,
y: 0
},
{
url: 'https://cdn.colorhub.me/luBXTEKH8FM/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vMWEvNGEvMDc3Mjk3MjEyNzUxYmJkNTZjZTE3MTk1YWIwYTlmOWRiYWFmMWE0YS5qcGVn.webp',
x: 0,
y: 0
},
{
url: 'https://img.colorhub.me/8gK5WgsJi_0/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vMjUvNTIvOWFmOWM4Yjg3ZWMxZmU5ODg3Y2UyNzQ3MTQ1NjY0YTNiNWRiMjU1Mi5qcGVn.webp',
x: 0,
y: 0
},
{
url: 'https://img.colorhub.me/DAWB9Jj1Ais/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vYjUvZmUvODNlZGY0OTNhZmVhZTRlY2M1OGQ1MDY0YWQzYzJhYzNkYjM2YjVmZS5qcGVn.webp',
x: 0,
y: 0
},
{
url: 'https://img.colorhub.me/81plMyBlfqk/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vNzUvMjMvZTg4MzJlZmE3MTFiMWE4M2I3M2VmOWU5YzIyNzFmODAxZDVkNzUyMy5qcGVn.webp',
x: 0,
y: 0
}, {
url: 'https://cdn.colorhub.me/lDLUT-mvKks/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vZWMvNjkvY2NmMDlkZTc1ZTM3MzMxYTdkNTVhMDZkYjY3MDQxNjY0Y2FkZWM2OS5qcGVn.webp',
x: 0,
y: 0
},
],
}
},
async mounted() {
await this.getColumnNums()
await this.calcData(this.list)
window.addEventListener('resize', this.handleResize);
window.addEventListener('scroll', this.handleScroll);
},
beforeDestroy() {
// 在组件销毁前移除事件监听,避免内存泄漏
window.removeEventListener('resize', this.handleResize);
window.removeEventListener('scroll', this.handleScroll);
},
methods: {
//窗口改变重新计算
async handleResize() {
await this.getColumnNums()
await this.newCalc()
},
//触底加载更多
async handleScroll() {
if (this.loadMore) return
const scrollTop =
document.documentElement.scrollTop || document.body.scrollTop;
const clientHeight =
document.documentElement.clientHeight || document.body.clientHeight;
const scrollHeight =
document.documentElement.scrollHeight || document.body.scrollHeight;
if (scrollTop + clientHeight + 10 >= scrollHeight) {
this.loadMore = true
await this.newAddCalc(this.dropDownData)
}
},
async newAddCalc(list) {
for (let i = 0; i < list.length; i++) {
this.list.push(await this.newGetImgInfo(list[i], i))
}
},
newGetImgInfo(item, idx) {
let that = this
return new Promise((resolve, reject) => {
let img = new Image()
img.src = item.url
img.onload = function () {
//渲染后的高度
let renderHeight = ((that.width - 10) / this.width * this.height) + 10
let {value, index} = that.findMinItemAndIndex(that.columns)
item.x = index * that.width
item.y = value
that.columns[index] += renderHeight
item.renderHeight = renderHeight
resolve(item)
}
});
},
newCalc() {
this.list.map((item, idx) => {
if (idx < this.columnNums) {
item.y = 0
item.x = idx * this.width
this.columns[idx] = item.renderHeight
} else {
let {value, index} = this.findMinItemAndIndex(this.columns)
item.x = index * this.width
item.y = value
this.columns[index] += item.renderHeight
}
})
},
async calcData(list) {
for (let i = 0; i < list.length; i++) {
await this.getImgInfo(list[i], i)
}
},
//获取图片的高度
getImgInfo(item, idx) {
let that = this
return new Promise((resolve, reject) => {
let img = new Image()
img.src = item.url
img.onload = function () {
//渲染后的高度
let renderHeight = ((that.width - 10) / this.width * this.height) + 10
if (idx < that.columnNums) {
item.y = 0
item.x = idx * that.width
that.columns[idx] = renderHeight
} else {
let {value, index} = that.findMinItemAndIndex(that.columns)
item.x = index * that.width
item.y = value
that.columns[index] += renderHeight
}
item.renderHeight = renderHeight
resolve()
}
});
},
//获取一共可以展示几列
getColumnNums() {
this.$nextTick(() => {
this.columns = []
let {width} = this.$refs.waterfallFlow.getBoundingClientRect()
this.columnNums = ~~Number((width / this.width))
for (let i = 0; i < this.columnNums; i++) {
this.columns.push(0)
}
})
},
//获取数组中最小的那一项和下标
findMinItemAndIndex(arr) {
let min = arr[0];
let minIndex = 0;
for (let i = 1; i < arr.length; i++) {
if (arr[i] < min) {
min = arr[i];
minIndex = i;
}
}
return {value: min, index: minIndex};
}
},
}
</script>
<style lang="scss" scoped>
.waterfallFlow-wrapper {
position: relative;
.waterfallFlow-item {
position: absolute;
left: 0;
top: 0;
padding: 5px;
box-sizing: border-box;
transition: .3s linear;
}
}
</style>
vue实现瀑布流+下拉加载更多
于 2024-07-13 15:17:12 首次发布