一、整理思路
- 实际场景中,瀑布流一般由
父组件
提供 数据列表
,子组件渲染
- 每个图片都是根据容器进行
绝对定位
,从而定好自己的位置
- 取出
屏幕的宽度
,设定 图片的宽度
固定
为一个值,计算可以铺 多少列
- 按列数
先铺上第一行
(left
、top
值)
- 第一行铺满以后,后面的每一张都要
铺在高度最低的列
,这是瀑布流的核心!所以要维护一个 长度为 列数 的 列高度数组
用于比较
- 总结:每次放置一张图,都要计算它的
left
、top
值丢进瀑布流数组中,并且更新 列高度数据
便于下次对比
二、代码
父组件
<WaterFall :list="list" />
const list = [
{
height: 300,
background: "red",
},
{
height: 400,
background: "pink",
},
{
height: 500,
background: "blue",
},
{
height: 200,
background: "green",
},
{
height: 300,
background: "gray",
},
{
height: 400,
background: "#CC00FF",
},
{
height: 200,
background: "gray",
},
{
height: 100,
background: "#996666",
},
{
height: 500,
background: "skyblue",
},
{
height: 300,
background: "#993366",
},
{
height: 100,
background: "#33FF33",
},
{
height: 400,
background: "skyblue",
},
{
height: 200,
background: "#6633CC",
},
{
height: 300,
background: "#666699",
},
{
height: 300,
background: "#66CCFF",
},
{
height: 300,
background: "skyblue",
},
{
height: 200,
background: "#CC3366",
},
{
height: 200,
background: "#CC9966",
},
{
height: 200,
background: "#FF00FF",
},
{
height: 500,
background: "#990000",
},
{
height: 400,
background: "red",
},
{
height: 100,
background: "#999966",
},
{
height: 200,
background: "#CCCC66",
},
{
height: 300,
background: "#FF33FF",
},
{
height: 400,
background: "#FFFF66",
},
{
height: 200,
background: "red",
},
{
height: 100,
background: "skyblue",
},
{
height: 200,
background: "#33CC00",
},
{
height: 300,
background: "#330033",
},
{
height: 100,
background: "#0066CC",
},
{
height: 200,
background: "skyblue",
},
{
height: 100,
background: "#006666",
},
{
height: 200,
background: "yellow",
},
{
height: 300,
background: "skyblue",
},
{
height: 120,
background: "#33CCFF",
},
{
height: 400,
background: "#999966",
},
{
height: 630,
background: "#CC9966",
},
{
height: 250,
background: "#33FF00",
},
{
height: 300,
background: "yellow",
},
{
height: 500,
background: "green",
},
];
子组件
<template>
<div class="list">
<div
class="item"
v-for="(item, index) in waterList"
:style="{
width: width + 'px',
height: item.height + 'px',
left: item.left + 'px',
top: item.top + 'px',
background: item.background,
}"
>
{{ index }}
div>
div>
template>
<script setup lang="ts">
import { ref, reactive, onMounted } from "vue";
const props = defineProps<{
list: any[];
}>();
const width = 120;
const gap = 20;
const waterList = ref<any[]>([]);
const heightList = reactive<number[]>([]);
onMounted(() => {
const column = Math.floor(document.body.clientWidth / width);
for (let i = 0; i < props.list.length; i++) {
if (i < column) {
props.list[i].top = 0;
props.list[i].left = width * i;
waterList.value?.push(props.list[i]);
heightList[i] = props.list[i].height;
}
else {
let current = heightList[0];
let col = 0;
heightList.forEach((h, i) => {
if (h < current) {
current = h;
col = i;
}
});
console.log("最低的列", col, "高度为", current);
props.list[i].left = col * width;
props.list[i].top = current + gap;
waterList.value.push(props.list[i]);
heightList[col] = current + gap + props.list[i].height;
}
}
console.log("waterList", waterList.value);
console.log("heightList", heightList);
});
</script>
<style lang="scss" scoped>
.list {
position: relative;
height: 100%;
overflow: auto;
.item {
position: absolute;
font-size: 30px;
}
}
</style>
效果如图