最近在开发移动端页面时,发现好多都使用了瀑布流布局,又没找到个满意的组件,避免每次重复开发,就自行封装了个瀑布流布局组件
主要想说一下js的,也当是个人笔记,其他借助flex、column、Grid等纯css实现的瀑布流可以自行了解,那些要使用比较简单快捷的,当然每个都有它相应的缺点。
实现原理
根据数据与列参数,以数组嵌套数组为数据格式,通过v-for动态遍历渲染。
父盒子使用flex布局,在让列的盒子根据内容撑开高度。添加数据时,动态获取每列盒子的高度,往最小高度的列盒子数组添加数据,就可以实现瀑布流布局。
具体内容可以通过插槽添加
说的不太清楚,上代码:
<template>
<div class="flow-wrapper">
<div
class="flow-col"
v-for="(item, index) in showData"
:key="index"
:ref="'flowCol' + index"
>
<div class="flow-row" v-for="(v, i) in item" :key="i">
<!-- 默认插槽 内容自定义 -->
<slot :item="v"> </slot>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
// 列数
itemColumn: {
type: Number,
default: 2,
},
// 数据来源
flowData: {
type: Array,
default: () => [],
},
},
watch: {
flowData: {
deep: true,
handler(newV) {
// 提取为渲染数据,避免重复操作整个数据
this.loadData(newV.slice(this.loadTotal));
},
},
},
data: () => ({
showData: [], // 用于渲染的数组
loadTotal: 0, // 已经渲染数据总数
}),
methods: {
// 处理数据,生成渲染数组
loadData(arr) {
for (let i = 0; i < arr.length; i++) {
// 预加载图片
let newImage = new Image();
newImage.src = arr[i].src;
newImage.onload = () => {
if (this.showData.length < this.itemColumn) {
// 生成列数组
let colArr = [];
colArr.push(arr[i]);
this.showData.push(colArr);
} else {
let minIndex = this.findMinHeightColIndex(this.itemColumn);
// 将数据插入最小高度的列
this.showData[minIndex].push(arr[i]);
}
};
}
this.loadTotal = this.flowData.length;
},
findMinHeightColIndex(num) {
let minIndex = 0;
//根据动态绑定获取各列高度
let minHeight = this.$refs["flowCol0"][0].offsetHeight;
for (let k = 0; k < num; k++) {
if (minHeight > this.$refs["flowCol" + k][0].offsetHeight) {
minHeight = this.$refs["flowCol" + k][0].offsetHeight;
minIndex = k;
}
}
return minIndex;
},
},
};
</script>
<style lang="scss" scoped>
.flow-wrapper {
width: 100%;
display: flex;
align-items: flex-start;
.flow-col {
flex: 1;
margin-right: 10px;
&:last-child {
margin: 0;
}
.flow-row {
border: 1px solid rgba(7, 17, 27, 0.1);
border-radius: 6px;
overflow: hidden;
margin-bottom: 10px;
background-color: #fff;
&:last-child {
margin: 0;
}
}
}
}
</style>
效果图:
(仿美团的,数据是假数据,凑合看吧)