浅析瀑布流布局及其原理
一、什么是瀑布流很多时候我们会看到一些Vlog网站或者展示图片的网站,它们的图片明明每一张的高度大小都不同,但是却能自动地适应,排成一行一行地展示,并且下拉到底的时候,加载的图片也会自动适应,这就是瀑布流,比如下图。...
·
一、什么是瀑布流
很多时候我们会看到一些Vlog网站或者展示图片的网站,它们的图片明明每一张的高度大小都不同,但是却能自动地适应,排成一行一行地展示,并且下拉到底的时候,加载的图片也会自动适应,这就是瀑布流,比如下图。
二、实现原理
要做到每一张图片都根据上面的高度自动适应排列,那么我们就不能单纯地靠html+css布局了,需要用到js来帮助计算位置(其实用CSS3也能布局)。那么计算什么呢?
首先,我们需要理清一个思路,就是这个布局是按一列列来看的,如下图:
我们要做的,其实就是在每一列下面插入新的图片,这样它就会紧挨着上面的图片对齐。至于上面和下面的图片间距,那么很自然地是利用了margin和padding属性,不熟悉盒子属性的可以移步去理解padding和margin,等于理解了盒子模型这篇文章看看。
三、事先准备
- 建议事前在网上随便下载15张以上的图片,不用理会长宽问题,这些都是可以用css设置的;
- 准备好jQuery
- 然后按照以下布局去把HTML结构和CSS样式写好:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="css/index.css">
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script src="js/index.js"></script>
<title>Document</title>
</head>
<body>
<div id="wrap" class="wrap">
<div class="item"> <img src="images/1.jpg" alt=""> </div>
<div class="item"> <img src="images/2.jpg" alt=""> </div>
<div class="item"> <img src="images/3.jpg" alt=""> </div>
<div class="item"> <img src="images/4.jpg" alt=""> </div>
<div class="item"> <img src="images/5.jpg" alt=""> </div>
<div class="item"> <img src="images/6.jpg" alt=""> </div>
<div class="item"> <img src="images/7.jpg" alt=""> </div>
<div class="item"> <img src="images/8.jpg" alt=""> </div>
<div class="item"> <img src="images/9.jpg" alt=""> </div>
<div class="item"> <img src="images/10.jpg" alt=""> </div>
<div class="item"> <img src="images/11.jpg" alt=""> </div>
<div class="item"> <img src="images/12.jpg" alt=""> </div>
<div class="item"> <img src="images/13.jpg" alt=""> </div>
<div class="item"> <img src="images/14.jpg" alt=""> </div>
<div class="item"> <img src="images/15.jpg" alt=""> </div>
<div class="item"> <img src="images/16.jpg" alt=""> </div>
<div class="item"> <img src="images/17.jpg" alt=""> </div>
<div class="item"> <img src="images/18.jpg" alt=""> </div>
</div>
</body>
</html>
css样式:
*{
margin: 0;
padding: 0;
border:none
}
body{
background: #ddd
}
.wrap{
width: auto;
height: auto;
position: relative;
margin:0 auto;
}
.item{
float: left;
width: 280px;
height: auto;
padding: 10px;
margin: 10px;
box-sizing: border-box;
}
.item img{
display: block;
width:100%;
border-radius: 10px;
cursor: pointer;
}
.item img:hover{
background-color: gray;
opacity: 0.5;
}
至此,那么你的第一排就已经布局好了,接下来我们就是要用js去计算一页能有多少列图片以及如何在每一列里面插入新图片。
四、瀑布流的核心
实现瀑布流的核心其实就两个:
- 找出图片高度最小的那一列,再那一列插入,然后继续找下一个高度最小的,一直循环直到插满图片为止;
- 计算出每一列距离浏览器整体的距离,也就是
position
里的left
或right
,有什么用呢?当你知道某一列的left
的时候,相当于就知道了在它下面插入图片时,图片如何定位到这一列了,只要图片的left
值和列是一样的,那么图片自然就插入到列里面了
实现代码如下:
var data=[
{"src":"1.jpg"},
{"src":"2.jpg"},
{"src":"3.jpg"},
{"src":"4.jpg"},
{"src":"5.jpg"},
{"src":"6.jpg"},
{"src":"7.jpg"},
{"src":"8.jpg"},
{"src":"9.jpg"},
{"src":"10.jpg"},
{"src":"11.jpg"},
{"src":"12.jpg"},
{"src":"13.jpg"},
{"src":"14.jpg"},
{"src":"15.jpg"},
{"src":"16.jpg"},
{"src":"17.jpg"},
{"src":"18.jpg"},
]
$(function(){
var wrap=$('#wrap');
var boxes=wrap.children("div");
waterfall(wrap,boxes);
$(this).scroll(function(event){
appendBox(wrap,boxes)
})
})
// 主要瀑布流布局函数
function waterfall(wrap,boxes){
// 第一步:先获取能容纳的列数:窗口宽度/每列宽度
// +20是外边距
var boxswidth=boxes.eq(0).width()+40;
var windowwidth=$(window).width();
var column=Math.floor(windowwidth/boxswidth);
// 顺便计算得出容器的宽度,让盒子居中
var wrapwidth=column*boxswidth;
wrap.width(wrapwidth)
// 第二步:定义一个数组存储每一列的高度
var arr=new Array;
// 遍历每一个盒子
for(var i=0;i<boxes.length;i++){
// 当i<column时,说明在第一行,把盒子的高度存入到数组里
if(i<column){
arr[i]=boxes.eq(i).height()+40
}
// 否则就是第二行,开始按最小高度插入图片到列中
else{
// 先获取最小高度列的索引
var minheight=Math.min.apply(null,arr)
var minindex=getMinIndex(minheight,arr)
// 这里的leftvalue,是指最小高度列距离窗口左边的距离,相当于间接定位了这一列接下来要插入图片时,position定位的left值是多少
var leftvalue=boxes.eq(minindex).position().left;
setStyle(boxes.eq(i),minheight,leftvalue,i)
// 到这里已经插入了一张图片在最低高度列,接下来要改变arr里的最低高度的值,让它继续下次遍历
arr[minindex]+=boxes.eq(i).height() + 20
}
}
}
//设置追加盒子的样式 减少刷新量
var getStartNumber=0;
var setStyle=function(box,top,left,index){
if(getStartNumber>=index){
return false;
};
box.css({
'position':'absolute',
'top':top,
'left':left,
'opacity':'0'
}) .stop().animate({/*第二行慢慢出来的动画*/
'opacity':'1'
},1000);
getStartNumber=index;
};
// 计算最小高度列的索引函数
function getMinIndex(minheight,arr){
var minindex=arr.indexOf(minheight)
return minindex
}
// 判断是否在底部的函数
function getBottom(wrap){
// 获取最后一列的高度和滚动的高度+窗口高度的和,如果长的一列的高度比窗口+滚动的高度要小,说明到底了需要追加
var documentHeight=$(window).height();
var scrollHeight=$(window).scrollTop();
var boxes = wrap.children('div')
var lastboxTop=boxes.eq(boxes.length-1).offset().top;
var lastboxHeight=boxes.eq(boxes.length-1).height()+20;
var totalHeight=lastboxHeight+lastboxTop
return documentHeight+scrollHeight>=totalHeight?true:false;
}
// 追加瀑布流效果
function appendBox(wrap,boxes){
// 先判断是否展示到了底部
if(getBottom(wrap)){
for (i in data){
var addstr="<div class='item'> <img src='images/"+data[i].src+"' alt=''> </div>"
wrap.append(addstr)
}
}else{
return false
}
waterfall(wrap,wrap.children('div'))
}
注意:这里面我还加入了瀑布流追加的效果,就是下拉到底会自动加载,不过图片是重复的,需要在js顶部先定义一组数据,用来替换生产<img>
里src,至于实现原理,不是本文重点,大家可以通过注释去尝试理解
更多推荐
已为社区贡献2条内容
所有评论(0)