你可以准备一些长宽都不相等的图片。
瀑布流特点
- 等宽不等高
- 为了让最后一行的差距最小,从第二行开始,需要将图片放在第一行最矮的图片下面
实现思路
- 设定每一列图片的宽度和间距
- 获取当前窗口的总宽度,从而根据图片宽度去判断分为几列
- 获取所有图片元素,定义一个空数组来保存高度
- 遍历容器
4.1 第一排,top固定 为gap;left 根据列数递增 为 (itemWidth+gap)i + gap
4.2 非第一批, top( minHeight+gap2) left的计算方式和4.1一样,其中i的位置是minHeight所在的列数 - 调用
function waterFall(){
const minGap = 20 // 粗略设定一个你想要的最小间距
const itemWidth = 300 // 定义每一项的宽度(保证等宽)
const scrollBarWidth = getScrollbarWidth(); //获取滚动条宽度
const pageWidth = window.innerWidth - scrollBarWidth; // 获取当前页面的宽度
// 实际列数= 页面宽度/(图片宽度+最小间距)
const column - Math.floor(pageWidth/(itemWidth+minGap))
//计算真实间距
const gap = (pageWidth - itemWidth*column) / column / 2;
const items = document.querySelectorAll("img")
const heightArr = [] // 定义一个空数组,保存最低高度
//便利所有的外层容器
for(let i = 0; i < items.length; i++){
const height = items[i].offsetHeight;
if(i < column){
// 索引i小于列数,当前为第一行;直接设置元素距离上一个左边距
items[i].style.cssText = `top: ${gap}px; left: ${(itemWidth + gap) * i + gap}px`;
// 保存当前元素的高度
heightArr.push(height)
}else{
// 不是第一行,进行比对
let minHeight = heightArr[0]
let minIndex = 0
for(let j = 0; j < heightArr.length; j++){
// 通过循环遍历比对,拿到最小值和最小值的索引
if(minHeight > heightArr[j]){
minHeight = heightArr[j]
minIndex = j
}
}
items[i].style.cssText = `top:${minHeight+gap*2}px; left: ${(itemWidth+gap)*minIndex + gap}px`
heightArr[minIndex] = minHeight + gap + height
}
}
}
// 获取滚动条宽度
function getScrollbarWidth(){
const oDiv = document.createElement('div')
oDiv.style.cssTex = `width:50px; height:50px; overflow:scroll;`
document.body.appendChild(oDiv) // 把div添加到body中
const scrollbarWidth = oDiv.offsetWidth - oDiv.clientWidth; // 使最大宽度和可视宽度相减,获得滚动条宽度
oDiv.remove();// 移出创建的div
return scrollbarWidth; // 返回滚动条宽度
}
window.onload = waterFall
window.onresize = waterFall;
完整代码
<!DOCTYPE html>
<html>
<head>
<style>
.box {
width: 100%;
height: 100%;
position:relative;
}
.item img{
position: absolute;
width: 300px;
}
</style>
</head>
<body>
<div class="box" style="border: 10px red solid;">
<div class="item">
<img src="1.jpeg" alt="" />
</div>
<div class="item" style="border: 1px red solid;">
<img src="2.jpeg" alt="" />
</div>
<div class="item">
<img src="3.jpeg" alt="" />
</div>
<div class="item">
<img src="4.jpeg" alt="" />
</div>
<div class="item">
<img src="5.jpeg" alt="" />
</div>
<div class="item">
<img src="6.jpeg" alt="" />
</div>
<div class="item">
<img src="7.jpeg" alt="" />
</div>
<div class="item">
<img src="8.jpeg" alt="" />
</div>
<div class="item">
<img src="9.jpeg" alt="" />
</div>
<div class="item">
<img src="10.jpeg" alt="" />
</div>
<div class="item">
<img src="11.jpeg" alt="" />
</div>
</div>
</body>
1 <script type="text/javascript">
// 定义瀑布流算法函数
function fall() {
const minGap = 10; // 最小间距,让每一列的最小空隙可以自定义,避免太过拥挤的情况发生。但是,会通过计算得到真实的间距。
const itemWidth = 300; // 每一项的宽度,即当前每一个图片容器的宽度。保证每一列都是等宽不等高的。
const scrollBarWidth = getScrollbarWidth(); // 获取滚动条的宽度
console.log("##############3",scrollBarWidth);
const pageWidth = window.innerWidth - scrollBarWidth; // 获取当前页面的宽度 = window.innerWidth - 滚动条的宽度
const column = Math.floor(pageWidth / (itemWidth + minGap)); // 实际列数=页面宽度/(图片宽度+最小间距)
const gap = (pageWidth - itemWidth * column) / column/2; // 计算真实间距 = (页面宽度- 图片宽度*实际列数)/实际列数/2
const items = document.querySelectorAll('img'); // 获取所有的外层元素
const heightArr = []; // 定义一个空数组,保存最低高度。
// 获取滚动条的宽度
function getScrollbarWidth() {
const oDiv = document.createElement('div');//创建一个div
// 给div设置样式。随便定义宽高,只要能获取到滚动条就可以
oDiv.style.cssText = `width: 50px;height: 50px;overflow: scroll;`
document.body.appendChild(oDiv);//把div添加到body中
const scrollbarWidth = oDiv.offsetWidth - oDiv.clientWidth;// 使最大宽度和可视宽度相减,获得到滚动条宽度。
oDiv.remove();//移除创建的div
return scrollbarWidth;//返回滚动条宽度
}
for (let i = 0; i < items.length; i++) {
// 遍历所有的外层容器
const height = items[i].offsetHeight;
// 如果当前处在第一行
if (i < column) {
// 直接设置元素距离上部的位置和距离左边的距离。
items[i].style.cssText = `top: ${gap}px;left: ${(itemWidth + gap) * i + gap}px`;
// 保存当前元素的高度。
heightArr.push(height);
} else {
// 不是第一行的话,就进行比对。
let minHeight = heightArr[0]; // 先保存第一项的高度
let minIndex = 0; // 保存第一项的索引值
for (let j = 0; j < heightArr.length; j++) {
// 通过循环遍历比对,拿到最小值和最小值的索引。
if (minHeight > heightArr[j]) {
minHeight = heightArr[j];
minIndex = j;
}
}
// 通过最小值为当前元素设置top值,通过索引为当前元素设置left值。
items[i].style.cssText = `top: ${minHeight + gap *2}px; left: ${(itemWidth + gap) * minIndex + gap}px`;
// 并修改当前索引的高度为当前元素的高度
heightArr[minIndex] = minHeight + gap + height;
}
}
}
// 页面加载完成调用一次。
window.onload = fall;
// 页面尺寸发生改变再次调用。
window.onresize = fall;
</script>
</html>
参考
关于瀑布流的布局原理…