方法1: css
使用css 只需要在容器盒子里加上这两行代码,就可以实现瀑布流,不在过多赘述
.content-box {
// 列数
columns: 5;
// 间隙值
column-gap: 10px;
}
方法2: 使用js
分析代码逻辑:
- 首先将im的盒子设置绝对定位,其父元素设置相对定位.
html部分结构:
<div class="content-box">
<div class="img-box"><img src="https://c-ssl.duitang.com/uploads/item/202009/15/20200915235152_FsBXU.thumb.1000_0.jpeg" class="img">
</div>
<div class="img-box"><img src="https://c-ssl.duitang.com/uploads/item/202004/01/20200401164316_i5rh2.thumb.1000_0.jpeg" class="img">
</div>
<-- ......-->
</div>
css代码:
.content-box {
width: 1200px;
position: relative;
margin: 50px auto;
border: 1px solid rgba(253, 114, 109, 0.5);
box-sizing: border-box;
}
.img-box .img {
width: 100%;
height: 100%;
}
.img-box {
position: absolute;
box-sizing: border-box;
}
2.计算出每一列所需要的宽度:
很明显, 每一行的宽度= (容器宽度-间隙值(列数-1))/列数*
- 渲染下一行第一个时,首先找到上一行中,盒子底部距离容器顶部距离最小的.然后将图片插入,并更新现存的列的高度,然后循环这一步
4.因为使用的是网络图片而不是本地图片,所以要等待图片加载完成后(或图片预加载)再进行瀑布流布局,否则会获取不到图片真实高度
代码实现:
(function() {
var Waterfall = function(opt) {
this.el = document.getElementsByClassName(opt.el)[0]
this.columns = opt.columns
this.gap = opt.gap
// 每个盒子
this.items = this.el.getElementsByTagName('div')
// 每个盒子的宽度
this.imgWith = (this.el.offsetWidth - this.gap * (this.columns - 1)) / this.columns
// 存储每一列的当前高度
this.heightArr = []
this.init()
}
Waterfall.prototype.init = function() {
this.render()
}
Waterfall.prototype.render = function() {
var item = null,
minIndex = -1
for (var i = 0; i < this.items.length; i++) {
item = this.items[i]
// 设置每个盒子的宽度
item.style.width = this.imgWith + 'px'
// 先确定第一行的位置
if (i < this.columns) {
item.style.top = '0px'
item.style.left = (this.gap + this.imgWith) * i + 'px'
this.heightArr[i] = item.offsetHeight
} else {
// 找到最小高度的列数
minIndex = getMinIndex(this.heightArr)
// 把图片加上去
item.style.top = this.heightArr[minIndex] + this.gap + 'px'
// left值与第一行相同列数的盒子相同
item.style.left = this.items[minIndex].offsetLeft + 'px'
// 更新数组 之前的值加上现在的图片高度,再加上gap
this.heightArr[minIndex] += item.offsetHeight + this.gap
}
}
}
function getMinIndex(arr) {
return arr.indexOf(Math.min.apply(null, arr))
}
window.Waterfall = Waterfall
})()
// 最后一个图片加载完成再开始排版
var imgCount = document.getElementsByClassName('img')
imgCount[imgCount.length - 1].onload = function() {
new Waterfall({
el: 'content-box',
columns: 5,
gap: 5
})
}
- 当然,你也可以按顺序依次插入,只需要更改render()里面的代码,并删除储存高度的数组:
Waterfall.prototype.render = function() {
var item = null,
index = 0
for (var i = 0; i < this.items.length; i++) {
item = this.items[i]
// 设置每个盒子的宽度
item.style.width = this.imgWith + 'px'
// 先确定第一行的位置
if (i < this.columns) {
item.style.top = '0px'
item.style.left = (this.gap + this.imgWith) * i + 'px'
this.heightArr[i] = item.offsetHeight
} else {
// 当前正在第几列? i 只能在0-column中循环
index = index < this.columns ? index : -1
index++
// 把图片加上去
item.style.top = this.heightArr[index] + this.gap + 'px'
// left值与第一行相同列数的盒子相同
item.style.left = this.items[index].offsetLeft + 'px'
// 更新数组 之前的值加上现在的图片高度,再加上gap
this.heightArr[index] += item.offsetHeight + this.gap
}
}
}
虽然这会导致结尾图片不齐的问题:
且部分图片仍然会重叠。