javascript实现瀑布流布局实践思路教程
淘宝有部分页面中使用了瀑布流布局,淘宝的kissy框架加入了这种布局的插件,详细可以查看相关的API函数,在淘宝UED的博客中乔花写了有关瀑布流布局的文章。下面是用JQ框架实现瀑布流布局的实现思路。
1、设置一些全局变量,通过全局变量然后初始化页面,保存临时数据在变量中。初始化一些数据,计算宽度等值。
function water(opts) { this.container=opts.container;//容器 this.context=opts.context; this.elem=opts.elem;//元素 this.len=opts.len;//需要调用数据次数 this.url=opts.url;//ajax地址 this.colArr=[];//top数组 即列高 this.containerW=960;//容器宽度 this.colNum=4;//列数 this.columnW=210; //元素宽度 this.columnP=20; //元素padding this.columnM=13; //元素margin this.columnOw=0; //元素的outerWidth this.i=0;//ajax判断需要 this.b=false;//ajax判断需要 this.threshold=10;//临界点 }2、计算left ,top值,这个是最关键的,很多人不知道这个值是如何计算的。通过上面的代码,我们发现一个this.colArr这个数组,其实这个数组就是保存top值。首先我们初始化top值
if(_this.colArr.length==0) { //初始化,如果数组中未保存任何值,责初始化设置0 for(var i=0,len=_this.colNum;i<len;i++) { _this.colArr[i]=0; } }根据一开始设置的列数,循环变量,给colArr数组设置初始值。top值如何计算呢?我们只要对元素进行遍历,第一行的初始值则都为0,故top=0, 每一个元素赋值以后,则对这个元素进行计算 _flow=元素高度+margin,然后重写colArr数组里面的数据。这里又有一个疑问,重写第几个。 考虑到瀑布流这种布局的方式,首先考虑的是填充最小高度的那个,即重写colArr中最小的值。left值的判断比较简单,可以获取数组中最小值的 index(由于列数和数组长度相同),然后乘以元素的宽度即可。
于是有下面的代码:
Array.max= function(array) {//获取数组中最大值 return Math.max.apply(Math,array); } Array.min= function(array) {//获取数组中最小值 return Math.min.apply(Math,array); } water.prototype= { flow: function(elem) { var _this=this; elem.find(_this.elem).each( function(i){ /*遍历元素,将每个元素的高度+margin值(即为top值)保存在colArr数组中。一共四列,数组中每个值进行重新赋值,取数组中最小值,进行排列,将每个列一次先填满。*/ var _elem=$(this); var _count=$.inArray(Array.min(_this.colArr),_this.colArr);//获取最小值的index var _flow=_this.colArr[_count];//通过最小值的index,从数组中获取值 _elem.css({ "top":_flow, "left":_count*_this.columnOw });//赋值 left为 _count(即列数)*元素宽度 _this.sArr[_count]=_flow+_this.columnM; _this.colArr[_count]=_flow+_elem.outerHeight()+_this.columnM;//重新对数组赋值 }); var _max=Array.max(_this.colArr); _this.container.height(_max); } }有了上面的思路,接下来的填充和ajax效果就不多说,直接看代码比较好,对于scroll的控制,简单的讲下,其实和lazy-load相似,判断临界点和可视区域的距离,这里的临界点其实就是列的最小高度,即colArr里面最小值。
所有代码:
/* *autor:demon *time:2012.2.9 * web:http://www.cssdemon.me * 瀑布流布局 */ function water(opts) { this.container=opts.container;//容器 this.context=opts.context; this.elem=opts.elem;//元素 this.len=opts.len;//需要调用数据次数 this.url=opts.url;//ajax地址 this.colArr=[];//top数组 即列高 this.containerW=960;//容器宽度 this.colNum=4;//列数 this.columnW=210; //元素宽度 this.columnP=20; //元素padding this.columnM=13; //元素margin this.columnOw=0; //元素的outerWidth this.i=0;//ajax判断需要 this.b=false;//ajax判断需要 this.threshold=10;//临界点 } Array.max= function(array) {//获取数组中最大值 return Math.max.apply(Math,array); } Array.min= function(array) {//获取数组中最小值 return Math.min.apply(Math,array); } water.prototype= { init: function() { var _this=this; $("<div class='sCon'></div>").appendTo(_this.container); _this.columnOw=_this.columnW+_this.columnP+_this.columnM;//计算元素的宽度 if(_this.colArr.length==0) {//初始化,如果数组中未保存任何值,责初始化设置0 for(var i=0,len=_this.colNum;i<len;i++) { _this.colArr[i]=0; } } _this.flow(_this.context); _this.scoll(".sCon"); }, flow: function(elem) { var _this=this; elem.find(_this.elem).each( function(i) { /* 遍历元素,将每个元素的高度+margin值(即为top值) 保存在colArr数组中。一共四列,数组中每个值进行重新赋值,取数组中最小值,进行排列,将每个列一次先填满。 */ var _elem=$(this); var _count=$.inArray(Array.min(_this.colArr),_this.colArr);//获取最小值的index var _flow=_this.colArr[_count];//通过最小值的index,从数组中获取值 _elem.css({ "top":_flow, "left":_count*_this.columnOw });//赋值 left为 _count(即列数)*元素宽度 //_this.sArr[_count]=_flow+_this.columnM; _this.colArr[_count]=_flow+_elem.outerHeight()+_this.columnM;//重新对数组赋值 }); var _max=Array.max(_this.colArr); _this.container.height(_max); }, fill: function() { /* 计算填充, 获取数组最大的值, for循环按列循环,判断i是否等于数组中最大值的坐标,不等于的,则设置一个div height计算:最大值-数组中保存的top值-margin值 */ var _this=this; var max=Array.max(_this.colArr); var _count=$.inArray(max,_this.colArr); var _fillHtml=""; for(var i=0,len=_this.colNum;i<len;i++) { if(i!=_count) { _fillHtml+="<div class='goods-fill' style='top:"+_this.colArr[i] +"px;left:"+i*_this.columnOw+"px;height:"+(max-_this.colArr[i]-_this.columnM) +"px;"+"'>"+"</div>"; } } _this.context.append(_fillHtml); }, getAjax: function(elem) { var _this=this; _this.i++; $.getJSON(_this.url+_this.i, function(data) {//ajax, json格式 {"status":"","data":""} if(data) { _this.b=data.status; $(elem).append(data.data); _this.flow($(elem)); $(elem).find(_this.elem).appendTo(_this.context); if(data.status==true&&_this.i==_this.len) { $(window).unbind("scroll"); setTimeout( function() { return _this.fill() },100); } } }) }, scoll: function(elem) { var _this=this, _scroll, _threshold=_this.threshold; _height=parseInt($(window).height()); $(window).scroll( function() { if(_this.b==false&&_this.i<_this.len) { _srcoll=parseInt($(this).scrollTop()); _sTop=_height+_srcoll+_threshold; _top=Array.min(_this.colArr); if(_top<_sTop) {//alert(1) _this.getAjax(elem); } } }) } } $( function() { opts= { container:$(".goods-wall"), context:$(".goods-container"), elem:".goods", url:"data.php?k=", len:4 } goods=new water(opts) goods.init(); })文章原作者在代码中有注明!
<< 上一篇
下一篇 >>