前端实现瀑布流(上)
什么是瀑布流?
Pinterest
最早实现了瀑布流的网站,因此,瀑布流的英文名称是Pinterest-style layout
。
瀑布流特征
每行的列数是固定的
瀑布流中的元素等比例进行缩放
元素宽度固定
元素高度不固定
第一行顶部对齐
其他行通过遍历,找到上一行中,高度最小的列,放在它后面
向下滚动的时候,像瀑布往下流一样,因此得名。
使用 JavaScript 实现瀑布流的核心思想
不管什么效果,最终都要实现为 HTML/CSS 再进行渲染的。动手之前,要先考虑几个问题:
- 可以设置元素的宽和高
- 一行内可以有多个元素
- 可以设置元素的位置
使用 relative + absolute 进行布局正合适,这几个特性都满足。
代码解析
CSS:
.masonry {
width: 100%;
margin-top: 50px;
position:relative;
}
.item {
z-index: 10;
transition: 0.25s;
overflow: hidden;
position: absolute;
}
.item img{
width: 100%;
height:100%;
}
JS 代码:
(代码来自下方链接的博客,注释已经写的很完整)
var pageWidth = $('.masonry').width();
var columns = 4; // 4 列
var itemWidth = parseInt(pageWidth/columns); // 得到item的宽度
$(".article-item").width(itemWidth); // 设置到item的宽度
var arr = [];
$(".masonry .item").each(function(i){
var height = $(this).find("img").height();
var width = $(this).find("img").width();
var bi = itemWidth/width; // 获取缩小的比值
var boxheight = parseInt(height*bi); // 图片的高度*比值 = item的高度
if (i < columns) {
// 2- 确定第一行
$(this).css({
top:0,
left:(itemWidth) * i
});
arr.push(boxheight);
} else {
// 其他行
// 3- 找到数组中最小高度 和 它的索引
console.log(arr.length, arr);
var minHeight = arr[0];
var index = 0;
for (var j = 0; j < arr.length; j++) {
if (minHeight > arr[j]) {
minHeight = arr[j];
index = j;
}
}
// 4- 设置下一行的第一个盒子位置
// top值就是最小列的高度
$(this).css({
top:arr[index],
left:$(".masonry .article-item").eq(index).css("left")
});
// 5- 修改最小列的高度
// 最小列的高度 = 当前自己的高度 + 拼接过来的高度
arr[index] = arr[index] + boxheight;
}
});
其他
窗口大小发生变化时,重新计算窗口大小
function resetSize() {
$(".masonry .item").each(function (i) {
$(this).css({
top: 'auto',
left: 'auto',
width: 'auto',
height: 'auto',
});
})
}
window.onresize = function() {
resetSize();
waterFall();
};
这里增加了个 resetSize 方法,在窗口发生变化时,首先重置元素的大小,可以避免高度计算不正确的Bug
增加行间距
大部分的时候,是不希望元素密密麻麻挤在一起的,需要增加一个边距。我是通过 CSS 对元素进行操作,来设置的:
.article-item {
padding-right: 15px;
padding-bottom: 15px;
box-sizing: border-box;
}
最小高度计算
因为是 absolute 布局,所以默认的盒模型高度不适用,如果想给父元素设置高度,可以通过 js 进行计算:
var maxItemOffsetTop = 0
$(".masonry .item").each(function (it) {
var offsetTop = $(this).offset().top
if (offsetTop > maxItemOffsetTop) {
maxItemOffsetTop = offsetTop
}
});
var masonryOffsetTop = $(".masonry").offset().top
var masonryMinHeight = maxItemOffsetTop + $(".masonry .article-item").last().height() - masonryOffsetTop
$(".masonry").css('minHeight', masonryMinHeight)
这段代码是放在计算瀑布流的后面执行,以最后一行最高的元素为参考,进行的计算。
只要掌握了思想和计算方法,实现瀑布流还是很简单的。其他平台上的瀑布流实现的都差不多。下一篇讲一讲纯 CSS 来实现瀑布流。
###参考
blog comments powered by Disqus