瀑布流(Waterfall)是一种常见的网页布局方式,尤其适用于图片或卡片的展示。这种布局的特点是内容块在页面上垂直堆叠,同时每个内容块的宽度可能不同,从而在视觉上形成类似瀑布的层叠效果。瀑布流布局可以提高页面的美感和用户体验。
react
import React, { useState, useEffect } from "react";
const Masonry = ({ columns = 3, gap = 4, images }) => {
const [columnHeights, setColumnHeights] = useState(
new Array(columns).fill(0)
);
const [items, setItems] = useState([]);
useEffect(() => {
const heights = new Array(columns).fill(0);
const layoutItems = images.map((image) => {
const columnIndex = heights.indexOf(Math.min(...heights));
const newHeight = heights[columnIndex] + image.height + gap;
heights[columnIndex] = newHeight;
return {
...image,
column: columnIndex,
};
});
setItems(layoutItems);
setColumnHeights(heights);
}, [images, columns, gap]);
return (
<div className="flex gap-4">
{Array.from({ length: columns }).map((_, columnIndex) => (
<div key={columnIndex} className="flex flex-col gap-4 flex-1">
{items
.filter((item) => item.column === columnIndex)
.map((item) => (
<div key={item.src} className="mb-4">
<img src={item.src} alt={item.alt} className="w-full block" />
</div>
))}
</div>
))}
</div>
);
};
export default Masonry;
这段代码实现了一个简单的 Masonry 布局组件,它根据列数 (columns
)、间距 (gap
)、以及传入的图片列表 (images
) 来动态排列图片,使其形成一个瀑布流式的布局。
主要概念与逻辑
1. 状态管理
useState
钩子用于管理两个状态:columnHeights
:存储每一列的当前高度,初始值为[0, 0, 0]
(假设默认列数为3)。items
:存储已经计算好布局的图片数据,包括图片属于哪一列的信息。
javascriptconst [columnHeights, setColumnHeights] = useState(new Array(columns).fill(0)); const [items, setItems] = useState([]);
2. 布局计算
useEffect
钩子在images
,columns
,gap
改变时执行,用来计算每张图片应放在哪一列以及每一列的高度。javascriptuseEffect(() => { const heights = new Array(columns).fill(0); const layoutItems = images.map((image) => { const columnIndex = heights.indexOf(Math.min(...heights)); const newHeight = heights[columnIndex] + image.height + gap; heights[columnIndex] = newHeight; return { ...image, column: columnIndex, }; }); setItems(layoutItems); setColumnHeights(heights); }, [images, columns, gap]);
heights
:用于存储每一列的当前高度,初始值为[0, 0, 0]
。layoutItems
:通过map
遍历images
,为每张图片计算其所属的列 (columnIndex
),根据当前最矮的列来决定图片放在哪一列。
javascriptconst columnIndex = heights.indexOf(Math.min(...heights));
Math.min(...heights)
用来找到当前最矮的列,然后使用heights.indexOf
找到对应的列索引columnIndex
。newHeight
:计算图片放置后该列的高度,newHeight = heights[columnIndex] + image.height + gap;
。
最后更新每列的高度,并返回新图片对象,包含图片本身的数据和它所属的列 (
column
)。
3. 布局渲染
在
return
语句中,根据计算出的items
数组进行布局渲染。javascriptreturn ( <div className="flex gap-4"> {Array.from({ length: columns }).map((_, columnIndex) => ( <div key={columnIndex} className="flex flex-col gap-4 flex-1"> {items .filter((item) => item.column === columnIndex) .map((item) => ( <div key={item.src} className="mb-4"> <img src={item.src} alt={item.alt} className="w-full block" /> </div> ))} </div> ))} </div> );
Array.from({ length: columns })
:创建一个数组,其长度等于列数,以此来生成每一列的容器<div>
。filter
:在每一列中,筛选出属于该列的图片。map
:遍历筛选后的图片,渲染每一张图片。
flex
布局:整个布局使用flex
来创建水平排列的列,并在每一列中使用flex-col
创建垂直排列的图片列表。gap
:用于设置图片之间的间距。
组件功能
- 动态生成任意数量的列,并根据图片的高度和给定的间距实现瀑布流布局。
- 图片被自动分配到当前最矮的列,以保持整体视觉平衡。
columns
、gap
和images
参数可动态调整,布局将自动更新。