一、整理思路
实际场景中,瀑布流一般由 父组件
提供 数据列表
,子组件渲染 每个图片都是根据容器进行 绝对定位
,从而定好自己的位置 取出 屏幕的宽度
,设定 图片的宽度
固定
为一个值,计算可以铺 多少列
按列数 先铺上第一行
(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>
效果如图