基本思路
假设一排放5张图片。当第一排排满足够多的等宽的元素时,显示的是这样的。那么假如我们要放第6个元素的时候,应该放在什么位置呢? 如果按照我们的正常逻辑来想,应该是放在第一张图片下面,依次水平排列过去,如下图:
这样布局会出现列的长短不一,实现不了瀑布流的效果,正确的思路应该是从第6个元素开始,接下去的每一个元素都会放在上行中高度最低的那一列下方。如下图:
代码实现
ini
import { useEffect } from 'react';
import styles from './style.module.scss'
import classNames from 'classnames';
const list = [
{
img:'https://img0.baidu.com/it/u=2269054305,2051617662&fm=253&fmt=auto&app=138&f=JPEG?w=347&h=459',
title:'这是标题这是标题',
des:'这是描述一一一一一一'
},
{
img:'https://img1.baidu.com/it/u=1569101010,2354561158&fm=253&fmt=auto&app=138&f=JPEG?w=477&h=500',
title:'这是标题这是标题',
des:'这是描述这是描述这是描述这是描述这是描述这是描述二二二二二二二二二二'
},
{
img:'https://img0.baidu.com/it/u=546803172,3230568524&fm=253&fmt=auto&app=138&f=PNG?w=427&h=500',
title:'这是标题这是标题',
des:'这是描述这是描述这是描述这是描述这是描述这是描述这是描述这是描述这是描述这是描述这是描述这是描述'
},
{
img:' https://img1.baidu.com/it/u=1937457859,1823693439&fm=253&fmt=auto&app=138&f=JPEG?w=456&h=455',
title:'这是标题这是标题',
des:'这是描述这是描述这是描述这是描述三三'
},
{
img:'https://img0.baidu.com/it/u=1440396978,4151905066&fm=253&fmt=auto&app=138&f=JPEG?w=388&h=556',
title:'这是标题这是标题',
des:'这是描述这是描述这是描述这是描述这是描述这是描述这是描述这是描述这是描述这是描述这是描述这是描述'
},
{
img:'https://img2.baidu.com/it/u=3300693751,3848672578&fm=253&fmt=auto&app=138&f=PNG?w=500&h=754',
title:'这是标题这是标题',
des:'这是描述这是描述这是描述这是描述这是描述'
},
{
img:'https://img0.baidu.com/it/u=3573637456,2237837126&fm=253&fmt=auto&app=138&f=JPEG?w=268&h=347',
title:'这是标题这是标题',
des:'这是描述这是描述这是描述这是描述这是描述这是描述四四四这是描述这是描述这是描述这是描述这是描述这是描述四四四'
},
{
img:'https://img1.baidu.com/it/u=2908802412,1187745874&fm=253&fmt=auto&app=120&f=JPEG?w=196&h=228',
title:'这是标题这是标题',
des:'这是描述这是描述这是描述这是描述这是描述'
},
]
const Home = () => {
// 每一行显示5个元素
const column = 5;
// 间距
const gap = 20;
// 每列高度数组
const heightList:number[] = [];
useEffect(()=>{
getElementPosition();
setListHeight();
},[])
const getElementPosition = ()=>{
const items = document.querySelectorAll('.item');
const iWidth = (window.innerWidth - 40 - (column - 1) * gap) / column;
for(let index = 0; index < items.length; index ++){
const item = items[index];
const height = items[index].clientHeight;
// 设置第一排元素样式,记录每一列高度
if (index < column) {
heightList[index] = height;
item.setAttribute(
"style",
`width: ${iWidth}px;transform: translate(${index*iWidth+index*gap}px,0)`
)
// 后面每次向高度最低的列加入数据
}else{
let minHeight :number = heightList[0];
let minIndex :number = 0;
// 找到最小高度元素,向下插入元素
for (let j = 0; j < heightList.length; j++) {
if (minHeight > heightList[j]) {
minHeight = heightList[j];
minIndex = j;
}
}
// 设置插入元素位置
item.setAttribute(
"style",
`width:${iWidth}px;transform:translate(${(iWidth + gap) * minIndex}px,${minHeight + gap}px);`
);
// 更新最小高度
heightList[minIndex] = height + gap + minHeight;
}
}
}
const setListHeight = ()=>{
const max = Math.max(...heightList);
const list = document.getElementById('list');
if(list){
list.style.height = `${max}px`;
}
}
return (
<div className={styles.home}>
<div className={classNames(styles.list)} id='list'>
{
list.map((n,index)=>{
return <div className={classNames(styles.item,"item")} key={index}
>
<div className={styles['img-wrap']}>
<img src={n.img} alt="" />
</div>
<div className={styles.title}>{n.title}</div>
<div className={styles.des}>{n.des}</div>
</div>
})
}
</div>
</div>
);
};
export default Home;
css
// style.module.scss
.home{
padding: 20px 30px;
background: #fff;
.list {
width: 100%;
position: relative;
.item{
position: absolute;
left: 0;
top: 0;
border:1px solid #eee;
padding: 10px;
box-sizing: border-box;
.img-wrap{
width: 100%;
img{
width: 100%;
height: auto;
}
}
.title{
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
}
}
效果如图: