一、什么是瀑布流
瀑布流是一种布局方式,就是一行中的块级元素同宽不同高,下一行的第一个元素插入到上一行中高度最小的元素下面。并且在鼠标滚动的时候继续加载图片。
像下面的图中,1234这四个区域都是同一个宽度的元素,并且占据了一行的宽度。那么第五块元素想要插进页面的时候,就选择此时高度最小的第四列。依次类推。
所以,我们可以发现,这里的问题主要有以下几个
-
首行如何布局
-
第一行结束了之后如何选择哪一列进行插入
-
鼠标滚动的时候这么触发
接下来我们一一解决上面提出来的问题。
首先,解决首行如何布局。
我们先用一个大的盒子装载所有的图片,并为其设置position为relative。
至于为什么要设置position为relative,那是因为待会我们要设置的box需要设置position为absolute,而这个absolute的相对定位是相对于它最接近的设置了position(值为relative)的元素而定位的。
可以在这里就设置宽度也可以待会在js中再设置宽度。取决于你。
<div id="main"></div>
#main{position:relative;}
然后每一个图片所在的区域我们用一个box来包裹,在里面添加图片和介绍文字。然后设置一下阴影,边框什么的。
<style>
.box{
padding: 15px 0 0 15px;
float: left;
}
.pic{
height: auto;
padding: 10px;
border: 1px #cccccc solid;
box-shadow: 0 0 5px #cccccc;
border-radius: 5px;
}
.pic img{
width: 300px;
height: auto;
}
</style>
<div class="box">
<div class="pic">
<img src="img/1.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/17.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/18.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/19.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/5.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/6.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/20.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/8.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/21.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/10.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/1.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/17.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/18.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/19.jpg"/>
<p>pic 1</p>
</div>
</div>
接下来来讲js部分。
首先要做的就是将除了第一行以外的元素设置偏移值,使他们偏移到合适的位置(高度最低的列)除此之外还要设置这个元素的position为absolute。因为只有absolute是不占用偏移值所在区间的空间位置。
所以我们需要获取当前高度最小的是哪一列。
获取到高度最小的是哪一列之后,将当前元素的top设置为这一列的高度,left为一个box的宽度乘上当前列的索引值。
这样,当前元素就去到了它该去的地方了。然后,将当前box的宽度添加到当前列的高度,那么此时,这一列就有可能不再是高度最低的列了。
我们首先获取到当前所有class为box的元素(自定义函数getEleByCls),然后,遍历这些元素,当元素不在第一行的时候,就开始设置top和left的值。
不说了,直接看代码。
function getEleByCls(parent,clsName) {//获得所有class为clsname的div并返回一个数组。
var eleArr = parent.getElementsByTagName("*");
var allcls = [];
for (i in eleArr){
if (eleArr[i].className == clsName){
allcls.push(eleArr[i]);
}
}
return allcls;
}
function waterfall(parent,box) {
var oparent = document.getElementById(parent);//
var allbox = getEleByCls(oparent,box);
//计算列数
var boxW = allbox[0].offsetWidth;//一个盒子的宽度
var cols = Math.floor(document.documentElement.offsetWidth/boxW) ;//一共有多少列
//设置main宽度
oparent.style.cssText = "width:"+cols*boxW+"px;margin:0 auto;";
console.log(cols);
var hArr = [];//存放每一列的高度
var hArrMin = 0;//当前高度最小的值
var index = 0;//当前高度最小的值的索引
for(i in allbox){
if (i<cols){
hArr.push(allbox[i].offsetHeight);//将第一行的box的高度放到数组中
}else {
hArrMin = Math.min.apply(null,hArr);//当前数组中最小的列
index = hArr.indexOf(hArrMin);
allbox[i].style.cssText = "position:absolute;top:"+hArrMin+"px;left:"+index*boxW+"px";//一定要设置position为absolute不然的话当设了top和left之后仍然会占用位置。
hArr[index] = hArr[index]+allbox[i].offsetHeight;//将当前box的高度添加到其插入到的列中对应的总高度。
}
}
}
window.onload = function (ev) {
waterfall("main","box");
window.onscroll = function (ev2) {//检测鼠标滚动的时候触发
if (checkScroll()){
var json = {
"data":[{"src":"img/24.jpg"},
{"src":"img/25.jpg"},
{"src":"img/26.jpg"},
{"src":"img/27.jpg"},
{"src":"img/28.jpg"},
{"src":"img/29.jpg"},
{"src":"img/19.jpg"},
{"src":"img/18.jpg"},
{"src":"img/17.jpg"},
{"src":"img/16.jpg"}
]
};
for (i in json.data){
var box = document.createElement("div");
box.className = "box";
var pic = document.createElement("div");
pic.className = "pic";
var img = document.createElement("img");
img.src = json.data[i].src;
pic.appendChild(img);
box.appendChild(pic);
var main = document.getElementById("main");
main.appendChild(box);
}
waterfall("main","box");
}
}
};
function checkScroll() {//判断是否可以滚动
var main = document.getElementById("main");
var allcls = getEleByCls(main,"box");
var arrLen = allcls.length;
var lastBoxHeight = allcls[arrLen-1].offsetTop;
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
var windowHeight = document.body.clientHeight || document.documentElement.clientHeight;
console.log(lastBoxHeight,scrollTop,windowHeight);
return (lastBoxHeight < scrollTop+windowHeight)?true:false;//如果为真,证明最后一张图片已经出现,此时需要继续加载。
}
二、使用css3的多列来实现瀑布流。
HTML代码跟上面一样,但是这里不要引进上面的js文件以及style文件
*{
margin: 0px;
padding: 0px;
}
#main{
/*设置为有多少列*/
column-count: auto;
/*列与列之间的间隔*/
column-gap: 15px;
/*一列的宽度*/
column-width: 300px;
-moz-column-count: auto;
-moz-column-width: 300px;
-moz-column-gap: 5px;
width: 1625px;
margin: 0 auto;
height: auto;
}
.box{
width: 300px;
padding: 15px 0 0 15px;
/*不允许元素内部断行从而产生新列*/
break-inside: avoid;
}
.pic{
height: auto;
padding: 10px;
border: 1px #cccccc solid;
box-shadow: 0 0 5px #cccccc;
border-radius: 5px;
}
.pic img{
width: 280px;
height: auto;
}
三、使用jQuery来实现瀑布流
(下面是我16年的时候写的呱呱呱)
简单的设置了几个div而已;下面的是全场的重点,也是整个js瀑布流设计的思想体现:
整个设计的思想就是先把第一行放好后,寻找到第一行高度最小的一张图片,将下一张图片放置在它的下面,然后将这两张照片的高度加起来继续寻找下一张高度最小的图片,依次类推的放置好所有的图片;而每一行放置的图片数量就是屏幕的大小除以图片的宽度;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
*{
margin: 0;
padding: 0;
}
.box{
position: relative;
float: left;
}
.pic{
box-shadow:0 0 5px darkgrey;
border-radius: 8px;
border: 1px solid #A9A9A9 ;
padding: 5px;
margin: 0 auto ;
}
.pic img {
width: 255px;
height: auto;
}
p{
text-align: center;
font-size: small;
color:darksalmon;
}
</style>
</head>
<body>
<div id="main">
<div class="box">
<div class="pic">
<img src="img/1.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/17.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/18.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/19.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/5.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/6.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/20.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/8.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/21.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/10.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/1.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/17.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/18.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/19.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/5.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/6.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/20.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/8.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/21.jpg"/>
<p>pic 1</p>
</div>
</div>
<div class="box">
<div class="pic">
<img src="img/10.jpg"/>
<p>pic 1</p>
</div>
</div>
</div>
<script src="js/jquery-3.1.0.min.js"></script>
<script>
$(document).ready( function(){
$( window).on("load" ,function(){
imgLocation();
var imgLoc={ "data":[{"src" :"10.jpg"},{ "src":"11.jpg" },{"src": "12.jpg"},{"src" :"13.jpeg"},
{ "src":"14.jpeg" },{"src": "15.jpg"},{"src" :"16.jpg"},{ "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"}]};
//模拟json数据格式
window.onscroll =function(){
if(scrollside()){
$.each(imgLoc.data, function(index ,value){
var box=$( "<div></div>").addClass("box" ).appendTo($("#main")); //创建一个box在main后面
var img=$( "<div></div>").addClass("pic" ).appendTo(box);
$("<img />").attr( "src","img/" +$(value).attr ("src")).appendTo(img);
});
imgLocation();
}
};
});
});
function scrollside(){ //判断是否可以滚动加载图片(判断滚动页面的高度是否超过了页面)
var box= $(".box"); //获取box
var lastBoxHeight=box.last().get( 0).offsetTop+ Math.floor(box.last().height() /2); //获得判断是否可以滚动的高度
var documentHeight= $(document).width(); //获得屏幕的高度
var scrlHeight= $(window).scrollTop(); //获得滚动条的高度
return (lastBoxHeight<documentHeight +scrlHeight)? true:false ;//当当前屏幕的高度少于滚动条和本来屏幕的高度的时候就可以进行加载
}
//此函数用来对图片进行布局
function imgLocation(){
var box= $(".box");
var boxWidth= box.eq(0).width(); //用eq来寻找第一个box
var num=Math.floor($( window).width()/ boxWidth);//window.width就是获得屏幕的宽度,num是一行能排放照片的数量
var boxArr= [];
box.each( function(index ,value){ //遍历所有的box,并添加偏移值
var boxHeight= box.eq(index).height();
if(index< num){
boxArr[index] =boxHeight;
} else{
var minHeight= Math.min.apply(null,boxArr);//寻找当前高度最低的box
var minHeightIndex= $.inArray(minHeight,boxArr);//找到它的偏移
$(value).css({
"position":"absolute" ,
"top":minHeight,
"left":box.eq(minHeightIndex).position ().left,
});
boxArr[minHeightIndex] +=box.eq(index).height();
}
});
}
</script>
</body>
</html>