简介
瀑布流布局是一种很常见的布局方式,他的主要视觉体验为图片元素等宽不等高,图片元素之间的水平排序参差不齐,而且随着滚动条的滚动,数据会进行异步的加载,这样的布局有两个好处,1-有视觉的冲击力,比较好看;2-图片元素能够保持原始比例,不会被拉伸。最终浏览器中看到的效果如下图:
HTML和CSS实现步骤
步骤1:确定html布局,代码(部分)如下
<div id="main"> <div class="box"> <div class="pic"> <img src="img/1.jpg"/> </div> </div> <div class="box"> <div class="pic"> <img src="img/2.jpg"/> </div> </div> </div>
其中class=box的div主要作用是控制定位,class=pic的div的主要作用是实现各种效果,如边框阴影
步骤2:用css实现上图的效果
*{margin: 0px; padding: 0px;} #main{ position: relative; } .box{ padding: 15px 0 0 15px; float: left; } .pic{ border: 1px solid #ccc; border-radius: 5px; box-shadow: 5px 5px 5px #CCCCCC; padding: 10px; } .pic img{ width: 165px; height: auto; }
注意:这里我们为什么不直接设置class=pic的margin值作为div之间的间隔,而是在外面又套了一层div呢?因为使用javascript中outerwidth属性能直接算出元素padding+margin+boder的值,而使用margin不能做到这一点。
javascript实现步骤
步骤1:取出所有div[class=box],放到变量var oBoxs中
步骤2:算出屏幕可视区域能容纳div[class=box]的个数,把个数放到var cols中
步骤3:遍历oBoxs,把前cols个div的高度放到变量oBoxsH中
步骤4:找出oBoxsH中的最小值及其索引,把下一个div的top值设置成为oBoxsH中的最小值,left的值设置成为oBoxsH中的最小值及的索引x当前div的宽度
步骤5:更新oBoxsH的最小值
步骤6:判断滚动的临界点,并加载数据
// 瀑布流主方法 function waterfall(parent,box){ var oParent=document.getElementById(parent); var oBoxs=getByClass(oParent,box); var cols = Math.floor(document.documentElement.offsetWidth/oBoxs[0].offsetWidth); var oBoxsH = []; for(var i=0;i<oBoxs.length;i++){ if(i<cols){ // 将图片的高度值添加到数组中 oBoxsH.push(oBoxs[i].offsetHeight); }else{ // 求最小值和最小值的索引 var minBoxH = Math.min.apply(null, oBoxsH); var idx = getMinhIndex(oBoxsH, minBoxH); //计算及定义图片出现的位置 oBoxs[i].style.position='absolute'; oBoxs[i].style.left = oBoxs[idx].offsetLeft + 'px'; oBoxs[i].style.top = minBoxH + 'px'; // 改变数组值 oBoxsH[idx] += oBoxs[i].offsetHeight; } } }
// 取出所有class为clsName的元素 function getByClass(parent,clsName){ var boxArr=new Array(), oElements=parent.getElementsByTagName('*'); for(var i=0;i<oElements.length;i++){ if(oElements[i].className==clsName){ boxArr.push(oElements[i]); } } return boxArr; } // 求值在数组中的索引,arr接收的是数组,val接收的是判断的值 function getMinhIndex(arr,val){ for(var i=0; i<arr.length; i++) { if(arr[i] == val) { return i; } } } // 获取滚动时异步取数据的边界 function checkScrollSide () { var oBoxs = getByClass(document.getElementById("main"), "box");// 获取所有box var oEltHeight = Math.floor(oBoxs[oBoxs.length-1].offsetTop + oBoxs[oBoxs.length-1].offsetHeight/2);// 当滚动的高度大小最后一个元素一半时,加载数据 var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;// 使用兼容代码 return (oEltHeight < scrollTop + document.documentElement.clientHeight ? true : false) }
绑定事件,加载数据
var imgData = [{"src":"30.jpg"},{"src":"31.jpg"},{"src":"32.jpg"},{"src":"33.jpg"},{"src":"34.jpg"}]; window.onload=function(){ if(checkScrollSide()) { loadData(); } waterfall('main','box'); window.onscroll = function() { if(checkScrollSide()) { loadData(); waterfall('main','box'); } } }