# 什么是瀑布流?
- 瀑布流,又称瀑布流式布局
- 是比较流行的一种网站页面布局,视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部
- 最早采用此布局的网站是 Pinterest,逐渐在国内流行开来。国内大多数清新站基本为这类风格
- 即多行等宽元素排列,后面的元素依次添加到其后,等宽不等高,根据图片原比例缩放直至宽度达到我们的要求,依次按照规则放入指定位置。
- 就比如下面这种效果就属于瀑布流布局
# 实现思路
-
本人比较懒,不做图介绍,这里进行文字描述~还有不明白的可自行问度娘!
-
首先我们肯定是要先获取父元素与所有子元素
-
然后获取第一个子元素的宽度和屏幕的宽度,然后使用
屏幕宽度 / 子元素宽度
向下取整计算出列数 -
再声明一个数组存放元素的高度,数组长度应与列数一致
-
数组中的第一组元素高度值应该是小于列数的元素高度值
-
每次循环获取当前元素的高度值
-
然后每次循环求出
最小高度与最小高度它的索引
,以索引从小到大的顺序依次
定位图片top
值 -
并利用
索引 * 图片宽度
计算出应在的列数位置 -
同时利用最小索引求出应该相加的元素,将数组中的最小值进行累加
-
举个栗子
// 这是一个元素高度值数组 此时最小值为 10 它的索引为 0 | |
let list = [10, 20, 30, 40] | |
// 进行循环 例如当前元素高度为 50 那么数组中的最小值会加上元素高度 即 list [0] += 50 | |
let list = [10 + 50, 20, 30, 40] -> [60, 20, 30, 40] // 此时最小值为 20 它的索引为 1 | |
// 接着循环第二个元素 假如高度值为 30 即应该 list [1] += 30 | |
let list = [60, 20 + 30, 30, 40] -> [60, 50, 30, 40] // 此时最小值为 30 它的索引为 2 | |
// 依次类推.... |
- 这就是实现瀑布流的思路,下面进行代码实现~
# 实现 waterFall
// 1.0 定义一个函数 接收 父元素 与 子元素们 选择器 | |
function waterFall(parent, childs) { | |
// 1.1 获取标签父元素与其中的所有子元素 | |
const parentEl = document.querySelector(parent) | |
const childsEls = document.querySelectorAll(childs) | |
// 1.2 获取一个子元素的宽度 | |
const childElWidth = childsEls[0].offsetWidth | |
// 1.3 获取屏幕的宽度 进行兼容判断 | |
const screenWidth = document.documentElement.clientWidth || document.body.clientWidth | |
// 1.4 根据上面条件计算出应排版列数 | |
const cols = ~~(screenWidth / childElWidth) | |
// 1.5 给父元素宽度并进行居中 | |
parentEl.style.width = cols * childElWidth + 'px' | |
parentEl.style.margin = '0 auto' | |
// 2.0 声明数组 存放每次应该定位的高度 数组长度与列数一致 | |
const childsElHeightArr = [] | |
// 2.1 声明三个变量 分别用于保存 数组中最小高度、元素高度与最小索引值 | |
let minChildElHeight = 0, childElHeight = 0, minIndex = 0 | |
// 3.0 对所有子元素进行遍历 | |
childsEls.forEach((item, index) => { | |
// 3.1 遍历获取元素的高度 | |
childElHeight = item.offsetHeight | |
// 3.2 判断如果列数小于 index 则是第一排元素 添加进数组用于计算高度 | |
if (cols > index) return childsElHeightArr.push(childElHeight) | |
// 3.3 否则利用算法金星定位 | |
// 3.4 计算出数组中的最小高度 | |
minChildElHeight = Math.min(...childsElHeightArr) | |
// 3.5 计算数组最小高度所在的索引 这里我封装一个函数 calcMinIndex 即 -> 4.0 | |
minIndex = calcMinIndex(childsElHeightArr) | |
// 3.6 进行绝对定位 | |
item.style.position = 'absolute' | |
// 3.7 利用最小索引 * 元素宽度 得出子元素据左的距离 | |
item.style.left = minIndex * childElWidth + 'px' | |
// 3.8 将每次最小高度赋值给元素的高度 | |
item.style.top = minChildElHeight + 'px' | |
// 3.9 将每次最小高度值与元素高度进行相加 | |
childsElHeightArr[minIndex] += childElHeight | |
// 4.0 封装计算数组最小值的索引 | |
function calcMinIndex(array) { | |
let index = 0 | |
for (let i = 0; i < array.length; i++){ | |
if (array[index] > array[i]) index = i | |
} | |
return index | |
} | |
}) | |
} |
# 测试代码
# CSS
代码
* { | |
padding: 0; | |
margin: 0; | |
} | |
img { | |
max-width: 300px; | |
vertical-align: top; | |
} | |
#main { | |
position: relative; | |
} | |
.box { | |
float: left; | |
padding: 12px 0 0 12px; | |
} | |
.pic { | |
padding: 10px; | |
border: 1px solid #ccc; | |
} |
# HTML
代码
<div id="main"> | |
<div class="box"> | |
<div class="pic"><img src="./images/01.jpg" alt=""></div> | |
</div> | |
<div class="box"> | |
<div class="pic"><img src="./images/02.jpg" alt=""></div> | |
</div> | |
<div class="box"> | |
<div class="pic"><img src="./images/03.jpg" alt=""></div> | |
</div> | |
<div class="box"> | |
<div class="pic"><img src="./images/04.jpg" alt=""></div> | |
</div> | |
<div class="box"> | |
<div class="pic"><img src="./images/05.jpg" alt=""></div> | |
</div> | |
<div class="box"> | |
<div class="pic"><img src="./images/06.jpg" alt=""></div> | |
</div> | |
<div class="box"> | |
<div class="pic"><img src="./images/07.jpg" alt=""></div> | |
</div> | |
<div class="box"> | |
<div class="pic"><img src="./images/08.jpg" alt=""></div> | |
</div> | |
<div class="box"> | |
<div class="pic"><img src="./images/09.jpg" alt=""></div> | |
</div> | |
<div class="box"> | |
<div class="pic"><img src="./images/10.jpg" alt=""></div> | |
</div> | |
<div class="box"> | |
<div class="pic"><img src="./images/11.jpg" alt=""></div> | |
</div> | |
<div class="box"> | |
<div class="pic"><img src="./images/12.jpg" alt=""></div> | |
</div> | |
<div class="box"> | |
<div class="pic"><img src="./images/13.jpg" alt=""></div> | |
</div> | |
<div class="box"> | |
<div class="pic"><img src="./images/14.jpg" alt=""></div> | |
</div> | |
</div> |
# JavaScript
代码
window.addEventListener('load', () => waterFall('#main','.box')) |
- 实现效果图
- 至此,实现瀑布流篇章也告辞段落了,有时间还会分享一期结合瀑布流实现懒加载的
JavaScript
原生代码~